Add host model support for LoongArch, allowing libvirt to detect
the host CPU and expand a host-model CPU definition into a custom
model.

The following driver callbacks are implemented:
- getHost: read CPUCFG registers from the host
- update: expand host-model to a custom model
- compare: compare guest and host CPU features

The QEMU capabilities code is adjusted so that LoongArch no longer
falls back to the generic ARM/unknown path.

Signed-off-by: Xianglai Li <[email protected]>
---
Cc: Bibo Mao <[email protected]>

 src/cpu/cpu_loongarch.c      | 64 ++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_capabilities.c |  2 +-
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/cpu/cpu_loongarch.c b/src/cpu/cpu_loongarch.c
index 89ba1a0512..8ce9d53cb0 100644
--- a/src/cpu/cpu_loongarch.c
+++ b/src/cpu/cpu_loongarch.c
@@ -33,6 +33,7 @@ VIR_LOG_INIT("cpu.cpu_loongarch");
 
 #define PRID_SERIES_MASK        0xf000
 #define LOONGARCH_CPUCFG0       0x0
+#define LOONGARCH_CPUCFGMAX     0x14
 
 typedef struct _virCPULoongArchVendor virCPULoongArchVendor;
 struct _virCPULoongArchVendor {
@@ -614,11 +615,67 @@ virCPULoongArchDriverDecode(virCPUDef *cpu,
 }
 
 static int
-virCPULoongArchUpdate(virCPUDef *guest G_GNUC_UNUSED,
-                      const virCPUDef *host G_GNUC_UNUSED,
-                      bool relative G_GNUC_UNUSED,
+virCPULoongArchGetHost(virCPUDef *cpu,
+                 virDomainCapsCPUModels *models)
+{
+    g_autoptr(virCPUData) cpuData = NULL;
+    virCPULoongArchData *data;
+    uint32_t i, val;
+
+    if (!(cpuData = virCPUDataNew(archs[0])))
+        return -1;
+
+    data = &cpuData->data.loongarch;
+    data->features = g_ptr_array_new();
+    g_ptr_array_set_free_func(data->features,
+                              (GDestroyNotify) virCPULoongArchFeatureFree);
+
+    for (i = 0; i < (LOONGARCH_CPUCFGMAX +1); i++) {
+        g_autoptr(virCPULoongArchFeature) feature = NULL;
+        val = 0;
+
+#if defined(__loongarch64)
+        asm("cpucfg %0, %1"
+            : "=r" (val)
+            : "r" (i)
+            :
+            );
+#endif
+
+        if (!val)
+            continue;
+
+        feature = virCPULoongArchFeatureNew();
+        feature->index = i;
+        feature->value = val;
+        g_ptr_array_add(data->features, g_steal_pointer(&feature));
+    }
+
+    return virCPULoongArchDriverDecode(cpu, cpuData, models);
+}
+
+static int
+virCPULoongArchUpdate(virCPUDef *guest,
+                      const virCPUDef *host,
+                      bool relative,
                       virCPUFeaturePolicy removedPolicy G_GNUC_UNUSED)
 {
+    g_autoptr(virCPUDef) updated = virCPUDefCopyWithoutModel(guest);
+
+    if (!relative || guest->mode != VIR_CPU_MODE_HOST_MODEL)
+        return 0;
+
+    if (!host) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("unknown host CPU model"));
+        return -1;
+    }
+
+    updated->mode = VIR_CPU_MODE_CUSTOM;
+    virCPUDefCopyModel(updated, host, true);
+    virCPUDefStealModel(guest, updated, false);
+    guest->mode = VIR_CPU_MODE_CUSTOM;
+    guest->match = VIR_CPU_MATCH_EXACT;
     return 0;
 }
 
@@ -630,6 +687,7 @@ struct cpuArchDriver cpuDriverLoongArch = {
     .decode     = virCPULoongArchDriverDecode,
     .encode     = NULL,
     .dataFree   = virCPULoongArchDataFree,
+    .getHost    = virCPULoongArchGetHost,
     .baseline   = NULL,
     .update     = virCPULoongArchUpdate,
     .getModels  = NULL,
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index bc2b0412dc..43abb00826 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -4104,7 +4104,7 @@ 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)) {
+    } else if (ARCH_IS_ARM(qemuCaps->arch)) {
         ret = 2;
     }
 
-- 
2.39.1

Reply via email to