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 <lixianglai@loongson.cn> --- Cc: Bibo Mao <maobibo@loongson.cn> 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