diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 324c701e81adeb3f876dd7bc44beab41a862e7a4..38629b0bc786ebccb5a60b3058da4ec74e8ce46b 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -661,6 +661,7 @@ virCPUarmDecode(virCPUDef *cpu,
if (cpuData->features) {
cpu->nfeatures = g_strv_length(cpuData->features);
+ cpu->nfeatures_max = cpu->nfeatures;
cpu->features = g_new0(virCPUFeatureDef, cpu->nfeatures);
for (i = 0; i < cpu->nfeatures; i++) {
diff --git a/src/cpu_map/arm_Tengyun-S5000C.xml b/src/cpu_map/arm_Tengyun-S5000C.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f8fa593c19b3d1494bff0f55ef1a3e5519b8bd83
--- /dev/null
+++ b/src/cpu_map/arm_Tengyun-S5000C.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml
index 5d18a4aed697df2778dd793d80e30170fea7c03a..bca4a3d363312caa44f4b0e958defc16fd674ee9 100644
--- a/src/cpu_map/index.xml
+++ b/src/cpu_map/index.xml
@@ -119,5 +119,6 @@
+
diff --git a/src/cpu_map/meson.build b/src/cpu_map/meson.build
index ca4934d363d0bde8749bfa7d7f4eb3fb746fcb2f..409f3c0c5e12f1eccff5b61e1ee3121b20824a80 100644
--- a/src/cpu_map/meson.build
+++ b/src/cpu_map/meson.build
@@ -11,6 +11,7 @@ cpumap_data = [
'arm_Neoverse-N2.xml',
'arm_Neoverse-V1.xml',
'arm_Tengyun-S2500.xml',
+ 'arm_Tengyun-S5000C.xml',
'arm_ThunderX299xx.xml',
'arm_vendors.xml',
'index.xml',
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 95529970049696c2436b59f58aa65cb35282a308..c21f0e55dc6f834eb059400de99043c493dc5e5d 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -3718,6 +3718,62 @@ virQEMUCapsInitCPUModelX86(virQEMUCaps *qemuCaps,
return 0;
}
+/**
+ * Returns 0 when host CPU model provided by QEMU was filled in qemuCaps,
+ * 1 when the caller should fall back to using virCaps *->host.cpu,
+ * 2 when cpu model info is not supported for this configuration,
+ * -1 on error.
+ */
+static int
+virQEMUCapsInitCPUModelARM(virQEMUCaps *qemuCaps,
+ virDomainVirtType type,
+ qemuMonitorCPUModelInfo *modelInfo,
+ virCPUDef *cpu,
+ bool migratable)
+{
+ size_t i;
+ g_autoptr(virCPUDef) hostCPU = NULL;
+
+ if (!modelInfo) {
+ if (type == VIR_DOMAIN_VIRT_KVM) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("missing host CPU model info from QEMU "
+ "capabilities for binary %s"),
+ qemuCaps->binary);
+ return -1;
+ }
+ return 2;
+ }
+
+ if (!(hostCPU = virQEMUCapsProbeHostCPU(qemuCaps->arch, NULL)))
+ return -1;
+
+ cpu->model = g_strdup(hostCPU->model);
+ cpu->features = g_new0(virCPUFeatureDef, modelInfo->nprops);
+
+ cpu->nfeatures_max = modelInfo->nprops;
+ cpu->nfeatures = 0;
+
+ for (i = 0; i < modelInfo->nprops; i++) {
+ virCPUFeatureDef *feature = cpu->features + cpu->nfeatures;
+ qemuMonitorCPUProperty *prop = modelInfo->props + i;
+ const char *name = virQEMUCapsCPUFeatureFromQEMU(qemuCaps->arch, prop->name);
+
+ if (prop->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN)
+ continue;
+
+ feature->name = g_strdup(name);
+
+ if (!prop->value.boolean ||
+ (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO))
+ feature->policy = VIR_CPU_FEATURE_DISABLE;
+ else
+ feature->policy = VIR_CPU_FEATURE_REQUIRE;
+ cpu->nfeatures++;
+ }
+
+ return 0;
+}
/**
* Returns 0 when host CPU model provided by QEMU was filled in qemuCaps,
@@ -3743,8 +3799,11 @@ virQEMUCapsInitCPUModel(virQEMUCaps *qemuCaps,
} else if (ARCH_IS_X86(qemuCaps->arch)) {
ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, modelInfo,
cpu, migratable);
- } else if (ARCH_IS_ARM(qemuCaps->arch) || ARCH_IS_LOONGARCH(qemuCaps->arch)) {
- ret = 2;
+ } else if (ARCH_IS_ARM(qemuCaps->arch)) {
+ ret = virQEMUCapsInitCPUModelARM(qemuCaps, type, modelInfo,
+ cpu, migratable);
+ } else if (ARCH_IS_LOONGARCH(qemuCaps->arch)) {
+ ret = 2;
}
if (ret == 0)