diff --git a/Add-loongarch-cpu-model-and-vendor-info.patch b/Add-loongarch-cpu-model-and-vendor-info.patch new file mode 100644 index 0000000000000000000000000000000000000000..2524bf0a08887d4a92eaec25d959eb477ad211f6 --- /dev/null +++ b/Add-loongarch-cpu-model-and-vendor-info.patch @@ -0,0 +1,69 @@ +From 55c7dc34b8ff1a75bb011ca783b6cd3c7f1a5643 Mon Sep 17 00:00:00 2001 +From: zhaotianrui +Date: Wed, 11 Jan 2023 11:41:55 -0500 +Subject: [PATCH 2/4] Add loongarch cpu model and vendor info + +Define loongarch cpu model type and vendor id in +cpu_map/loongarch.xml + +Signed-off-by: zhaotianrui +--- + src/cpu_map/Makefile.inc.am | 2 ++ + src/cpu_map/index.xml | 5 +++++ + src/cpu_map/loongarch_3a5000.xml | 6 ++++++ + src/cpu_map/loongarch_vendors.xml | 3 +++ + 4 files changed, 16 insertions(+) + create mode 100644 src/cpu_map/loongarch_3a5000.xml + create mode 100644 src/cpu_map/loongarch_vendors.xml + +diff --git a/src/cpu_map/Makefile.inc.am b/src/cpu_map/Makefile.inc.am +index 8eb818706a..3c674dea40 100644 +--- a/src/cpu_map/Makefile.inc.am ++++ b/src/cpu_map/Makefile.inc.am +@@ -68,6 +68,8 @@ cpumap_DATA = \ + cpu_map/x86_Skylake-Server-noTSX-IBRS.xml \ + cpu_map/x86_Westmere.xml \ + cpu_map/x86_Westmere-IBRS.xml \ ++ cpu_map/loongarch_vendors.xml \ ++ cpu_map/loongarch_3a5000.xml \ + cpu_map/arm_vendors.xml \ + cpu_map/arm_cortex-a53.xml \ + cpu_map/arm_cortex-a57.xml \ +diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml +index 3ccc76b9ed..1c05dd814d 100644 +--- a/src/cpu_map/index.xml ++++ b/src/cpu_map/index.xml +@@ -101,4 +101,9 @@ + + + ++ ++ ++ ++ ++ + +diff --git a/src/cpu_map/loongarch_3a5000.xml b/src/cpu_map/loongarch_3a5000.xml +new file mode 100644 +index 0000000000..f6fe3386f7 +--- /dev/null ++++ b/src/cpu_map/loongarch_3a5000.xml +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ ++ +diff --git a/src/cpu_map/loongarch_vendors.xml b/src/cpu_map/loongarch_vendors.xml +new file mode 100644 +index 0000000000..c744654617 +--- /dev/null ++++ b/src/cpu_map/loongarch_vendors.xml +@@ -0,0 +1,3 @@ ++ ++ ++ +-- +2.27.0 + diff --git a/Add-loongarch-cpu-support.patch b/Add-loongarch-cpu-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..a8995c223aabf3f93b3dc97ea537bd4a9721a0e3 --- /dev/null +++ b/Add-loongarch-cpu-support.patch @@ -0,0 +1,994 @@ +From c0b26612cf12d5f0594a9dfa5bd97fcf7acfe9da Mon Sep 17 00:00:00 2001 +From: zhaotianrui +Date: Wed, 11 Jan 2023 10:53:08 -0500 +Subject: [PATCH 1/4] Add loongarch cpu support + +Add loongarch cpu support: Define new cpu type 'loongarch64' +and implement it's driver functions. + +Signed-off-by: zhaotianrui +--- + docs/schemas/basictypes.rng | 1 + + po/POTFILES.in | 1 + + src/cpu/Makefile.inc.am | 3 + + src/cpu/cpu.c | 2 + + src/cpu/cpu.h | 3 +- + src/cpu/cpu_loongarch.c | 739 +++++++++++++++++++++++++++++++++++ + src/cpu/cpu_loongarch.h | 28 ++ + src/cpu/cpu_loongarch_data.h | 40 ++ + src/qemu/qemu_capabilities.c | 1 + + src/qemu/qemu_domain.c | 4 + + src/util/virarch.c | 1 + + src/util/virarch.h | 3 + + 12 files changed, 825 insertions(+), 1 deletion(-) + create mode 100644 src/cpu/cpu_loongarch.c + create mode 100644 src/cpu/cpu_loongarch.h + create mode 100644 src/cpu/cpu_loongarch_data.h + +diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng +index 81465273c8..34d285db48 100644 +--- a/docs/schemas/basictypes.rng ++++ b/docs/schemas/basictypes.rng +@@ -444,6 +444,7 @@ + x86_64 + xtensa + xtensaeb ++ loongarch64 + + + +diff --git a/po/POTFILES.in b/po/POTFILES.in +index 197ff2f3d3..24dc8087d6 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -60,6 +60,7 @@ + @SRCDIR@/src/cpu/cpu_arm.c + @SRCDIR@/src/cpu/cpu_map.c + @SRCDIR@/src/cpu/cpu_ppc64.c ++@SRCDIR@/src/cpu/cpu_loongarch.c + @SRCDIR@/src/cpu/cpu_s390.c + @SRCDIR@/src/cpu/cpu_x86.c + @SRCDIR@/src/datatypes.c +diff --git a/src/cpu/Makefile.inc.am b/src/cpu/Makefile.inc.am +index 1ee1290c2d..e2219bbc1c 100644 +--- a/src/cpu/Makefile.inc.am ++++ b/src/cpu/Makefile.inc.am +@@ -15,6 +15,9 @@ CPU_SOURCES = \ + cpu/cpu_ppc64.h \ + cpu/cpu_ppc64.c \ + cpu/cpu_ppc64_data.h \ ++ cpu/cpu_loongarch.h \ ++ cpu/cpu_loongarch.c \ ++ cpu/cpu_loongarch_data.h \ + cpu/cpu_map.h \ + cpu/cpu_map.c \ + $(NULL) +diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c +index 89c06aceeb..df78a0d33f 100644 +--- a/src/cpu/cpu.c ++++ b/src/cpu/cpu.c +@@ -30,6 +30,7 @@ + #include "cpu_s390.h" + #include "cpu_arm.h" + #include "cpu_sw64.h" ++#include "cpu_loongarch.h" + #include "capabilities.h" + #include "virstring.h" + +@@ -44,6 +45,7 @@ static struct cpuArchDriver *drivers[] = { + &cpuDriverS390, + &cpuDriverArm, + &cpuDriverSW64, ++ &cpuDriverLoongArch, + }; + + +diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h +index ec22a183a1..307c85fb61 100644 +--- a/src/cpu/cpu.h ++++ b/src/cpu/cpu.h +@@ -28,7 +28,7 @@ + #include "cpu_x86_data.h" + #include "cpu_ppc64_data.h" + #include "cpu_arm_data.h" +- ++#include "cpu_loongarch_data.h" + + typedef struct _virCPUData virCPUData; + typedef virCPUData *virCPUDataPtr; +@@ -38,6 +38,7 @@ struct _virCPUData { + virCPUx86Data x86; + virCPUppc64Data ppc64; + virCPUarmData arm; ++ virCPULoongArchData loongarch; + /* generic driver needs no data */ + } data; + }; +diff --git a/src/cpu/cpu_loongarch.c b/src/cpu/cpu_loongarch.c +new file mode 100644 +index 0000000000..953316bf78 +--- /dev/null ++++ b/src/cpu/cpu_loongarch.c +@@ -0,0 +1,739 @@ ++/* ++ * cpu_loongarch.c: CPU driver for 64-bit LOONGARCH CPUs ++ * ++ * Copyright (C) 2023 Loongson Technology. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "virlog.h" ++#include "viralloc.h" ++#include "cpu.h" ++#include "virstring.h" ++#include "cpu_map.h" ++#include "virbuffer.h" ++ ++#define VIR_FROM_THIS VIR_FROM_CPU ++ ++VIR_LOG_INIT("cpu.cpu_loongarch"); ++ ++static const virArch archs[] = { VIR_ARCH_LOONGARCH64 }; ++ ++typedef struct { ++ char *name; ++} LoongArch_vendor; ++ ++typedef struct { ++ char *name; ++ const LoongArch_vendor *vendor; ++ virCPULoongArchData data; ++} LoongArch_model; ++ ++typedef struct { ++ size_t nvendors; ++ LoongArch_vendor **vendors; ++ size_t nmodels; ++ LoongArch_model **models; ++} LoongArch_map; ++ ++static void ++LoongArchDataClear(virCPULoongArchData *data) ++{ ++ if (!data) ++ return; ++ ++ VIR_FREE(data->prid); ++} ++ ++static int ++LoongArchDataCopy(virCPULoongArchData *dst, const virCPULoongArchData *src) ++{ ++ size_t i; ++ ++ if (VIR_ALLOC_N(dst->prid, src->len) < 0) ++ return -1; ++ ++ dst->len = src->len; ++ ++ for (i = 0; i < src->len; i++) { ++ dst->prid[i].value = src->prid[i].value; ++ dst->prid[i].mask = src->prid[i].mask; ++ } ++ ++ return 0; ++} ++ ++static void ++LoongArchVendorFree(LoongArch_vendor *vendor) ++{ ++ if (!vendor) ++ return; ++ ++ VIR_FREE(vendor->name); ++ VIR_FREE(vendor); ++} ++ ++static LoongArch_vendor * ++LoongArchVendorFind(const LoongArch_map *map, ++ const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < map->nvendors; i++) { ++ if (STREQ(map->vendors[i]->name, name)) ++ return map->vendors[i]; ++ } ++ ++ return NULL; ++} ++ ++static void ++LoongArchModelFree(LoongArch_model *model) ++{ ++ if (!model) ++ return; ++ ++ LoongArchDataClear(&model->data); ++ VIR_FREE(model->name); ++ VIR_FREE(model); ++} ++ ++static LoongArch_model * ++LoongArchModelCopy(const LoongArch_model *model) ++{ ++ LoongArch_model *copy; ++ ++ if (VIR_ALLOC(copy) < 0) ++ goto cleanup; ++ ++ copy->name = g_strdup(model->name); ++ ++ if (LoongArchDataCopy(©->data, &model->data) < 0) ++ goto cleanup; ++ ++ copy->vendor = model->vendor; ++ ++ return copy; ++ ++ cleanup: ++ LoongArchModelFree(copy); ++ return NULL; ++} ++ ++static LoongArch_model * ++LoongArchModelFind(const LoongArch_map *map, ++ const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < map->nmodels; i++) { ++ if (STREQ(map->models[i]->name, name)) ++ return map->models[i]; ++ } ++ ++ return NULL; ++} ++ ++static LoongArch_model * ++LoongArchModelFindPrid(const LoongArch_map *map, ++ uint32_t prid) ++{ ++ size_t i; ++ size_t j; ++ ++ for (i = 0; i < map->nmodels; i++) { ++ LoongArch_model *model = map->models[i]; ++ for (j = 0; j < model->data.len; j++) { ++ if ((prid & model->data.prid[j].mask) == model->data.prid[j].value) ++ return model; ++ } ++ } ++ ++ return NULL; ++} ++ ++static LoongArch_model * ++LoongArchModelFromCPU(const virCPUDef *cpu, ++ const LoongArch_map *map) ++{ ++ LoongArch_model *model; ++ ++ if (!cpu->model) { ++ virReportError(VIR_ERR_INVALID_ARG, "%s", ++ _("no CPU model specified")); ++ return NULL; ++ } ++ ++ if (!(model = LoongArchModelFind(map, cpu->model))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Unknown CPU model %s"), cpu->model); ++ return NULL; ++ } ++ ++ return LoongArchModelCopy(model); ++} ++ ++static void ++LoongArchMapFree(LoongArch_map *map) ++{ ++ size_t i; ++ ++ if (!map) ++ return; ++ ++ for (i = 0; i < map->nmodels; i++) ++ LoongArchModelFree(map->models[i]); ++ VIR_FREE(map->models); ++ ++ for (i = 0; i < map->nvendors; i++) ++ LoongArchVendorFree(map->vendors[i]); ++ VIR_FREE(map->vendors); ++ ++ VIR_FREE(map); ++} ++ ++static int ++LoongArchVendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED, ++ const char *name, ++ void *data) ++{ ++ LoongArch_map *map = data; ++ LoongArch_vendor *vendor; ++ int ret = -1; ++ ++ if (VIR_ALLOC(vendor) < 0) ++ return ret; ++ vendor->name = g_strdup(name); ++ ++ if (LoongArchVendorFind(map, vendor->name)) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("CPU vendor %s already defined"), vendor->name); ++ goto cleanup; ++ } ++ ++ if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) ++ goto cleanup; ++ ++ ret = 0; ++ ++ cleanup: ++ LoongArchVendorFree(vendor); ++ return ret; ++} ++ ++static int ++LoongArchModelParse(xmlXPathContextPtr ctxt, ++ const char *name, ++ void *data) ++{ ++ LoongArch_map *map = data; ++ LoongArch_model *model; ++ xmlNodePtr *nodes = NULL; ++ char *vendor = NULL; ++ unsigned long prid; ++ size_t i; ++ int n; ++ int ret = -1; ++ ++ if (VIR_ALLOC(model) < 0) ++ goto cleanup; ++ ++ model->name = g_strdup(name); ++ ++ if (LoongArchModelFind(map, model->name)) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("CPU model %s already defined"), model->name); ++ goto cleanup; ++ } ++ ++ if (virXPathBoolean("boolean(./vendor)", ctxt)) { ++ vendor = virXPathString("string(./vendor/@name)", ctxt); ++ if (!vendor) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Invalid vendor element in CPU model %s"), ++ model->name); ++ goto cleanup; ++ } ++ ++ if (!(model->vendor = LoongArchVendorFind(map, vendor))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Unknown vendor %s referenced by CPU model %s"), ++ vendor, model->name); ++ goto cleanup; ++ } ++ } ++ ++ if ((n = virXPathNodeSet("./prid", ctxt, &nodes)) <= 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Missing Prid information for CPU model %s"), ++ model->name); ++ goto cleanup; ++ } ++ ++ if (VIR_ALLOC_N(model->data.prid, n) < 0) ++ goto cleanup; ++ ++ model->data.len = n; ++ ++ for (i = 0; i < n; i++) { ++ ctxt->node = nodes[i]; ++ ++ if (virXPathULongHex("string(./@value)", ctxt, &prid) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Missing or invalid Prid value in CPU model %s"), ++ model->name); ++ goto cleanup; ++ } ++ model->data.prid[i].value = prid; ++ ++ if (virXPathULongHex("string(./@mask)", ctxt, &prid) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Missing or invalid PVR mask in CPU model %s"), ++ model->name); ++ goto cleanup; ++ } ++ model->data.prid[i].mask = prid; ++ } ++ ++ if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) ++ goto cleanup; ++ ++ ret = 0; ++ ++ cleanup: ++ LoongArchModelFree(model); ++ VIR_FREE(vendor); ++ VIR_FREE(nodes); ++ return ret; ++} ++ ++static LoongArch_map * ++LoongArchLoadMap(void) ++{ ++ LoongArch_map *map; ++ ++ if (VIR_ALLOC(map) < 0) ++ goto cleanup; ++ ++ if (cpuMapLoad("loongarch64", LoongArchVendorParse, NULL, LoongArchModelParse, map) < 0) ++ goto cleanup; ++ ++ return map; ++ ++ cleanup: ++ LoongArchMapFree(map); ++ return NULL; ++} ++ ++static virCPUDataPtr ++LoongArchMakeCPUData(virArch arch, ++ virCPULoongArchData *data) ++{ ++ virCPUDataPtr cpuData; ++ ++ if (VIR_ALLOC(cpuData) < 0) ++ return NULL; ++ ++ cpuData->arch = arch; ++ ++ if (LoongArchDataCopy(&cpuData->data.loongarch, data) < 0) ++ VIR_FREE(cpuData); ++ ++ return cpuData; ++} ++ ++static virCPUCompareResult ++LoongArchCompute(virCPUDefPtr host, ++ const virCPUDef *other, ++ virCPUDataPtr *guestData, ++ char **message) ++{ ++ LoongArch_map *map = NULL; ++ LoongArch_model *host_model = NULL; ++ LoongArch_model *guest_model = NULL; ++ virCPUDefPtr cpu = NULL; ++ virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; ++ virArch arch; ++ size_t i; ++ ++ /* Ensure existing configurations are handled correctly */ ++ if (!(cpu = virCPUDefCopy(other))) ++ goto cleanup; ++ ++ if (cpu->arch != VIR_ARCH_NONE) { ++ bool found = false; ++ ++ for (i = 0; i < G_N_ELEMENTS(archs); i++) { ++ if (archs[i] == cpu->arch) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ VIR_DEBUG("CPU arch %s does not match host arch", ++ virArchToString(cpu->arch)); ++ if (message) { ++ *message = g_strdup_printf(_("CPU arch %s does not match host arch"), ++ virArchToString(cpu->arch)); ++ } ++ ret = VIR_CPU_COMPARE_INCOMPATIBLE; ++ goto cleanup; ++ } ++ arch = cpu->arch; ++ } else { ++ arch = host->arch; ++ } ++ ++ if (cpu->vendor && ++ (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) { ++ VIR_DEBUG("host CPU vendor does not match required CPU vendor %s", ++ cpu->vendor); ++ if (message) { ++ *message = g_strdup_printf(_("host CPU vendor does not match required " ++ "CPU vendor %s"), cpu->vendor); ++ } ++ ret = VIR_CPU_COMPARE_INCOMPATIBLE; ++ goto cleanup; ++ } ++ ++ if (!(map = LoongArchLoadMap())) ++ goto cleanup; ++ ++ /* Host CPU information */ ++ if (!(host_model = LoongArchModelFromCPU(host, map))) ++ goto cleanup; ++ ++ if (cpu->type == VIR_CPU_TYPE_GUEST) { ++ /* Guest CPU information */ ++ switch (cpu->mode) { ++ case VIR_CPU_MODE_HOST_MODEL: ++ case VIR_CPU_MODE_HOST_PASSTHROUGH: ++ /* host-model and host-passthrough: ++ * the guest CPU is the same as the host */ ++ guest_model = LoongArchModelCopy(host_model); ++ break; ++ ++ case VIR_CPU_MODE_CUSTOM: ++ /* custom: ++ * look up guest CPU information */ ++ guest_model = LoongArchModelFromCPU(cpu, map); ++ break; ++ } ++ } else { ++ /* Other host CPU information */ ++ guest_model = LoongArchModelFromCPU(cpu, map); ++ } ++ ++ if (!guest_model) ++ goto cleanup; ++ ++ if (STRNEQ(guest_model->name, host_model->name)) { ++ VIR_DEBUG("host CPU model does not match required CPU model %s", ++ guest_model->name); ++ if (message) { ++ *message = g_strdup_printf(_("host CPU model does not match required " ++ "CPU model %s"),guest_model->name); ++ } ++ ret = VIR_CPU_COMPARE_INCOMPATIBLE; ++ goto cleanup; ++ } ++ ++ if (guestData) ++ if (!(*guestData = LoongArchMakeCPUData(arch, &guest_model->data))) ++ goto cleanup; ++ ++ ret = VIR_CPU_COMPARE_IDENTICAL; ++ ++ cleanup: ++ virCPUDefFree(cpu); ++ LoongArchMapFree(map); ++ LoongArchModelFree(host_model); ++ LoongArchModelFree(guest_model); ++ return ret; ++} ++ ++static virCPUCompareResult ++virCPULoongArchCompare(virCPUDefPtr host, ++ virCPUDefPtr cpu, ++ bool failIncompatible) ++{ ++ virCPUCompareResult ret; ++ char *message = NULL; ++ ++ if (!host || !host->model) { ++ if (failIncompatible) { ++ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", ++ _("unknown host CPU")); ++ } else { ++ VIR_WARN("unknown host CPU"); ++ ret = VIR_CPU_COMPARE_INCOMPATIBLE; ++ } ++ return -1; ++ } ++ ++ ret = LoongArchCompute(host, cpu, NULL, &message); ++ ++ if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { ++ ret = VIR_CPU_COMPARE_ERROR; ++ if (message) { ++ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message); ++ } else { ++ virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); ++ } ++ } ++ VIR_FREE(message); ++ ++ return ret; ++} ++ ++static int ++LoongArchDriverDecode(virCPUDefPtr cpu, ++ const virCPUData *data, ++ virDomainCapsCPUModelsPtr models) ++{ ++ int ret = -1; ++ LoongArch_map *map; ++ const LoongArch_model *model; ++ ++ if (!data || !(map = LoongArchLoadMap())) ++ return -1; ++ ++ if (!(model = LoongArchModelFindPrid(map, data->data.loongarch.prid[0].value))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("Cannot find CPU model with Prid 0x%08x"), ++ data->data.loongarch.prid[0].value); ++ goto cleanup; ++ } ++ ++ if (!virCPUModelIsAllowed(model->name, models)) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("CPU model %s is not supported by hypervisor"), ++ model->name); ++ goto cleanup; ++ } ++ ++ cpu->model = g_strdup(model->name); ++ if (model->vendor) { ++ cpu->vendor = g_strdup(model->vendor->name); ++ } ++ ret = 0; ++ ++ cleanup: ++ LoongArchMapFree(map); ++ ++ return ret; ++} ++ ++static void ++virCPULoongArchDataFree(virCPUDataPtr data) ++{ ++ if (!data) ++ return; ++ ++ LoongArchDataClear(&data->data.loongarch); ++ VIR_FREE(data); ++} ++ ++static int ++virCPULoongArchGetHostPRID(void) ++{ ++ return 0x14c010; ++} ++ ++static int ++virCPULoongArchGetHost(virCPUDefPtr cpu, ++ virDomainCapsCPUModelsPtr models) ++{ ++ virCPUDataPtr cpuData = NULL; ++ virCPULoongArchData *data; ++ int ret = -1; ++ ++ if (!(cpuData = virCPUDataNew(archs[0]))) ++ goto cleanup; ++ ++ data = &cpuData->data.loongarch; ++ if (VIR_ALLOC(data->prid) < 0) ++ goto cleanup; ++ ++ ++ data->len = 1; ++ ++ data->prid[0].value = virCPULoongArchGetHostPRID(); ++ data->prid[0].mask = 0xffff00ul; ++ ++ ret = LoongArchDriverDecode(cpu, cpuData, models); ++ ++ cleanup: ++ virCPULoongArchDataFree(cpuData); ++ return ret; ++} ++ ++ ++static int ++virCPULoongArchUpdate(virCPUDefPtr guest, ++ const virCPUDef *host ATTRIBUTE_UNUSED) ++{ ++ /* ++ * - host-passthrough doesn't even get here ++ * - host-model is used for host CPU running in a compatibility mode and ++ * it needs to remain unchanged ++ * - custom doesn't support any optional features, there's nothing to ++ * update ++ */ ++ ++ if (guest->mode == VIR_CPU_MODE_CUSTOM) ++ guest->match = VIR_CPU_MATCH_EXACT; ++ ++ return 0; ++} ++ ++static virCPUDefPtr ++LoongArchDriverBaseline(virCPUDefPtr *cpus, ++ unsigned int ncpus, ++ virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED, ++ const char **features ATTRIBUTE_UNUSED, ++ bool migratable ATTRIBUTE_UNUSED) ++{ ++ LoongArch_map *map; ++ const LoongArch_model *model; ++ const LoongArch_vendor *vendor = NULL; ++ virCPUDefPtr cpu = NULL; ++ size_t i; ++ ++ if (!(map = LoongArchLoadMap())) ++ goto error; ++ ++ if (!(model = LoongArchModelFind(map, cpus[0]->model))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Unknown CPU model %s"), cpus[0]->model); ++ goto error; ++ } ++ ++ for (i = 0; i < ncpus; i++) { ++ const LoongArch_vendor *vnd; ++ ++ if (STRNEQ(cpus[i]->model, model->name)) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("CPUs are incompatible")); ++ goto error; ++ } ++ ++ if (!cpus[i]->vendor) ++ continue; ++ ++ if (!(vnd = LoongArchVendorFind(map, cpus[i]->vendor))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("Unknown CPU vendor %s"), cpus[i]->vendor); ++ goto error; ++ } ++ ++ if (model->vendor) { ++ if (model->vendor != vnd) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("CPU vendor %s of model %s differs from " ++ "vendor %s"), ++ model->vendor->name, model->name, ++ vnd->name); ++ goto error; ++ } ++ } else if (vendor) { ++ if (vendor != vnd) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("CPU vendors do not match")); ++ goto error; ++ } ++ } else { ++ vendor = vnd; ++ } ++ } ++ ++ cpu = virCPUDefNew(); ++ cpu->model = g_strdup(model->name); ++ if (vendor) { ++ cpu->vendor = g_strdup(vendor->name); ++ } ++ cpu->type = VIR_CPU_TYPE_GUEST; ++ cpu->match = VIR_CPU_MATCH_EXACT; ++ cpu->fallback = VIR_CPU_FALLBACK_FORBID; ++ ++ cleanup: ++ LoongArchMapFree(map); ++ return cpu; ++ ++ error: ++ virCPUDefFree(cpu); ++ cpu = NULL; ++ goto cleanup; ++} ++ ++static int ++virCPULoongArchDriverGetModels(char ***models) ++{ ++ LoongArch_map *map; ++ size_t i; ++ int ret = -1; ++ ++ if (!(map = LoongArchLoadMap())) { ++ goto error; ++ } ++ ++ if (models) { ++ if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0) ++ goto error; ++ ++ for (i = 0; i < map->nmodels; i++) { ++ (*models)[i] = g_strdup(map->models[i]->name); ++ } ++ } ++ ++ ret = map->nmodels; ++ ++ cleanup: ++ LoongArchMapFree(map); ++ return ret; ++ ++ error: ++ if (models) { ++ virStringListFree(*models); ++ *models = NULL; ++ } ++ goto cleanup; ++} ++ ++struct cpuArchDriver cpuDriverLoongArch = { ++ .name = "LoongArch", ++ .arch = archs, ++ .narch = G_N_ELEMENTS(archs), ++ .compare = virCPULoongArchCompare, ++ .decode = LoongArchDriverDecode, ++ .encode = NULL, ++ .dataFree = virCPULoongArchDataFree, ++ .getHost = virCPULoongArchGetHost, ++ .baseline = LoongArchDriverBaseline, ++ .update = virCPULoongArchUpdate, ++ .getModels = virCPULoongArchDriverGetModels, ++}; +diff --git a/src/cpu/cpu_loongarch.h b/src/cpu/cpu_loongarch.h +new file mode 100644 +index 0000000000..304af628d4 +--- /dev/null ++++ b/src/cpu/cpu_loongarch.h +@@ -0,0 +1,28 @@ ++/* ++ * cpu_loongarch.h: CPU driver for 64-bit LOONGARCH CPUs ++ * ++ * Copyright (C) 2023 Loongson Technology. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ */ ++ ++#ifndef __VIR_CPU_LOONGARCH_H__ ++# define __VIR_CPU_LOONGARCH_H__ ++ ++# include "cpu.h" ++ ++extern struct cpuArchDriver cpuDriverLoongArch; ++ ++#endif /* __VIR_CPU_LOONGARCH_H__ */ +diff --git a/src/cpu/cpu_loongarch_data.h b/src/cpu/cpu_loongarch_data.h +new file mode 100644 +index 0000000000..c640a0c6b4 +--- /dev/null ++++ b/src/cpu/cpu_loongarch_data.h +@@ -0,0 +1,40 @@ ++/* ++ * cpu_loongarch_data.h: 64-bit LOONGARCH CPU specific data ++ * ++ * Copyright (C) 2023 Loongson Technology. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; If not, see ++ * . ++ */ ++ ++#ifndef __VIR_CPU_LOONGARCH_DATA_H__ ++# define __VIR_CPU_LOONGARCH_DATA_H__ ++ ++# include ++ ++typedef struct _virCPULoongArchPrid virCPULoongArchPrid; ++struct _virCPULoongArchPrid { ++ uint32_t value; ++ uint32_t mask; ++}; ++ ++# define VIR_CPU_LOONGARCH_DATA_INIT { 0 } ++ ++typedef struct _virCPULoongArchData virCPULoongArchData; ++struct _virCPULoongArchData { ++ size_t len; ++ virCPULoongArchPrid *prid; ++}; ++ ++#endif /* __VIR_CPU_MIPS64_DATA_H__ */ +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index 2e9f2025ba..0c3eb148b2 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -2692,6 +2692,7 @@ static const char *preferredMachines[] = + "sim", /* VIR_ARCH_XTENSAEB */ + + "core3", /* VIR_ARCH_SW_64 */ ++ "loongson7a", /* VIR_ARCH_LOONGARCH64 */ + }; + G_STATIC_ASSERT(G_N_ELEMENTS(preferredMachines) == VIR_ARCH_LAST); + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 70835e4efd..37dac3694b 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -4361,6 +4361,10 @@ qemuDomainDefAddDefaultDevices(virDomainDefPtr def, + addPCIeRoot = true; + break; + ++ case VIR_ARCH_LOONGARCH64: ++ addPCIeRoot = true; ++ break; ++ + case VIR_ARCH_ARMV7B: + case VIR_ARCH_CRIS: + case VIR_ARCH_ITANIUM: +diff --git a/src/util/virarch.c b/src/util/virarch.c +index 653136cc73..decdbdd7ac 100644 +--- a/src/util/virarch.c ++++ b/src/util/virarch.c +@@ -85,6 +85,7 @@ static const struct virArchData { + { "xtensaeb", 32, VIR_ARCH_BIG_ENDIAN }, + + { "sw_64", 64, VIR_ARCH_LITTLE_ENDIAN}, ++ { "loongarch64", 64, VIR_ARCH_LITTLE_ENDIAN }, + }; + + G_STATIC_ASSERT(G_N_ELEMENTS(virArchData) == VIR_ARCH_LAST); +diff --git a/src/util/virarch.h b/src/util/virarch.h +index 5eb146eb1b..a7834ae799 100644 +--- a/src/util/virarch.h ++++ b/src/util/virarch.h +@@ -70,6 +70,7 @@ typedef enum { + VIR_ARCH_XTENSAEB, /* XTensa 32 BE http://en.wikipedia.org/wiki/Xtensa#Processor_Cores */ + + VIR_ARCH_SW_64, /* SW64 64 LE XHB*/ ++ VIR_ARCH_LOONGARCH64, /* LoongArch 64 LE */ + + VIR_ARCH_LAST, + } virArch; +@@ -99,6 +100,8 @@ typedef enum { + + #define ARCH_IS_SW64(arch) ((arch) == VIR_ARCH_SW_64) + ++#define ARCH_IS_LOONGARCH(arch) ((arch) == VIR_ARCH_LOONGARCH64) ++ + typedef enum { + VIR_ARCH_LITTLE_ENDIAN, + VIR_ARCH_BIG_ENDIAN, +-- +2.27.0 + diff --git a/Config-some-capabilities-for-loongarch-virt-machine.patch b/Config-some-capabilities-for-loongarch-virt-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..447845b303d37e863eada983587e5a6e028afb23 --- /dev/null +++ b/Config-some-capabilities-for-loongarch-virt-machine.patch @@ -0,0 +1,263 @@ +From 4b7f6284eaa3e3b15360e25848fc68b37ee6c768 Mon Sep 17 00:00:00 2001 +From: zhaotianrui +Date: Wed, 11 Jan 2023 11:56:03 -0500 +Subject: [PATCH 3/4] Config some capabilities for loongarch virt machine + +Config some capabilities for loongarch virt machine such as +PCI multi bus and the path of loongarch uefi binary. + +Signed-off-by: zhaotianrui +--- + src/qemu/qemu.conf | 3 +- + src/qemu/qemu_capabilities.c | 4 ++ + src/qemu/qemu_conf.c | 3 +- + src/qemu/qemu_domain.c | 31 ++++++++++- + src/qemu/qemu_domain.h | 1 + + src/qemu/qemu_domain_address.c | 86 ++++++++++++++++++++++++++++++ + src/qemu/test_libvirtd_qemu.aug.in | 1 + + 7 files changed, 125 insertions(+), 4 deletions(-) + +diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf +index abdbf07fec..3856087248 100644 +--- a/src/qemu/qemu.conf ++++ b/src/qemu/qemu.conf +@@ -771,7 +771,8 @@ + # "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd", + # "/usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.fd", + # "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd", +-# "/usr/share/AAVMF/AAVMF32_CODE.fd:/usr/share/AAVMF/AAVMF32_VARS.fd" ++# "/usr/share/AAVMF/AAVMF32_CODE.fd:/usr/share/AAVMF/AAVMF32_VARS.fd", ++# "/usr/share/qemu/loongarch_bios.bin:/usr/share/qemu/loongarch_vars.bin" + #] + + # The backend to use for handling stdout/stderr output from +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index 0c3eb148b2..21b477cd4d 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -1983,6 +1983,10 @@ bool virQEMUCapsHasPCIMultiBus(virQEMUCapsPtr qemuCaps, + * since forever */ + if (ARCH_IS_SW64(def->os.arch)) + return true; ++ /* loongarch64 support PCI-multibus on all machine types ++ * since forever */ ++ if (ARCH_IS_LOONGARCH(def->os.arch)) ++ return true; + + if (def->os.arch == VIR_ARCH_PPC || + ARCH_IS_PPC64(def->os.arch)) { +diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c +index 28319a1baf..3253875d6e 100644 +--- a/src/qemu/qemu_conf.c ++++ b/src/qemu/qemu_conf.c +@@ -98,7 +98,8 @@ qemuDriverUnlock(virQEMUDriverPtr driver) + "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd:" \ + "/usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.fd:" \ + "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd:" \ +- "/usr/share/AAVMF/AAVMF32_CODE.fd:/usr/share/AAVMF/AAVMF32_VARS.fd" ++ "/usr/share/AAVMF/AAVMF32_CODE.fd:/usr/share/AAVMF/AAVMF32_VARS.fd:" \ ++ "/usr/share/qemu/loongarch_bios.bin:/usr/share/qemu/loongarch_vars.bin" + #endif + + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 37dac3694b..152c8615d5 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -5186,7 +5186,7 @@ qemuDomainDefValidateFeatures(const virDomainDef *def, + switch ((virDomainFeature) i) { + case VIR_DOMAIN_FEATURE_IOAPIC: + if (def->features[i] != VIR_DOMAIN_IOAPIC_NONE) { +- if (!ARCH_IS_X86(def->os.arch)) { ++ if (!ARCH_IS_X86(def->os.arch) && !ARCH_IS_LOONGARCH(def->os.arch)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("The '%s' feature is not supported for " + "architecture '%s' or machine type '%s'"), +@@ -9089,6 +9089,11 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, + cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI; + else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI)) + cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI; ++ } else if (ARCH_IS_LOONGARCH(def->os.arch)) { ++ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI)) ++ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI; ++ else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI)) ++ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI; + } + } + /* forbid usb model 'qusb1' and 'qusb2' in this kind of hyperviosr */ +@@ -12985,6 +12990,20 @@ qemuDomainMachineIsPSeries(const char *machine, + return false; + } + ++static bool ++qemuDomainMachineIsLoongson(const char *machine, ++ const virArch arch) ++{ ++ if (!ARCH_IS_LOONGARCH(arch)) ++ return false; ++ ++ if (STREQ(machine, "loongson7a") || ++ STRPREFIX(machine, "loongson7a-")) { ++ return true; ++ } ++ ++ return false; ++} + + /* You should normally avoid this function and use + * qemuDomainHasBuiltinIDE() instead. */ +@@ -12996,7 +13015,8 @@ qemuDomainMachineHasBuiltinIDE(const char *machine, + STREQ(machine, "malta") || + STREQ(machine, "sun4u") || + STREQ(machine, "core3") || +- STREQ(machine, "g3beige"); ++ STREQ(machine, "g3beige") || ++ STREQ(machine, "loongson7a"); + } + + +@@ -13066,6 +13086,13 @@ qemuDomainIsPSeries(const virDomainDef *def) + } + + ++bool ++qemuDomainIsLoongson(const virDomainDef *def) ++{ ++ return qemuDomainMachineIsLoongson(def->os.machine, def->os.arch); ++} ++ ++ + bool + qemuDomainHasPCIRoot(const virDomainDef *def) + { +diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h +index 7603724ccd..368fc4030f 100644 +--- a/src/qemu/qemu_domain.h ++++ b/src/qemu/qemu_domain.h +@@ -999,6 +999,7 @@ bool qemuDomainIsS390CCW(const virDomainDef *def); + bool qemuDomainIsARMVirt(const virDomainDef *def); + bool qemuDomainIsRISCVVirt(const virDomainDef *def); + bool qemuDomainIsPSeries(const virDomainDef *def); ++bool qemuDomainIsLoongson(const virDomainDef *def); + bool qemuDomainHasPCIRoot(const virDomainDef *def); + bool qemuDomainHasPCIeRoot(const virDomainDef *def); + bool qemuDomainHasBuiltinIDE(const virDomainDef *def); +diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c +index ab6bce19f4..7f48773832 100644 +--- a/src/qemu/qemu_domain_address.c ++++ b/src/qemu/qemu_domain_address.c +@@ -2078,6 +2078,87 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, + return 0; + } + ++static int ++qemuDomainValidateDevicePCISlotsLoongson(virDomainDefPtr def, ++ virQEMUCapsPtr qemuCaps, ++ virDomainPCIAddressSetPtr addrs) ++{ ++ int ret = -1; ++ virPCIDeviceAddress tmp_addr; ++ bool qemuDeviceVideoUsable = virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); ++ g_autofree char *addrStr = NULL; ++ virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; ++ ++ if (addrs->nbuses) { ++ memset(&tmp_addr, 0, sizeof(tmp_addr)); ++ tmp_addr.slot = 1; ++ /* pci-ohci at 00:01.0 */ ++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) ++ return -1; ++ } ++ ++ if (def->nvideos > 0 && ++ def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_NONE && ++ def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_RAMFB) { ++ /* reserve slot 2 for vga device */ ++ virDomainVideoDefPtr primaryVideo = def->videos[0]; ++ ++ if (virDeviceInfoPCIAddressIsWanted(&primaryVideo->info)) { ++ memset(&tmp_addr, 0, sizeof(tmp_addr)); ++ tmp_addr.slot = 2; ++ ++ if (!(addrStr = virPCIDeviceAddressAsString(&tmp_addr))) ++ return -1; ++ if (!virDomainPCIAddressValidate(addrs, &tmp_addr, ++ addrStr, flags, true)) ++ return ret; ++ ++ if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { ++ if (qemuDeviceVideoUsable) { ++ if (qemuDomainPCIAddressReserveNextAddr(addrs, ++ &primaryVideo->info) < 0) { ++ return ret; ++ } ++ } else { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("PCI address 0:0:2.0 is in use, " ++ "QEMU needs it for primary video")); ++ return ret; ++ } ++ } else { ++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) ++ return ret; ++ primaryVideo->info.addr.pci = tmp_addr; ++ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; ++ } ++ } else if (!qemuDeviceVideoUsable) { ++ if (primaryVideo->info.addr.pci.domain != 0 || ++ primaryVideo->info.addr.pci.bus != 0 || ++ primaryVideo->info.addr.pci.slot != 2 || ++ primaryVideo->info.addr.pci.function != 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Primary video card must have PCI address 0:0:2.0")); ++ return ret; ++ } ++ /* If TYPE == PCI, then qemuDomainCollectPCIAddress() function ++ * has already reserved the address, so we must skip */ ++ } ++ } else if (addrs->nbuses && !qemuDeviceVideoUsable) { ++ memset(&tmp_addr, 0, sizeof(tmp_addr)); ++ tmp_addr.slot = 2; ++ ++ if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { ++ VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video" ++ " device will not be possible without manual" ++ " intervention"); ++ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) { ++ return ret; ++ } ++ } ++ ++ ret = 0; ++ return ret; ++} + + static int + qemuDomainValidateDevicePCISlotsChipsets(virDomainDefPtr def, +@@ -2094,6 +2175,11 @@ qemuDomainValidateDevicePCISlotsChipsets(virDomainDefPtr def, + return -1; + } + ++ if (qemuDomainIsLoongson(def) && ++ qemuDomainValidateDevicePCISlotsLoongson(def, qemuCaps, addrs) < 0) { ++ return -1; ++ } ++ + return 0; + } + +diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in +index 19da591aae..caa06a45cb 100644 +--- a/src/qemu/test_libvirtd_qemu.aug.in ++++ b/src/qemu/test_libvirtd_qemu.aug.in +@@ -95,6 +95,7 @@ module Test_libvirtd_qemu = + { "2" = "/usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.fd" } + { "3" = "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd" } + { "4" = "/usr/share/AAVMF/AAVMF32_CODE.fd:/usr/share/AAVMF/AAVMF32_VARS.fd" } ++ { "5" = "/usr/share/qemu/loongarch_bios.bin:/usr/share/qemu/loongarch_vars.bin" } + } + { "stdio_handler" = "logd" } + { "gluster_debug_level" = "9" } +-- +2.27.0 + diff --git a/Implement-the-method-of-getting-host-info-for-loonga.patch b/Implement-the-method-of-getting-host-info-for-loonga.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf0198f5d8eb8e5c26d168bb9fc2977a644c3230 --- /dev/null +++ b/Implement-the-method-of-getting-host-info-for-loonga.patch @@ -0,0 +1,65 @@ +From 4123437e633f05af0ae8091d5db440597394ba36 Mon Sep 17 00:00:00 2001 +From: zhaotianrui +Date: Wed, 11 Jan 2023 14:09:41 -0500 +Subject: [PATCH 4/4] Implement the method of getting host info for loongarch + +Implement method for loongarch to get host info, such as +cpu frequency, system info, etc. + +Signed-off-by: zhaotianrui +--- + src/util/virarch.c | 2 ++ + src/util/virhostcpu.c | 2 +- + src/util/virsysinfo.c | 3 ++- + 3 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/util/virarch.c b/src/util/virarch.c +index decdbdd7ac..0520a1c80b 100644 +--- a/src/util/virarch.c ++++ b/src/util/virarch.c +@@ -227,6 +227,8 @@ virArch virArchFromHost(void) + arch = VIR_ARCH_X86_64; + } else if (STREQ(ut.machine, "sw_64")) { + arch = VIR_ARCH_SW_64; ++ } else if (STREQ(ut.machine, "loongarch64")) { ++ arch = VIR_ARCH_LOONGARCH64; + } else { + /* Otherwise assume the canonical name */ + if ((arch = virArchFromString(ut.machine)) == VIR_ARCH_NONE) { +diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c +index 5ec98d6016..ce3da7e6ec 100644 +--- a/src/util/virhostcpu.c ++++ b/src/util/virhostcpu.c +@@ -577,7 +577,7 @@ virHostCPUParseFrequency(FILE *cpuinfo, + char line[1024]; + + /* No sensible way to retrieve CPU frequency */ +- if (ARCH_IS_ARM(arch)) ++ if (ARCH_IS_ARM(arch) || ARCH_IS_LOONGARCH(arch)) + return 0; + + if (ARCH_IS_X86(arch)) +diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c +index 8a53702224..6d4778fed7 100644 +--- a/src/util/virsysinfo.c ++++ b/src/util/virsysinfo.c +@@ -1190,7 +1190,7 @@ virSysinfoRead(void) + { + #if defined(__powerpc__) + return virSysinfoReadPPC(); +-#elif defined(__arm__) || defined(__aarch64__) ++#elif defined(__arm__) || defined(__aarch64__) || defined(__loongarch__) + return virSysinfoReadARM(); + #elif defined(__s390__) || defined(__s390x__) + return virSysinfoReadS390(); +@@ -1198,6 +1198,7 @@ virSysinfoRead(void) + (defined(__x86_64__) || \ + defined(__i386__) || \ + defined(__amd64__) || \ ++ defined(__loongarch__) || \ + defined(__sw_64__)) + return virSysinfoReadDMI(); + #else /* WIN32 || not supported arch */ +-- +2.27.0 + diff --git a/libvirt.spec b/libvirt.spec index 8c4f4f873abe5a9ea251f47283da3780d3526162..4d5c9a8197faadaa45c7d354ca9e4f82564da77e 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -13,7 +13,7 @@ %define with_qemu_tcg %{with_qemu} -%define qemu_kvm_arches %{ix86} x86_64 aarch64 +%define qemu_kvm_arches %{ix86} x86_64 aarch64 loongarch64 %ifarch %{qemu_kvm_arches} %define with_qemu_kvm %{with_qemu} @@ -44,7 +44,7 @@ %endif %define with_storage_zfs 0%{!?_without_storage_zfs:1} -%ifarch aarch64 x86_64 +%ifarch aarch64 x86_64 loongarch64 %define with_storage_zfs 0 %endif @@ -101,7 +101,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 6.2.0 -Release: 51 +Release: 52 License: LGPLv2+ URL: https://libvirt.org/ @@ -468,6 +468,10 @@ Patch0355: virsh-Check-whether-enough-arguments-was-passed-to-i.patch Patch0356: virNetDevSaveNetConfig-Pass-mode-to-virFileWriteStr.patch Patch0357: live_migrate-virsh-migrate-command-supports-the-zstd.patch Patch0358: glibcompat-Provide-implementation-for-G_GNUC_NO_INLI.patch +Patch0359: Add-loongarch-cpu-support.patch +Patch0360: Add-loongarch-cpu-model-and-vendor-info.patch +Patch0361: Config-some-capabilities-for-loongarch-virt-machine.patch +Patch0362: Implement-the-method-of-getting-host-info-for-loonga.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -1358,6 +1362,8 @@ LOADERS="$LOADERS:/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd:/usr/share/edk2/ovmf-ia LOADERS="$LOADERS:/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw:/usr/share/edk2/aarch64/vars-template-pflash.raw" # Fedora edk2-arm LOADERS="$LOADERS:/usr/share/edk2/arm/QEMU_EFI-pflash.raw:/usr/share/edk2/arm/vars-template-pflash.raw" +# LoongArch +LOADERS="$LOADERS:/usr/share/qemu-kvm/loongarch_bios.bin:/usr/share/qemu-kvm/loongarch_bios.bin" %define arg_loader_nvram --with-loader-nvram="$LOADERS" # place macros above and build commands below this comment @@ -2080,7 +2086,7 @@ exit 0 %{_bindir}/virt-pki-validate %{_bindir}/virt-host-validate -%ifnarch aarch64 x86_64 +%ifnarch aarch64 x86_64 loongarch64 %{_datadir}/systemtap/tapset/libvirt_probes*.stp %{_datadir}/systemtap/tapset/libvirt_functions.stp %if %{with_qemu} @@ -2202,6 +2208,9 @@ exit 0 %changelog +* Tue Mar 28 2023 zhaotianrui - 6.2.0-52 +- libvirt: add loongarch support + * Tue Feb 14 2023 mayunlong - 6.2.0-51 - live_migrate: virsh migrate command supports the zstd compression algorithm - glibcompat: Provide implementation for G_GNUC_NO_INLINE