From 83d21394ad99e58e65f3eeb25ab6a9aec999732e Mon Sep 17 00:00:00 2001 From: Renbo Date: Thu, 6 Apr 2023 16:58:00 +0800 Subject: [PATCH 1/2] update to libvirt-8.0.0-10.4.module+el8.7.0+18295+4ee500a4 Signed-off-by: Renbo --- libvirt-Add-loongarch-support.patch | 1233 ----------------- ...ibvirt-guests-when-building-libvirtd.patch | 75 + ...ET_TYPE_ETHERNET-not-share-host-view.patch | 46 + ...jectGetStringArray-for-optional-data.patch | 58 + ...ssReconnect-Don-t-build-memory-paths.patch | 57 + ...case-in-qemuDomainGetPreservedMounts.patch | 80 ++ ...troduce-qemuDomainNamespaceSetupPath.patch | 68 + ...Ls-when-creating-a-path-in-namespace.patch | 45 + ...-require-a-hugetlbfs-mount-for-memfd.patch | 50 + ...pagate-hugetlbfs-mounts-on-reconnect.patch | 65 + ...ls-Fix-install_mode-for-some-scripts.patch | 65 + ...rom-virJSONValueObjectGetStringArray.patch | 124 ++ ...cpi-Add-PCIe-5.0-and-6.0-link-speeds.patch | 65 + libvirt.spec | 51 +- 14 files changed, 837 insertions(+), 1245 deletions(-) delete mode 100644 libvirt-Add-loongarch-support.patch create mode 100644 libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch create mode 100644 libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch create mode 100644 libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch create mode 100644 libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch create mode 100644 libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch create mode 100644 libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch create mode 100644 libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch create mode 100644 libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch create mode 100644 libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch create mode 100644 libvirt-tools-Fix-install_mode-for-some-scripts.patch create mode 100644 libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch create mode 100644 libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch diff --git a/libvirt-Add-loongarch-support.patch b/libvirt-Add-loongarch-support.patch deleted file mode 100644 index 94fd22a..0000000 --- a/libvirt-Add-loongarch-support.patch +++ /dev/null @@ -1,1233 +0,0 @@ -From da7befb4ce165d692f34156f740f4ea3ce2b7fec Mon Sep 17 00:00:00 2001 -From: zhaotianrui -Date: Sat, 3 Sep 2022 14:23:43 -0400 -Subject: [PATCH] Add loongarch support - -Signed-off-by: zhaotianrui -Change-Id: I8d245bc2fb914b08af4ade8e334d59ba3a5c2f01 ---- - po/POTFILES.in | 1 + - src/cpu/cpu.c | 3 +- - src/cpu/cpu.h | 3 +- - src/cpu/cpu_loongarch.c | 727 ++++++++++++++++++++++++++++++ - src/cpu/cpu_loongarch.h | 28 ++ - src/cpu/cpu_loongarch_data.h | 40 ++ - src/cpu/meson.build | 1 + - src/cpu_map/index.xml | 5 + - src/cpu_map/loongarch_vendors.xml | 3 + - src/cpu_map/ls_3a5000.xml | 6 + - src/cpu_map/meson.build | 2 + - src/qemu/qemu_capabilities.c | 5 + - src/qemu/qemu_conf.c | 4 +- - src/qemu/qemu_domain.c | 20 +- - src/qemu/qemu_domain.h | 1 + - src/qemu/qemu_domain_address.c | 58 +++ - src/qemu/qemu_validate.c | 3 +- - src/util/virarch.c | 3 + - src/util/virarch.h | 3 + - src/util/virhostcpu.c | 2 +- - src/util/virsysinfo.c | 2 +- - 21 files changed, 913 insertions(+), 7 deletions(-) - 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 - create mode 100644 src/cpu_map/loongarch_vendors.xml - create mode 100644 src/cpu_map/ls_3a5000.xml - -diff --git a/po/POTFILES.in b/po/POTFILES.in -index bf0a3b3529..1153e78265 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -68,6 +68,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/cpu.c b/src/cpu/cpu.c -index 285c7eee44..49527c3688 100644 ---- a/src/cpu/cpu.c -+++ b/src/cpu/cpu.c -@@ -31,7 +31,7 @@ - #include "cpu_arm.h" - #include "capabilities.h" - #include "virstring.h" -- -+#include "cpu_loongarch.h" - - #define VIR_FROM_THIS VIR_FROM_CPU - -@@ -42,6 +42,7 @@ static struct cpuArchDriver *drivers[] = { - &cpuDriverPPC64, - &cpuDriverS390, - &cpuDriverArm, -+ &cpuDriverLoongArch, - }; - - -diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h -index 071b33fe76..ce7aee4757 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; - struct _virCPUData { -@@ -37,6 +37,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..f7b4b85a44 ---- /dev/null -+++ b/src/cpu/cpu_loongarch.c -@@ -0,0 +1,727 @@ -+/* -+ * cpu_loongarch.c: CPU driver for 64-bit LOONGARCH CPUs -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * Copyright (C) IBM Corporation, 2010 -+ * -+ * 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" -+#include "cpu_loongarch.h" -+#include "cpu_loongarch_data.h" -+ -+#define VIR_FROM_THIS VIR_FROM_CPU -+ -+VIR_LOG_INIT("cpu.cpu_loongarch"); -+ -+static const virArch archs[] = { VIR_ARCH_LOONGARCH64 }; -+ -+typedef struct _LoongArch_vendor LoongArch_vendor; -+struct _LoongArch_vendor { -+ char *name; -+}; -+ -+typedef struct _LoongArch_model LoongArch_model; -+struct _LoongArch_model { -+ char *name; -+ LoongArch_vendor *vendor; -+ virCPULoongArchData data; -+}; -+ -+typedef struct _LoongArch_map LoongArch_map; -+struct _LoongArch_map { -+ size_t nvendors; -+ LoongArch_vendor **vendors; -+ size_t nmodels; -+ LoongArch_model **models; -+}; -+ -+static void -+LoongArchDataClear(virCPULoongArchData *data) -+{ -+ if (!data) -+ return; -+ -+ g_free(data->prid); -+} -+ -+static int -+LoongArchDataCopy(virCPULoongArchData *dst, const virCPULoongArchData *src) -+{ -+ size_t i; -+ -+ dst->prid = g_new0(virCPULoongArchPrid, src->len); -+ 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; -+ -+ g_free(vendor); -+} -+ -+static LoongArch_vendor * -+LoongArchVendorFind(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); -+ g_free(model->name); -+ g_free(model); -+} -+ -+static LoongArch_model * -+LoongArchModelCopy(LoongArch_model *model) -+{ -+ LoongArch_model *copy; -+ -+ copy = g_new0(LoongArch_model, 1); -+ copy->name = g_strdup(model->name); -+ -+ if (LoongArchDataCopy(©->data, &model->data) < 0) -+ goto error; -+ -+ copy->vendor = model->vendor; -+ -+ return copy; -+ -+ error: -+ LoongArchModelFree(copy); -+ return NULL; -+} -+ -+static LoongArch_model * -+LoongArchModelFind(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(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, -+ 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]); -+ g_free(map->models); -+ -+ for (i = 0; i < map->nvendors; i++) -+ LoongArchVendorFree(map->vendors[i]); -+ g_free(map->vendors); -+ -+ g_free(map); -+} -+ -+static int -+LoongArchVendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED, -+ const char *name, -+ void *data) -+{ -+ LoongArch_map *map = data; -+ LoongArch_vendor *vendor; -+ int ret = -1; -+ -+ vendor = g_new0(LoongArch_vendor, 1); -+ vendor->name = g_strdup(name); -+ -+ if (LoongArchVendorFind(map, vendor->name)) { -+ virReportError(VIR_ERR_INTERNAL_ERROR, -+ _("CPU vendor %s already defined"), vendor->name); -+ goto cleanup; -+ } -+ -+ VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor); -+ 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; -+ -+ model = g_new0(LoongArch_model, 1); -+ 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; -+ } -+ -+ model->data.prid = g_new0(virCPULoongArchPrid, n); -+ 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; -+ } -+ -+ VIR_APPEND_ELEMENT(map->models, map->nmodels, model); -+ ret = 0; -+ -+ cleanup: -+ LoongArchModelFree(model); -+ g_free(vendor); -+ g_free(nodes); -+ return ret; -+} -+ -+static LoongArch_map * -+LoongArchLoadMap(void) -+{ -+ LoongArch_map *map; -+ -+ map = g_new0(LoongArch_map, 1); -+ if (cpuMapLoad("loongarch64", LoongArchVendorParse, NULL, LoongArchModelParse, map) < 0) -+ goto error; -+ -+ return map; -+ -+ error: -+ LoongArchMapFree(map); -+ return NULL; -+} -+ -+static virCPUData * -+LoongArchMakeCPUData(virArch arch, -+ virCPULoongArchData *data) -+{ -+ virCPUData *cpuData; -+ -+ cpuData = g_new0(virCPUData, 1); -+ cpuData->arch = arch; -+ -+ if (LoongArchDataCopy(&cpuData->data.loongarch, data) < 0) -+ g_free(cpuData); -+ -+ return cpuData; -+} -+ -+static virCPUCompareResult -+LoongArchCompute(virCPUDef *host, -+ const virCPUDef *other, -+ virCPUData *guestData, -+ char **message) -+{ -+ LoongArch_map *map = NULL; -+ LoongArch_model *host_model = NULL; -+ LoongArch_model *guest_model = NULL; -+ virCPUDef *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(virCPUDef *host, -+ virCPUDef *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); -+ } -+ } -+ g_free(message); -+ -+ return ret; -+} -+ -+static int -+LoongArchDriverDecode(virCPUDef *cpu, -+ const virCPUData *data, -+ virDomainCapsCPUModels *models) -+{ -+ int ret = -1; -+ LoongArch_map *map; -+ 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(virCPUData *data) -+{ -+ if (!data) -+ return; -+ -+ LoongArchDataClear(&data->data.loongarch); -+ g_free(data); -+} -+ -+static int virCPULoongArchGetHostPRID(void) -+{ -+ return 0x14c010; -+} -+ -+static int -+virCPULoongArchGetHost(virCPUDef *cpu, -+ virDomainCapsCPUModels *models) -+{ -+ virCPUData *cpuData = NULL; -+ virCPULoongArchData *data; -+ int ret = -1; -+ -+ if (!(cpuData = virCPUDataNew(archs[0]))) -+ goto cleanup; -+ -+ data = &cpuData->data.loongarch; -+ -+ data->prid = g_new0(virCPULoongArchPrid, 1); -+ 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(virCPUDef *guest, -+ const virCPUDef *host, -+ bool relative) -+{ -+ /* -+ * - 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 -+ */ -+ VIR_DEBUG("host model %s, if relatived %d",host->model, relative); -+ if (guest->mode == VIR_CPU_MODE_CUSTOM) -+ guest->match = VIR_CPU_MATCH_EXACT; -+ -+ return 0; -+} -+ -+static virCPUDef * -+LoongArchDriverBaseline(virCPUDef **cpus, -+ unsigned int ncpus, -+ virDomainCapsCPUModels *models, -+ const char **features, -+ bool migratable) -+{ -+ LoongArch_map *map; -+ LoongArch_model *model; -+ LoongArch_vendor *vendor = NULL; -+ virCPUDef *cpu = NULL; -+ size_t i; -+ if (models && *features) { -+ VIR_DEBUG("migratable %d features %s",migratable, *features); -+ } -+ 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++) { -+ 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 = g_new0(virCPUDef ,1); -+ 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) { -+ *models = g_new0(char *, map->nmodels + 1); -+ 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) { -+ g_strfreev(*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..1fde3b5162 ---- /dev/null -+++ b/src/cpu/cpu_loongarch.h -@@ -0,0 +1,28 @@ -+/* -+ * cpu_loongarch.h: CPU driver for 64-bit LOONGARCH CPUs -+ * -+ * Copyright (C) Copyright (C) IBM Corporation, 2010 -+ * -+ * 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..1a759e7d16 ---- /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) 2012 IBM Corporation. -+ * -+ * 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/cpu/meson.build b/src/cpu/meson.build -index b4ad95e46d..ad2f859fd8 100644 ---- a/src/cpu/meson.build -+++ b/src/cpu/meson.build -@@ -5,6 +5,7 @@ cpu_sources = [ - 'cpu_ppc64.c', - 'cpu_s390.c', - 'cpu_x86.c', -+ 'cpu_loongarch.c', - ] - - cpu_lib = static_library( -diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml -index ffe1fa91e5..d302de396a 100644 ---- a/src/cpu_map/index.xml -+++ b/src/cpu_map/index.xml -@@ -110,4 +110,9 @@ - - - -+ -+ -+ -+ -+ - -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 @@ -+ -+ -+ -diff --git a/src/cpu_map/ls_3a5000.xml b/src/cpu_map/ls_3a5000.xml -new file mode 100644 -index 0000000000..f6fe3386f7 ---- /dev/null -+++ b/src/cpu_map/ls_3a5000.xml -@@ -0,0 +1,6 @@ -+ -+ -+ -+ -+ -+ -diff --git a/src/cpu_map/meson.build b/src/cpu_map/meson.build -index 013fc62a02..9657c5164e 100644 ---- a/src/cpu_map/meson.build -+++ b/src/cpu_map/meson.build -@@ -77,6 +77,8 @@ cpumap_data = [ - 'x86_vendors.xml', - 'x86_Westmere-IBRS.xml', - 'x86_Westmere.xml', -+ 'loongarch_vendors.xml', -+ 'ls_3a5000.xml', - ] - - install_data(cpumap_data, install_dir: pkgdatadir / 'cpu_map') -diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c -index c4f7db55c8..75668c6451 100644 ---- a/src/qemu/qemu_capabilities.c -+++ b/src/qemu/qemu_capabilities.c -@@ -2073,6 +2073,9 @@ bool virQEMUCapsHasPCIMultiBus(const virDomainDef *def) - if (ARCH_IS_X86(def->os.arch)) - return true; - -+ if (STRPREFIX(def->os.machine,"loongson7a")) -+ return true; -+ - /* PPC supports multibus on all machine types which have pci since qemu-2.0.0 */ - if (def->os.arch == VIR_ARCH_PPC || - ARCH_IS_PPC64(def->os.arch)) { -@@ -2690,6 +2693,7 @@ static const char *preferredMachines[] = - - "malta", /* VIR_ARCH_MIPS64 */ - "malta", /* VIR_ARCH_MIPS64EL */ -+ "loongson7a", /* VIR_ARCH_LOONGARCH64 */ - "or1k-sim", /* VIR_ARCH_OR32 */ - NULL, /* VIR_ARCH_PARISC (no QEMU impl) */ - NULL, /* VIR_ARCH_PARISC64 (no QEMU impl) */ -@@ -5115,6 +5119,7 @@ virQEMUCapsInitQMPBasicArch(virQEMUCaps *qemuCaps) - case VIR_ARCH_MIPSEL: - case VIR_ARCH_MIPS64: - case VIR_ARCH_MIPS64EL: -+ case VIR_ARCH_LOONGARCH64: - case VIR_ARCH_OR32: - case VIR_ARCH_PARISC: - case VIR_ARCH_PARISC64: -diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c -index a0b8076d6b..8cd03261ac 100644 ---- a/src/qemu/qemu_conf.c -+++ b/src/qemu/qemu_conf.c -@@ -101,7 +101,9 @@ qemuDriverUnlock(virQEMUDriver *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-kvm/loongarch_bios.bin:/usr/share/qemu-kvm/loongarch_bios.bin" -+ - #endif - - -diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c -index 40fe9985e6..814d8cb67d 100644 ---- a/src/qemu/qemu_domain.c -+++ b/src/qemu/qemu_domain.c -@@ -3668,6 +3668,10 @@ qemuDomainDefAddDefaultDevices(virQEMUDriver *driver, - addPCIeRoot = virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_GPEX); - break; - -+ case VIR_ARCH_LOONGARCH64: -+ addPCIeRoot = true; -+ break; -+ - case VIR_ARCH_PPC64: - case VIR_ARCH_PPC64LE: - addPCIRoot = true; -@@ -5065,6 +5069,11 @@ qemuDomainControllerDefPostParse(virDomainControllerDef *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 */ -@@ -8324,6 +8333,13 @@ qemuDomainDefCheckABIStability(virQEMUDriver *driver, - } - - -+bool -+qemuDomainIsLoongson(const virDomainDef *def) -+{ -+ return (STRPREFIX(def->os.machine,"loongson3a") || STRPREFIX(def->os.machine,"loongson7a")); -+} -+ -+ - bool - qemuDomainCheckABIStability(virQEMUDriver *driver, - virDomainObj *vm, -@@ -8664,7 +8680,9 @@ qemuDomainMachineHasBuiltinIDE(const char *machine, - return qemuDomainMachineIsI440FX(machine, arch) || - STREQ(machine, "malta") || - STREQ(machine, "sun4u") || -- STREQ(machine, "g3beige"); -+ STREQ(machine, "g3beige") || -+ STREQ(machine, "loongson3a") || -+ STREQ(machine, "loongson7a"); - } - - -diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h -index e5046367e3..57f1f97348 100644 ---- a/src/qemu/qemu_domain.h -+++ b/src/qemu/qemu_domain.h -@@ -770,6 +770,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 18fc34d049..c3fac1c33b 100644 ---- a/src/qemu/qemu_domain_address.c -+++ b/src/qemu/qemu_domain_address.c -@@ -2026,6 +2026,59 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDef *def, - } - - -+static int -+qemuDomainValidateDevicePCISlotsLoongson(virDomainDef *def, -+ virDomainPCIAddressSet *addrs) -+{ -+ int ret = -1; -+ virPCIDeviceAddress tmp_addr; -+ char *addrStr = NULL; -+ virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_AUTOASSIGN -+ | 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) -+ goto cleanup; -+ } -+ -+ 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 */ -+ virDomainVideoDef *primaryVideo = def->videos[0]; -+ -+ if (virDeviceInfoPCIAddressIsWanted(&primaryVideo->info)) { -+ memset(&tmp_addr, 0, sizeof(tmp_addr)); -+ tmp_addr.slot = 2; -+ -+ if (!(addrStr = virPCIDeviceAddressAsString(&tmp_addr))) -+ goto cleanup; -+ if (!virDomainPCIAddressValidate(addrs, &tmp_addr, -+ addrStr, flags, true)) -+ goto cleanup; -+ -+ if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { -+ if (qemuDomainPCIAddressReserveNextAddr(addrs, -+ &primaryVideo->info) < 0) -+ goto cleanup; -+ } else { -+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) -+ goto cleanup; -+ primaryVideo->info.addr.pci = tmp_addr; -+ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; -+ } -+ } -+ } -+ ret = 0; -+ cleanup: -+ VIR_FREE(addrStr); -+ return ret; -+} -+ -+ - static int - qemuDomainValidateDevicePCISlotsChipsets(virDomainDef *def, - virDomainPCIAddressSet *addrs) -@@ -2040,6 +2093,11 @@ qemuDomainValidateDevicePCISlotsChipsets(virDomainDef *def, - return -1; - } - -+ if (qemuDomainIsLoongson(def) && -+ qemuDomainValidateDevicePCISlotsLoongson(def, addrs) < 0) { -+ return -1; -+ } -+ - return 0; - } - -diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c -index 7bc14293d6..7d01d31aaf 100644 ---- a/src/qemu/qemu_validate.c -+++ b/src/qemu/qemu_validate.c -@@ -186,7 +186,8 @@ qemuValidateDomainDefFeatures(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'"), -diff --git a/src/util/virarch.c b/src/util/virarch.c -index 2134dd6a9d..9f40a7110c 100644 ---- a/src/util/virarch.c -+++ b/src/util/virarch.c -@@ -59,6 +59,7 @@ static const struct virArchData { - - { "mips64", 64, VIR_ARCH_BIG_ENDIAN }, - { "mips64el", 64, VIR_ARCH_LITTLE_ENDIAN }, -+ { "loongarch64", 64, VIR_ARCH_LITTLE_ENDIAN }, - { "openrisc", 32, VIR_ARCH_BIG_ENDIAN }, - { "parisc", 32, VIR_ARCH_BIG_ENDIAN }, - { "parisc64", 64, VIR_ARCH_BIG_ENDIAN }, -@@ -222,6 +223,8 @@ virArch virArchFromHost(void) - arch = VIR_ARCH_X86_64; - } else if (STREQ(ut.machine, "arm64")) { - arch = VIR_ARCH_AARCH64; -+ } 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/virarch.h b/src/util/virarch.h -index 528f84f8a5..7d396f2fff 100644 ---- a/src/util/virarch.h -+++ b/src/util/virarch.h -@@ -44,6 +44,7 @@ typedef enum { - - VIR_ARCH_MIPS64, /* MIPS 64 BE https://en.wikipedia.org/wiki/MIPS_architecture */ - VIR_ARCH_MIPS64EL, /* MIPS 64 LE https://en.wikipedia.org/wiki/MIPS_architecture */ -+ VIR_ARCH_LOONGARCH64, - VIR_ARCH_OR32, /* OpenRisc 32 BE https://en.wikipedia.org/wiki/OpenRISC#QEMU_support */ - VIR_ARCH_PARISC, /* PA-Risc 32 BE https://en.wikipedia.org/wiki/PA-RISC */ - VIR_ARCH_PARISC64, /* PA-Risc 64 BE https://en.wikipedia.org/wiki/PA-RISC */ -@@ -98,6 +99,8 @@ typedef enum { - #define ARCH_IS_MIPS64(arch) ((arch) == VIR_ARCH_MIPS64 ||\ - (arch) == VIR_ARCH_MIPS64EL) - -+#define ARCH_IS_LOONGARCH(arch) ((arch) == VIR_ARCH_LOONGARCH64) -+ - typedef enum { - VIR_ARCH_LITTLE_ENDIAN, - VIR_ARCH_BIG_ENDIAN, -diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c -index 35f41daef2..137796ea07 100644 ---- a/src/util/virhostcpu.c -+++ b/src/util/virhostcpu.c -@@ -546,7 +546,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 af9e03c5ac..9577cf1910 100644 ---- a/src/util/virsysinfo.c -+++ b/src/util/virsysinfo.c -@@ -1247,7 +1247,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(); --- -2.27.0 - diff --git a/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch b/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch new file mode 100644 index 0000000..90206d3 --- /dev/null +++ b/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch @@ -0,0 +1,75 @@ +From a4fc108994dd64e0880be10b93b48830f32907de Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jim Fehlig +Date: Mon, 10 Jan 2022 11:42:58 -0700 +Subject: [PATCH] build: Only install libvirt-guests when building libvirtd + +libvirt-guests was already moved to the libvirt daemon package in commit +d800c50349. It only needs to be installed when building libvirtd. + +Signed-off-by: Jim Fehlig +Reviewed-by: Andrea Bolognani +(cherry picked from commit 3be5ba11a2c6fcb2dfdffa03ab4f847113f36b85) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2157091 +Signed-off-by: Michal Privoznik +--- + tools/meson.build | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/tools/meson.build b/tools/meson.build +index 22fa3604ba..2d0aecb90b 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -297,29 +297,31 @@ if conf.has('WITH_SANLOCK') + ) + endif + +-configure_file( +- input: 'libvirt-guests.sh.in', +- output: '@BASENAME@', +- configuration: tools_conf, +- install: true, +- install_dir: libexecdir, +- install_mode: 'rwxrwxr-x', +-) +- +-if init_script == 'systemd' +- install_data( +- 'libvirt-guests.sysconf', +- install_dir: sysconfdir / 'sysconfig', +- rename: 'libvirt-guests', +- ) +- ++if conf.has('WITH_LIBVIRTD') + configure_file( +- input: 'libvirt-guests.service.in', ++ input: 'libvirt-guests.sh.in', + output: '@BASENAME@', + configuration: tools_conf, + install: true, +- install_dir: prefix / 'lib' / 'systemd' / 'system', ++ install_dir: libexecdir, ++ install_mode: 'rwxrwxr-x', + ) ++ ++ if init_script == 'systemd' ++ install_data( ++ 'libvirt-guests.sysconf', ++ install_dir: sysconfdir / 'sysconfig', ++ rename: 'libvirt-guests', ++ ) ++ ++ configure_file( ++ input: 'libvirt-guests.service.in', ++ output: '@BASENAME@', ++ configuration: tools_conf, ++ install: true, ++ install_dir: prefix / 'lib' / 'systemd' / 'system', ++ ) ++ endif + endif + + if bash_completion_dep.found() +-- +2.39.0 + diff --git a/libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch b/libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch new file mode 100644 index 0000000..1c7bab7 --- /dev/null +++ b/libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch @@ -0,0 +1,46 @@ +From facb1f67ffca12cbe87abb50f1900956624c9774 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Thu, 24 Nov 2022 10:28:59 +0100 +Subject: [PATCH] conf: Make VIR_DOMAIN_NET_TYPE_ETHERNET not share 'host view' + +When setting up QoS for a domain , or when reporting +its statistics we may need to swap TX/RX values. This is all +explained in comment to virDomainNetTypeSharesHostView(). +However, this function claims that VIR_DOMAIN_NET_TYPE_ETHERNET +also shares the 'host view', meaning the TX/RX values must be +swapped. But that's not true. + +An easy reproducer is to start a domain with two -s: +one type of network, the other of type ethernet and configure the +same for both. Reversed setting can then be observed +(e.g. via tc). + +Reported-by: Oleg Vasilev +Signed-off-by: Michal Privoznik +Reviewed-by: Jiri Denemark +(cherry picked from commit 0862cb3ce46253a58ca02d36b2b6a6397a60bfc7) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2173976 +Signed-off-by: Michal Privoznik +--- + src/conf/domain_conf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 95afd9226e..b3bc027fd9 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -30473,9 +30473,9 @@ virDomainNetTypeSharesHostView(const virDomainNetDef *net) + virDomainNetType actualType = virDomainNetGetActualType(net); + switch (actualType) { + case VIR_DOMAIN_NET_TYPE_DIRECT: +- case VIR_DOMAIN_NET_TYPE_ETHERNET: + return true; + case VIR_DOMAIN_NET_TYPE_USER: ++ case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: +-- +2.39.2 + diff --git a/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch b/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch new file mode 100644 index 0000000..92450af --- /dev/null +++ b/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch @@ -0,0 +1,58 @@ +From 6725459d1b7d326b65ce4f19640a49851b54ae9b Mon Sep 17 00:00:00 2001 +Message-Id: <6725459d1b7d326b65ce4f19640a49851b54ae9b@dist-git> +From: Peter Krempa +Date: Thu, 1 Dec 2022 17:02:42 +0100 +Subject: [PATCH] qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray + for optional data + +The 'dependencies' field in the return data may be missing in some +cases. Historically 'virJSONValueObjectGetStringArray' didn't report +error in such case, but later refactor (commit 043b50b948ef3c2 ) added +an error in order to use it in other places too. + +Unfortunately this results in the error log being spammed with an +irrelevant error in case when qemuAgentGetDisks is invoked on a VM +running windows. + +Replace the use of virJSONValueObjectGetStringArray by fetching the +array first and calling virJSONValueArrayToStringList only when we have +an array. + +Fixes: 043b50b948ef3c2a4adf5fa32a93ec2589851ac6 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2149752 +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 3b576601dfb924bb518870a01de5d1a421cbb467) +https://bugzilla.redhat.com/show_bug.cgi?id=2152079 +--- + src/qemu/qemu_agent.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c +index f33cd47078..8a55044c9e 100644 +--- a/src/qemu/qemu_agent.c ++++ b/src/qemu/qemu_agent.c +@@ -2550,6 +2550,7 @@ int qemuAgentGetDisks(qemuAgent *agent, + for (i = 0; i < ndata; i++) { + virJSONValue *addr; + virJSONValue *entry = virJSONValueArrayGet(data, i); ++ virJSONValue *dependencies; + qemuAgentDiskInfo *disk; + + if (!entry) { +@@ -2575,7 +2576,11 @@ int qemuAgentGetDisks(qemuAgent *agent, + goto error; + } + +- disk->dependencies = virJSONValueObjectGetStringArray(entry, "dependencies"); ++ if ((dependencies = virJSONValueObjectGetArray(entry, "dependencies"))) { ++ if (!(disk->dependencies = virJSONValueArrayToStringList(dependencies))) ++ goto error; ++ } ++ + disk->alias = g_strdup(virJSONValueObjectGetString(entry, "alias")); + addr = virJSONValueObjectGetObject(entry, "address"); + if (addr) { +-- +2.39.0 + diff --git a/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch b/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch new file mode 100644 index 0000000..60b9b5f --- /dev/null +++ b/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch @@ -0,0 +1,57 @@ +From 10d13b42fdec802e07b00825058d3e33ee843f50 Mon Sep 17 00:00:00 2001 +Message-Id: <10d13b42fdec802e07b00825058d3e33ee843f50@dist-git> +From: Michal Privoznik +Date: Wed, 28 Sep 2022 10:12:36 +0200 +Subject: [PATCH] qemuProcessReconnect: Don't build memory paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let me take you on a short trip to history. A long time ago, +libvirt would configure all QEMUs to use $hugetlbfs/libvirt/qemu +for their hugepages setup. This was problematic, because it did +not allow enough separation between guests. Therefore in +v3.0.0-rc1~367 the path changed to a per-domain basis: + + $hugetlbfs/libvirt/qemu/$domainShortName + +And to help with migration on daemon restart a call to +qemuProcessBuildDestroyMemoryPaths() was added to +qemuProcessReconnect() (well, it was named +qemuProcessBuildDestroyHugepagesPath() back then, see +v3.10.0-rc1~174). This was desirable then, because the memory +hotplug code did not call the function, it simply assumes +per-domain paths to exist. But this changed in v3.5.0-rc1~92 +after which the per-domain paths are created on memory hotplug +too. + +Therefore, it's no longer necessary to create these paths in +qemuProcessReconnect(). They are created exactly when needed +(domain startup and memory hotplug). + +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit 3478cca80ea7382cfdbff836d5d0b92aa014297b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1164340aa9..0fb665bc82 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -8869,9 +8869,6 @@ qemuProcessReconnect(void *opaque) + goto cleanup; + } + +- if (qemuProcessBuildDestroyMemoryPaths(driver, obj, NULL, true) < 0) +- goto error; +- + if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps, + driver, obj, false)) < 0) { + goto error; +-- +2.38.1 + diff --git a/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch b/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch new file mode 100644 index 0000000..c82b2d5 --- /dev/null +++ b/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch @@ -0,0 +1,80 @@ +From 8283452dfdc2d33b717b81f9a011dc95aa9017e3 Mon Sep 17 00:00:00 2001 +Message-Id: <8283452dfdc2d33b717b81f9a011dc95aa9017e3@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:22 +0200 +Subject: [PATCH] qemu_namespace: Fix a corner case in + qemuDomainGetPreservedMounts() + +When setting up namespace for QEMU we look at mount points under +/dev (like /dev/pts, /dev/mqueue/, etc.) because we want to +preserve those (which is done by moving them to a temp location, +unshare(), and then moving them back). We have a convenience +helper - qemuDomainGetPreservedMounts() - that processes the +mount table and (optionally) moves the other filesystems too. +This helper is also used when attempting to create a path in NS, +because the path, while starting with "/dev/" prefix, may +actually lead to one of those filesystems that we preserved. + +And here comes the corner case: while we require the parent mount +table to be in shared mode (equivalent of `mount --make-rshared /'), +these mount events propagate iff the target path exist inside the +slave mount table (= QEMU's private namespace). And since we +create only a subset of /dev nodes, well, that assumption is not +always the case. + +For instance, assume that a domain is already running, no +hugepages were configured for it nor any hugetlbfs is mounted. +Now, when a hugetlbfs is mounted into '/dev/hugepages', this is +propagated into the QEMU's namespace, but since the target dir +does not exist in the private /dev, the FS is not mounted in the +namespace. + +Fortunately, this difference between namespaces is visible when +comparing /proc/mounts and /proc/$PID/mounts (where PID is the +QEMU's PID). Therefore, if possible we should look at the latter. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 46b03819ae8d833b11c2aaccb2c2a0361727f51b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 4bff325a2c..fc286ab0be 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -110,6 +110,8 @@ qemuDomainGetPreservedMountPath(virQEMUDriverConfig *cfg, + * b) generate backup path for all the entries in a) + * + * Any of the return pointers can be NULL. Both arrays are NULL-terminated. ++ * Get the mount table either from @vm's PID (if running), or from the ++ * namespace we're in (if @vm's not running). + * + * Returns 0 on success, -1 otherwise (with error reported) + */ +@@ -124,12 +126,18 @@ qemuDomainGetPreservedMounts(virQEMUDriverConfig *cfg, + size_t nmounts = 0; + g_auto(GStrv) paths = NULL; + g_auto(GStrv) savePaths = NULL; ++ g_autofree char *mountsPath = NULL; + size_t i; + + if (ndevPath) + *ndevPath = 0; + +- if (virFileGetMountSubtree(QEMU_PROC_MOUNTS, "/dev", &mounts, &nmounts) < 0) ++ if (vm->pid > 0) ++ mountsPath = g_strdup_printf("/proc/%lld/mounts", (long long) vm->pid); ++ else ++ mountsPath = g_strdup(QEMU_PROC_MOUNTS); ++ ++ if (virFileGetMountSubtree(mountsPath, "/dev", &mounts, &nmounts) < 0) + return -1; + + if (nmounts == 0) +-- +2.38.1 + diff --git a/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch b/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch new file mode 100644 index 0000000..7fc45c2 --- /dev/null +++ b/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch @@ -0,0 +1,68 @@ +From 1772cf15e26cc620f71513689f2ac2409a22df93 Mon Sep 17 00:00:00 2001 +Message-Id: <1772cf15e26cc620f71513689f2ac2409a22df93@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:58 +0200 +Subject: [PATCH] qemu_namespace: Introduce qemuDomainNamespaceSetupPath() + +Sometimes it may come handy to just bind mount a directory/file +into domain's namespace. Implement a thin wrapper over +qemuNamespaceMknodPaths() which has all the logic we need. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 5853d707189005a4ea5b2215e80853867b822fd9) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 19 +++++++++++++++++++ + src/qemu/qemu_namespace.h | 4 ++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index fc286ab0be..74ffd6fb90 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1398,6 +1398,25 @@ qemuNamespaceUnlinkPaths(virDomainObj *vm, + } + + ++int ++qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created) ++{ ++ g_autoptr(virGSListString) paths = NULL; ++ ++ if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) ++ return 0; ++ ++ paths = g_slist_prepend(paths, g_strdup(path)); ++ ++ if (qemuNamespaceMknodPaths(vm, paths, created) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++ + int + qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, +diff --git a/src/qemu/qemu_namespace.h b/src/qemu/qemu_namespace.h +index 020aca13d8..1ab9322061 100644 +--- a/src/qemu/qemu_namespace.h ++++ b/src/qemu/qemu_namespace.h +@@ -49,6 +49,10 @@ void qemuDomainDestroyNamespace(virQEMUDriver *driver, + + bool qemuDomainNamespaceAvailable(qemuDomainNamespace ns); + ++int qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created); ++ + int qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, + bool *created); +-- +2.38.1 + diff --git a/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch b/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch new file mode 100644 index 0000000..6796a0a --- /dev/null +++ b/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch @@ -0,0 +1,45 @@ +From a3fac9a9faf966abd77d63d064eef9d29337fd20 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:37:23 +0200 +Subject: [PATCH] qemu_namespace: Tolerate missing ACLs when creating a path in + namespace + +When creating a path in a domain's mount namespace we try to set +ACLs on it, so that it's a verbatim copy of the path in parent's +namespace. The ACLs are queried upfront (by +qemuNamespaceMknodItemInit()) but this is fault tolerant so the +pointer to ACLs might be NULL (meaning no ACLs were queried, for +instance because the underlying filesystem does not support +them). But then we take this NULL and pass it to virFileSetACLs() +which immediately returns an error because NULL is invalid value. + +Mimic what we do with SELinux label - only set ACLs if they are +non-NULL which includes symlinks. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 687374959e160dc566bd4b6d43c7bf1beb470c59) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 94453033f5..4bff325a2c 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1023,8 +1023,7 @@ qemuNamespaceMknodOne(qemuNamespaceMknodItem *data) + goto cleanup; + } + +- /* Symlinks don't have ACLs. */ +- if (!isLink && ++ if (data->acl && + virFileSetACLs(data->file, data->acl) < 0 && + errno != ENOTSUP) { + virReportSystemError(errno, +-- +2.38.1 + diff --git a/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch b/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch new file mode 100644 index 0000000..05516dc --- /dev/null +++ b/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch @@ -0,0 +1,50 @@ +From 51034fde2272e6d7855433ac8ef79ffa59ac14a7 Mon Sep 17 00:00:00 2001 +Message-Id: <51034fde2272e6d7855433ac8ef79ffa59ac14a7@dist-git> +From: Michal Privoznik +Date: Mon, 5 Sep 2022 10:34:44 +0200 +Subject: [PATCH] qemu_process: Don't require a hugetlbfs mount for memfd + +The aim of qemuProcessNeedHugepagesPath() is to determine whether +a hugetlbfs mount point is required for given domain (as in +whether qemuBuildMemoryBackendProps() picks up +memory-backend-file pointing to a hugetlbfs mount point). Well, +when domain is configured to use memfd backend then that +condition can never be true. Therefore, skip creating domain's +private path under hugetlbfs mount points. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit f14f8dff9330ed51d817f190a2ee9ac76dfac00b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5c6657a876..540eee9ff0 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3810,8 +3810,18 @@ qemuProcessNeedHugepagesPath(virDomainDef *def, + const long system_pagesize = virGetSystemPageSizeKB(); + size_t i; + +- if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) ++ switch ((virDomainMemorySource)def->mem.source) { ++ case VIR_DOMAIN_MEMORY_SOURCE_FILE: ++ /* This needs a hugetlbfs mount. */ + return true; ++ case VIR_DOMAIN_MEMORY_SOURCE_MEMFD: ++ /* memfd works without a hugetlbfs mount */ ++ return false; ++ case VIR_DOMAIN_MEMORY_SOURCE_NONE: ++ case VIR_DOMAIN_MEMORY_SOURCE_ANONYMOUS: ++ case VIR_DOMAIN_MEMORY_SOURCE_LAST: ++ break; ++ } + + for (i = 0; i < def->mem.nhugepages; i++) { + if (def->mem.hugepages[i].size != system_pagesize) +-- +2.38.1 + diff --git a/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch b/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch new file mode 100644 index 0000000..f42e6d8 --- /dev/null +++ b/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch @@ -0,0 +1,65 @@ +From 39c959670a3aa3bfcd410c46d3af6a8eb2810cc4 Mon Sep 17 00:00:00 2001 +Message-Id: <39c959670a3aa3bfcd410c46d3af6a8eb2810cc4@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:45:51 +0200 +Subject: [PATCH] qemu_process.c: Propagate hugetlbfs mounts on reconnect + +When reconnecting to a running QEMU process, we construct the +per-domain path in all hugetlbfs mounts. This is a relict from +the past (v3.4.0-100-g5b24d25062) where we switched to a +per-domain path and we want to create those paths when libvirtd +restarts on upgrade. + +And with namespaces enabled there is one corner case where the +path is not created. In fact an error is reported and the +reconnect fails. Ideally, all mount events are propagated into +the QEMU's namespace. And they probably are, except when the +target path does not exist inside the namespace. Now, it's pretty +common for users to mount hugetlbfs under /dev (e.g. +/dev/hugepages), but if domain is started without hugepages (or +more specifically - private hugetlbfs path wasn't created on +domain startup), then the reconnect code tries to create it. +But it fails to do so, well, it fails to set seclabels on the +path because, because the path does not exist in the private +namespace. And it doesn't exist because we specifically create +only a subset of all possible /dev nodes. Therefore, the mount +event, whilst propagated, is not successful and hence the +filesystem is not mounted. We have to do it ourselves. + +If hugetlbfs is mount anywhere else there's no problem and this +is effectively a dead code. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 0377177c7856bb87a9d8aa1324b54f5fbe9f1e5b) + +Conflicts: +- docs/kbase/qemu-passthrough-security.rst: Well, v8.8.0-rc1~32 + isn't backported, thus we can't remove a paragraph that the + backported commit did. It's a documentation after all, so no + harm. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132176 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 540eee9ff0..1164340aa9 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3906,6 +3906,9 @@ qemuProcessBuildDestroyMemoryPathsImpl(virQEMUDriver *driver, + return -1; + } + ++ if (qemuDomainNamespaceSetupPath(vm, path, NULL) < 0) ++ return -1; ++ + if (qemuSecurityDomainSetPathLabel(driver, vm, path, true) < 0) + return -1; + } else { +-- +2.38.1 + diff --git a/libvirt-tools-Fix-install_mode-for-some-scripts.patch b/libvirt-tools-Fix-install_mode-for-some-scripts.patch new file mode 100644 index 0000000..5fe194a --- /dev/null +++ b/libvirt-tools-Fix-install_mode-for-some-scripts.patch @@ -0,0 +1,65 @@ +From 5f671e3950e5ac3da2989ebd62c5694c66e6cd68 Mon Sep 17 00:00:00 2001 +Message-Id: <5f671e3950e5ac3da2989ebd62c5694c66e6cd68@dist-git> +From: Michal Privoznik +Date: Thu, 8 Dec 2022 08:39:24 +0100 +Subject: [PATCH] tools: Fix install_mode for some scripts + +Scripts from the following list were installed with group write +bit set: virt-xml-validate, virt-pki-validate, +virt-sanlock-cleanup, libvirt-guests.sh. This is very unusual and +in contrast with the way other scripts/binaries are installed. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151202 +Signed-off-by: Michal Privoznik +Reviewed-by: Peter Krempa +Reviewed-by: Jiri Denemark +(cherry picked from commit e771e32f15ff2b263ca70306d93080541a96792b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2157091 +Signed-off-by: Michal Privoznik +--- + tools/meson.build | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tools/meson.build b/tools/meson.build +index 2d0aecb90b..7c6e527939 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -247,7 +247,7 @@ configure_file( + configuration: tools_conf, + install: true, + install_dir: bindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + configure_file( +@@ -256,7 +256,7 @@ configure_file( + configuration: tools_conf, + install: true, + install_dir: bindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + executable( +@@ -293,7 +293,7 @@ if conf.has('WITH_SANLOCK') + configuration: tools_conf, + install: true, + install_dir: sbindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + endif + +@@ -304,7 +304,7 @@ if conf.has('WITH_LIBVIRTD') + configuration: tools_conf, + install: true, + install_dir: libexecdir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + if init_script == 'systemd' +-- +2.39.0 + diff --git a/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch b/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch new file mode 100644 index 0000000..fd230a1 --- /dev/null +++ b/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch @@ -0,0 +1,124 @@ +From de2fa128a683f6a08b2d3fe95fc7857faed03cbf Mon Sep 17 00:00:00 2001 +Message-Id: +From: Peter Krempa +Date: Thu, 1 Dec 2022 13:32:07 +0100 +Subject: [PATCH] util: json: Split out array->strinlist conversion from + virJSONValueObjectGetStringArray + +Introduce virJSONValueArrayToStringList which does only the conversion +from an array to a stringlist. + +This will allow refactoring the callers to be more careful in case when +they want to handle the existance of the member in the parent object +differently. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 6765bdeaf7e9cbdb4c39d47f3b77fb28a498408a) +https://bugzilla.redhat.com/show_bug.cgi?id=2152079 +--- + src/libvirt_private.syms | 1 + + src/util/virjson.c | 43 ++++++++++++++++++++++------------------ + src/util/virjson.h | 2 ++ + 3 files changed, 27 insertions(+), 19 deletions(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 5b7a056151..fa734dfd33 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2513,6 +2513,7 @@ virJSONValueArrayForeachSteal; + virJSONValueArrayGet; + virJSONValueArraySize; + virJSONValueArraySteal; ++virJSONValueArrayToStringList; + virJSONValueCopy; + virJSONValueFree; + virJSONValueFromString; +diff --git a/src/util/virjson.c b/src/util/virjson.c +index 6e13e97e15..5f1565107d 100644 +--- a/src/util/virjson.c ++++ b/src/util/virjson.c +@@ -1312,10 +1312,7 @@ virJSONValueObjectStealObject(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + { +- g_auto(GStrv) ret = NULL; + virJSONValue *data; +- size_t n; +- size_t i; + + data = virJSONValueObjectGetArray(object, key); + if (!data) { +@@ -1325,32 +1322,40 @@ virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + return NULL; + } + +- n = virJSONValueArraySize(data); +- ret = g_new0(char *, n + 1); ++ return virJSONValueArrayToStringList(data); ++} ++ ++ ++/** ++ * virJSONValueArrayToStringList: ++ * @data: a JSON array containing strings to convert ++ * ++ * Converts @data a JSON array containing strings to a NULL-terminated string ++ * list. @data must be a JSON array. In case @data is doesn't contain only ++ * strings an error is reported. ++ */ ++char ** ++virJSONValueArrayToStringList(virJSONValue *data) ++{ ++ size_t n = virJSONValueArraySize(data); ++ g_auto(GStrv) ret = g_new0(char *, n + 1); ++ size_t i; ++ + for (i = 0; i < n; i++) { + virJSONValue *child = virJSONValueArrayGet(data, i); +- const char *tmp; + +- if (!child) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element is missing item %zu"), +- key, i); ++ if (!child || ++ !(ret[i] = g_strdup(virJSONValueGetString(child)))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("JSON string array contains non-string element")); + return NULL; + } +- +- if (!(tmp = virJSONValueGetString(child))) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element does not contain a string"), +- key); +- return NULL; +- } +- +- ret[i] = g_strdup(tmp); + } + + return g_steal_pointer(&ret); + } + ++ + /** + * virJSONValueObjectForeachKeyValue: + * @object: JSON object to iterate +diff --git a/src/util/virjson.h b/src/util/virjson.h +index aced48a538..c9f83ab2bc 100644 +--- a/src/util/virjson.h ++++ b/src/util/virjson.h +@@ -172,6 +172,8 @@ virJSONValueObjectGetString(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, + const char *key); ++char ** ++virJSONValueArrayToStringList(virJSONValue *data); + const char * + virJSONValueObjectGetStringOrNumber(virJSONValue *object, + const char *key); +-- +2.39.0 + diff --git a/libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch b/libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch new file mode 100644 index 0000000..ea4e7d5 --- /dev/null +++ b/libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch @@ -0,0 +1,65 @@ +From e37daa747c6615da25a9285be580a05081b14993 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Fri, 8 Jul 2022 14:29:32 +0200 +Subject: [PATCH] vircpi: Add PCIe 5.0 and 6.0 link speeds +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The PCIe 5.0 and PCIe 6.0 standards define new link speeds: +32GT/s and 64GT/s, respectively. Update our internal enum to +include these new speeds. Otherwise we format incorrect XML: + + + + + + +Like all "good" specifications, these are also locked behind a +login portal. But we can look at pciutils' source code: [1] and +[2]. + +1: https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git/commit/ls-caps.c?id=caca31a0eea41c7b051705704c1158fddc02fbd2 +2: https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git/commit/ls-caps.c?id=5bdf63b6b1bc35b59c4b3f47f7ca83ca1868155b + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2105231 +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit d33c2a9e2f933b31f8e96e9938c237bdffe27f84) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2170233 +Signed-off-by: Michal Privoznik +--- + src/util/virpci.c | 2 +- + src/util/virpci.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/util/virpci.c b/src/util/virpci.c +index 0d476cd8b4..4949d1a3d4 100644 +--- a/src/util/virpci.c ++++ b/src/util/virpci.c +@@ -46,7 +46,7 @@ VIR_LOG_INIT("util.pci"); + + VIR_ENUM_IMPL(virPCIELinkSpeed, + VIR_PCIE_LINK_SPEED_LAST, +- "", "2.5", "5", "8", "16", ++ "", "2.5", "5", "8", "16", "32", "64" + ); + + VIR_ENUM_IMPL(virPCIStubDriver, +diff --git a/src/util/virpci.h b/src/util/virpci.h +index b9b9cd7b34..4d9193f24e 100644 +--- a/src/util/virpci.h ++++ b/src/util/virpci.h +@@ -83,6 +83,8 @@ typedef enum { + VIR_PCIE_LINK_SPEED_5, + VIR_PCIE_LINK_SPEED_8, + VIR_PCIE_LINK_SPEED_16, ++ VIR_PCIE_LINK_SPEED_32, ++ VIR_PCIE_LINK_SPEED_64, + VIR_PCIE_LINK_SPEED_LAST + } virPCIELinkSpeed; + +-- +2.39.1 + diff --git a/libvirt.spec b/libvirt.spec index 061e5d7..44ee06f 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -3,20 +3,19 @@ # This spec file assumes you are building on a Fedora or RHEL version # that's still supported by the vendor. It may work on other distros # or versions, but no effort will be made to ensure that going forward. -%define anolis_release .0.1 %define min_rhel 8 %define min_fedora 33 -%define arches_qemu_kvm %{ix86} x86_64 %{power64} %{arm} aarch64 s390x loongarch64 +%define arches_qemu_kvm %{ix86} x86_64 %{power64} %{arm} aarch64 s390x %if 0%{?rhel} %if 0%{?rhel} > 8 - %define arches_qemu_kvm x86_64 aarch64 s390x loongarch64 + %define arches_qemu_kvm x86_64 aarch64 s390x %else - %define arches_qemu_kvm x86_64 %{power64} aarch64 s390x loongarch64 + %define arches_qemu_kvm x86_64 %{power64} aarch64 s390x %endif %endif -%define arches_64bit x86_64 %{power64} aarch64 s390x riscv64 loongarch64 +%define arches_64bit x86_64 %{power64} aarch64 s390x riscv64 %define arches_x86 %{ix86} x86_64 %define arches_systemtap_64bit %{arches_64bit} @@ -24,9 +23,9 @@ %define arches_xen %{arches_x86} aarch64 %define arches_vbox %{arches_x86} %define arches_ceph %{arches_64bit} -%define arches_zfs %{arches_x86} %{power64} %{arm} loongarch64 -%define arches_numactl %{arches_x86} %{power64} aarch64 s390x loongarch64 -%define arches_numad %{arches_x86} %{power64} aarch64 loongarch64 +%define arches_zfs %{arches_x86} %{power64} %{arm} +%define arches_numactl %{arches_x86} %{power64} aarch64 s390x +%define arches_numad %{arches_x86} %{power64} aarch64 # The hypervisor drivers that run in libvirtd %define with_qemu 0%{!?_without_qemu:1} @@ -211,7 +210,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.0.0 -Release: 10%{anolis_release}%{?dist}%{?extra_release} +Release: 10.4%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -268,7 +267,18 @@ Patch44: libvirt-virsh-Add-support-for-VIR_MIGRATE_ZEROCOPY-flag.patch Patch45: libvirt-qemu_migration-Implement-VIR_MIGRATE_ZEROCOPY-flag.patch Patch46: libvirt-security_selinux.c-Relabel-existing-mode-bind-UNIX-sockets.patch Patch47: libvirt-RHEL-qemu_migration-Fix-restoring-memlock-limit-on-destination.patch -Patch1000: libvirt-Add-loongarch-support.patch +Patch48: libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch +Patch49: libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch +Patch50: libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch +Patch51: libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch +Patch52: libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch +Patch53: libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch +Patch54: libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch +Patch55: libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch +Patch56: libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch +Patch57: libvirt-tools-Fix-install_mode-for-some-scripts.patch +Patch58: libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch +Patch59: libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2142,8 +2152,25 @@ exit 0 %changelog -* Tue Dec 27 2022 zhaotianrui - 8.0.0-10.0.1 -- Add loongarch support +* Thu Mar 2 2023 Jiri Denemark - 8.0.0-10.4.el8 +- conf: Make VIR_DOMAIN_NET_TYPE_ETHERNET not share 'host view' (rhbz#2173976) + +* Fri Feb 17 2023 Jiri Denemark - 8.0.0-10.3.el8 +- vircpi: Add PCIe 5.0 and 6.0 link speeds (rhbz#2170233) + +* Thu Jan 5 2023 Jiri Denemark - 8.0.0-10.2.el8 +- util: json: Split out array->strinlist conversion from virJSONValueObjectGetStringArray (rhbz#2152079) +- qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray for optional data (rhbz#2152079) +- build: Only install libvirt-guests when building libvirtd (rhbz#2157091) +- tools: Fix install_mode for some scripts (rhbz#2157091) + +* Wed Nov 9 2022 Jiri Denemark - 8.0.0-10.1.el8 +- qemu_process: Don't require a hugetlbfs mount for memfd (rhbz#2132176) +- qemu_namespace: Tolerate missing ACLs when creating a path in namespace (rhbz#2132176) +- qemu_namespace: Fix a corner case in qemuDomainGetPreservedMounts() (rhbz#2132176) +- qemu_namespace: Introduce qemuDomainNamespaceSetupPath() (rhbz#2132176) +- qemu_process.c: Propagate hugetlbfs mounts on reconnect (rhbz#2132176) +- qemuProcessReconnect: Don't build memory paths (rhbz#2132176) * Mon Jul 25 2022 Jiri Denemark - 8.0.0-10 - security_selinux.c: Relabel existing mode="bind" UNIX sockets (rhbz#2101575) -- Gitee From 57a6b11310bc3f294d4755a2f12213ab157eacce Mon Sep 17 00:00:00 2001 From: zhaotianrui Date: Thu, 8 Sep 2022 09:28:25 -0400 Subject: [PATCH 2/2] Add loongarch support Signed-off-by: zhaotianrui --- libvirt-Add-loongarch-support.patch | 1233 +++++++++++++++++++++++++++ libvirt.spec | 21 +- 2 files changed, 1246 insertions(+), 8 deletions(-) create mode 100644 libvirt-Add-loongarch-support.patch diff --git a/libvirt-Add-loongarch-support.patch b/libvirt-Add-loongarch-support.patch new file mode 100644 index 0000000..94fd22a --- /dev/null +++ b/libvirt-Add-loongarch-support.patch @@ -0,0 +1,1233 @@ +From da7befb4ce165d692f34156f740f4ea3ce2b7fec Mon Sep 17 00:00:00 2001 +From: zhaotianrui +Date: Sat, 3 Sep 2022 14:23:43 -0400 +Subject: [PATCH] Add loongarch support + +Signed-off-by: zhaotianrui +Change-Id: I8d245bc2fb914b08af4ade8e334d59ba3a5c2f01 +--- + po/POTFILES.in | 1 + + src/cpu/cpu.c | 3 +- + src/cpu/cpu.h | 3 +- + src/cpu/cpu_loongarch.c | 727 ++++++++++++++++++++++++++++++ + src/cpu/cpu_loongarch.h | 28 ++ + src/cpu/cpu_loongarch_data.h | 40 ++ + src/cpu/meson.build | 1 + + src/cpu_map/index.xml | 5 + + src/cpu_map/loongarch_vendors.xml | 3 + + src/cpu_map/ls_3a5000.xml | 6 + + src/cpu_map/meson.build | 2 + + src/qemu/qemu_capabilities.c | 5 + + src/qemu/qemu_conf.c | 4 +- + src/qemu/qemu_domain.c | 20 +- + src/qemu/qemu_domain.h | 1 + + src/qemu/qemu_domain_address.c | 58 +++ + src/qemu/qemu_validate.c | 3 +- + src/util/virarch.c | 3 + + src/util/virarch.h | 3 + + src/util/virhostcpu.c | 2 +- + src/util/virsysinfo.c | 2 +- + 21 files changed, 913 insertions(+), 7 deletions(-) + 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 + create mode 100644 src/cpu_map/loongarch_vendors.xml + create mode 100644 src/cpu_map/ls_3a5000.xml + +diff --git a/po/POTFILES.in b/po/POTFILES.in +index bf0a3b3529..1153e78265 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -68,6 +68,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/cpu.c b/src/cpu/cpu.c +index 285c7eee44..49527c3688 100644 +--- a/src/cpu/cpu.c ++++ b/src/cpu/cpu.c +@@ -31,7 +31,7 @@ + #include "cpu_arm.h" + #include "capabilities.h" + #include "virstring.h" +- ++#include "cpu_loongarch.h" + + #define VIR_FROM_THIS VIR_FROM_CPU + +@@ -42,6 +42,7 @@ static struct cpuArchDriver *drivers[] = { + &cpuDriverPPC64, + &cpuDriverS390, + &cpuDriverArm, ++ &cpuDriverLoongArch, + }; + + +diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h +index 071b33fe76..ce7aee4757 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; + struct _virCPUData { +@@ -37,6 +37,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..f7b4b85a44 +--- /dev/null ++++ b/src/cpu/cpu_loongarch.c +@@ -0,0 +1,727 @@ ++/* ++ * cpu_loongarch.c: CPU driver for 64-bit LOONGARCH CPUs ++ * ++ * Copyright (C) 2013 Red Hat, Inc. ++ * Copyright (C) IBM Corporation, 2010 ++ * ++ * 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" ++#include "cpu_loongarch.h" ++#include "cpu_loongarch_data.h" ++ ++#define VIR_FROM_THIS VIR_FROM_CPU ++ ++VIR_LOG_INIT("cpu.cpu_loongarch"); ++ ++static const virArch archs[] = { VIR_ARCH_LOONGARCH64 }; ++ ++typedef struct _LoongArch_vendor LoongArch_vendor; ++struct _LoongArch_vendor { ++ char *name; ++}; ++ ++typedef struct _LoongArch_model LoongArch_model; ++struct _LoongArch_model { ++ char *name; ++ LoongArch_vendor *vendor; ++ virCPULoongArchData data; ++}; ++ ++typedef struct _LoongArch_map LoongArch_map; ++struct _LoongArch_map { ++ size_t nvendors; ++ LoongArch_vendor **vendors; ++ size_t nmodels; ++ LoongArch_model **models; ++}; ++ ++static void ++LoongArchDataClear(virCPULoongArchData *data) ++{ ++ if (!data) ++ return; ++ ++ g_free(data->prid); ++} ++ ++static int ++LoongArchDataCopy(virCPULoongArchData *dst, const virCPULoongArchData *src) ++{ ++ size_t i; ++ ++ dst->prid = g_new0(virCPULoongArchPrid, src->len); ++ 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; ++ ++ g_free(vendor); ++} ++ ++static LoongArch_vendor * ++LoongArchVendorFind(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); ++ g_free(model->name); ++ g_free(model); ++} ++ ++static LoongArch_model * ++LoongArchModelCopy(LoongArch_model *model) ++{ ++ LoongArch_model *copy; ++ ++ copy = g_new0(LoongArch_model, 1); ++ copy->name = g_strdup(model->name); ++ ++ if (LoongArchDataCopy(©->data, &model->data) < 0) ++ goto error; ++ ++ copy->vendor = model->vendor; ++ ++ return copy; ++ ++ error: ++ LoongArchModelFree(copy); ++ return NULL; ++} ++ ++static LoongArch_model * ++LoongArchModelFind(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(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, ++ 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]); ++ g_free(map->models); ++ ++ for (i = 0; i < map->nvendors; i++) ++ LoongArchVendorFree(map->vendors[i]); ++ g_free(map->vendors); ++ ++ g_free(map); ++} ++ ++static int ++LoongArchVendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED, ++ const char *name, ++ void *data) ++{ ++ LoongArch_map *map = data; ++ LoongArch_vendor *vendor; ++ int ret = -1; ++ ++ vendor = g_new0(LoongArch_vendor, 1); ++ vendor->name = g_strdup(name); ++ ++ if (LoongArchVendorFind(map, vendor->name)) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("CPU vendor %s already defined"), vendor->name); ++ goto cleanup; ++ } ++ ++ VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor); ++ 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; ++ ++ model = g_new0(LoongArch_model, 1); ++ 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; ++ } ++ ++ model->data.prid = g_new0(virCPULoongArchPrid, n); ++ 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; ++ } ++ ++ VIR_APPEND_ELEMENT(map->models, map->nmodels, model); ++ ret = 0; ++ ++ cleanup: ++ LoongArchModelFree(model); ++ g_free(vendor); ++ g_free(nodes); ++ return ret; ++} ++ ++static LoongArch_map * ++LoongArchLoadMap(void) ++{ ++ LoongArch_map *map; ++ ++ map = g_new0(LoongArch_map, 1); ++ if (cpuMapLoad("loongarch64", LoongArchVendorParse, NULL, LoongArchModelParse, map) < 0) ++ goto error; ++ ++ return map; ++ ++ error: ++ LoongArchMapFree(map); ++ return NULL; ++} ++ ++static virCPUData * ++LoongArchMakeCPUData(virArch arch, ++ virCPULoongArchData *data) ++{ ++ virCPUData *cpuData; ++ ++ cpuData = g_new0(virCPUData, 1); ++ cpuData->arch = arch; ++ ++ if (LoongArchDataCopy(&cpuData->data.loongarch, data) < 0) ++ g_free(cpuData); ++ ++ return cpuData; ++} ++ ++static virCPUCompareResult ++LoongArchCompute(virCPUDef *host, ++ const virCPUDef *other, ++ virCPUData *guestData, ++ char **message) ++{ ++ LoongArch_map *map = NULL; ++ LoongArch_model *host_model = NULL; ++ LoongArch_model *guest_model = NULL; ++ virCPUDef *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(virCPUDef *host, ++ virCPUDef *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); ++ } ++ } ++ g_free(message); ++ ++ return ret; ++} ++ ++static int ++LoongArchDriverDecode(virCPUDef *cpu, ++ const virCPUData *data, ++ virDomainCapsCPUModels *models) ++{ ++ int ret = -1; ++ LoongArch_map *map; ++ 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(virCPUData *data) ++{ ++ if (!data) ++ return; ++ ++ LoongArchDataClear(&data->data.loongarch); ++ g_free(data); ++} ++ ++static int virCPULoongArchGetHostPRID(void) ++{ ++ return 0x14c010; ++} ++ ++static int ++virCPULoongArchGetHost(virCPUDef *cpu, ++ virDomainCapsCPUModels *models) ++{ ++ virCPUData *cpuData = NULL; ++ virCPULoongArchData *data; ++ int ret = -1; ++ ++ if (!(cpuData = virCPUDataNew(archs[0]))) ++ goto cleanup; ++ ++ data = &cpuData->data.loongarch; ++ ++ data->prid = g_new0(virCPULoongArchPrid, 1); ++ 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(virCPUDef *guest, ++ const virCPUDef *host, ++ bool relative) ++{ ++ /* ++ * - 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 ++ */ ++ VIR_DEBUG("host model %s, if relatived %d",host->model, relative); ++ if (guest->mode == VIR_CPU_MODE_CUSTOM) ++ guest->match = VIR_CPU_MATCH_EXACT; ++ ++ return 0; ++} ++ ++static virCPUDef * ++LoongArchDriverBaseline(virCPUDef **cpus, ++ unsigned int ncpus, ++ virDomainCapsCPUModels *models, ++ const char **features, ++ bool migratable) ++{ ++ LoongArch_map *map; ++ LoongArch_model *model; ++ LoongArch_vendor *vendor = NULL; ++ virCPUDef *cpu = NULL; ++ size_t i; ++ if (models && *features) { ++ VIR_DEBUG("migratable %d features %s",migratable, *features); ++ } ++ 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++) { ++ 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 = g_new0(virCPUDef ,1); ++ 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) { ++ *models = g_new0(char *, map->nmodels + 1); ++ 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) { ++ g_strfreev(*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..1fde3b5162 +--- /dev/null ++++ b/src/cpu/cpu_loongarch.h +@@ -0,0 +1,28 @@ ++/* ++ * cpu_loongarch.h: CPU driver for 64-bit LOONGARCH CPUs ++ * ++ * Copyright (C) Copyright (C) IBM Corporation, 2010 ++ * ++ * 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..1a759e7d16 +--- /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) 2012 IBM Corporation. ++ * ++ * 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/cpu/meson.build b/src/cpu/meson.build +index b4ad95e46d..ad2f859fd8 100644 +--- a/src/cpu/meson.build ++++ b/src/cpu/meson.build +@@ -5,6 +5,7 @@ cpu_sources = [ + 'cpu_ppc64.c', + 'cpu_s390.c', + 'cpu_x86.c', ++ 'cpu_loongarch.c', + ] + + cpu_lib = static_library( +diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml +index ffe1fa91e5..d302de396a 100644 +--- a/src/cpu_map/index.xml ++++ b/src/cpu_map/index.xml +@@ -110,4 +110,9 @@ + + + ++ ++ ++ ++ ++ + +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 @@ ++ ++ ++ +diff --git a/src/cpu_map/ls_3a5000.xml b/src/cpu_map/ls_3a5000.xml +new file mode 100644 +index 0000000000..f6fe3386f7 +--- /dev/null ++++ b/src/cpu_map/ls_3a5000.xml +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ ++ +diff --git a/src/cpu_map/meson.build b/src/cpu_map/meson.build +index 013fc62a02..9657c5164e 100644 +--- a/src/cpu_map/meson.build ++++ b/src/cpu_map/meson.build +@@ -77,6 +77,8 @@ cpumap_data = [ + 'x86_vendors.xml', + 'x86_Westmere-IBRS.xml', + 'x86_Westmere.xml', ++ 'loongarch_vendors.xml', ++ 'ls_3a5000.xml', + ] + + install_data(cpumap_data, install_dir: pkgdatadir / 'cpu_map') +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index c4f7db55c8..75668c6451 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -2073,6 +2073,9 @@ bool virQEMUCapsHasPCIMultiBus(const virDomainDef *def) + if (ARCH_IS_X86(def->os.arch)) + return true; + ++ if (STRPREFIX(def->os.machine,"loongson7a")) ++ return true; ++ + /* PPC supports multibus on all machine types which have pci since qemu-2.0.0 */ + if (def->os.arch == VIR_ARCH_PPC || + ARCH_IS_PPC64(def->os.arch)) { +@@ -2690,6 +2693,7 @@ static const char *preferredMachines[] = + + "malta", /* VIR_ARCH_MIPS64 */ + "malta", /* VIR_ARCH_MIPS64EL */ ++ "loongson7a", /* VIR_ARCH_LOONGARCH64 */ + "or1k-sim", /* VIR_ARCH_OR32 */ + NULL, /* VIR_ARCH_PARISC (no QEMU impl) */ + NULL, /* VIR_ARCH_PARISC64 (no QEMU impl) */ +@@ -5115,6 +5119,7 @@ virQEMUCapsInitQMPBasicArch(virQEMUCaps *qemuCaps) + case VIR_ARCH_MIPSEL: + case VIR_ARCH_MIPS64: + case VIR_ARCH_MIPS64EL: ++ case VIR_ARCH_LOONGARCH64: + case VIR_ARCH_OR32: + case VIR_ARCH_PARISC: + case VIR_ARCH_PARISC64: +diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c +index a0b8076d6b..8cd03261ac 100644 +--- a/src/qemu/qemu_conf.c ++++ b/src/qemu/qemu_conf.c +@@ -101,7 +101,9 @@ qemuDriverUnlock(virQEMUDriver *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-kvm/loongarch_bios.bin:/usr/share/qemu-kvm/loongarch_bios.bin" ++ + #endif + + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 40fe9985e6..814d8cb67d 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -3668,6 +3668,10 @@ qemuDomainDefAddDefaultDevices(virQEMUDriver *driver, + addPCIeRoot = virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_GPEX); + break; + ++ case VIR_ARCH_LOONGARCH64: ++ addPCIeRoot = true; ++ break; ++ + case VIR_ARCH_PPC64: + case VIR_ARCH_PPC64LE: + addPCIRoot = true; +@@ -5065,6 +5069,11 @@ qemuDomainControllerDefPostParse(virDomainControllerDef *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 */ +@@ -8324,6 +8333,13 @@ qemuDomainDefCheckABIStability(virQEMUDriver *driver, + } + + ++bool ++qemuDomainIsLoongson(const virDomainDef *def) ++{ ++ return (STRPREFIX(def->os.machine,"loongson3a") || STRPREFIX(def->os.machine,"loongson7a")); ++} ++ ++ + bool + qemuDomainCheckABIStability(virQEMUDriver *driver, + virDomainObj *vm, +@@ -8664,7 +8680,9 @@ qemuDomainMachineHasBuiltinIDE(const char *machine, + return qemuDomainMachineIsI440FX(machine, arch) || + STREQ(machine, "malta") || + STREQ(machine, "sun4u") || +- STREQ(machine, "g3beige"); ++ STREQ(machine, "g3beige") || ++ STREQ(machine, "loongson3a") || ++ STREQ(machine, "loongson7a"); + } + + +diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h +index e5046367e3..57f1f97348 100644 +--- a/src/qemu/qemu_domain.h ++++ b/src/qemu/qemu_domain.h +@@ -770,6 +770,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 18fc34d049..c3fac1c33b 100644 +--- a/src/qemu/qemu_domain_address.c ++++ b/src/qemu/qemu_domain_address.c +@@ -2026,6 +2026,59 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDef *def, + } + + ++static int ++qemuDomainValidateDevicePCISlotsLoongson(virDomainDef *def, ++ virDomainPCIAddressSet *addrs) ++{ ++ int ret = -1; ++ virPCIDeviceAddress tmp_addr; ++ char *addrStr = NULL; ++ virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_AUTOASSIGN ++ | 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) ++ goto cleanup; ++ } ++ ++ 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 */ ++ virDomainVideoDef *primaryVideo = def->videos[0]; ++ ++ if (virDeviceInfoPCIAddressIsWanted(&primaryVideo->info)) { ++ memset(&tmp_addr, 0, sizeof(tmp_addr)); ++ tmp_addr.slot = 2; ++ ++ if (!(addrStr = virPCIDeviceAddressAsString(&tmp_addr))) ++ goto cleanup; ++ if (!virDomainPCIAddressValidate(addrs, &tmp_addr, ++ addrStr, flags, true)) ++ goto cleanup; ++ ++ if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { ++ if (qemuDomainPCIAddressReserveNextAddr(addrs, ++ &primaryVideo->info) < 0) ++ goto cleanup; ++ } else { ++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) ++ goto cleanup; ++ primaryVideo->info.addr.pci = tmp_addr; ++ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; ++ } ++ } ++ } ++ ret = 0; ++ cleanup: ++ VIR_FREE(addrStr); ++ return ret; ++} ++ ++ + static int + qemuDomainValidateDevicePCISlotsChipsets(virDomainDef *def, + virDomainPCIAddressSet *addrs) +@@ -2040,6 +2093,11 @@ qemuDomainValidateDevicePCISlotsChipsets(virDomainDef *def, + return -1; + } + ++ if (qemuDomainIsLoongson(def) && ++ qemuDomainValidateDevicePCISlotsLoongson(def, addrs) < 0) { ++ return -1; ++ } ++ + return 0; + } + +diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c +index 7bc14293d6..7d01d31aaf 100644 +--- a/src/qemu/qemu_validate.c ++++ b/src/qemu/qemu_validate.c +@@ -186,7 +186,8 @@ qemuValidateDomainDefFeatures(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'"), +diff --git a/src/util/virarch.c b/src/util/virarch.c +index 2134dd6a9d..9f40a7110c 100644 +--- a/src/util/virarch.c ++++ b/src/util/virarch.c +@@ -59,6 +59,7 @@ static const struct virArchData { + + { "mips64", 64, VIR_ARCH_BIG_ENDIAN }, + { "mips64el", 64, VIR_ARCH_LITTLE_ENDIAN }, ++ { "loongarch64", 64, VIR_ARCH_LITTLE_ENDIAN }, + { "openrisc", 32, VIR_ARCH_BIG_ENDIAN }, + { "parisc", 32, VIR_ARCH_BIG_ENDIAN }, + { "parisc64", 64, VIR_ARCH_BIG_ENDIAN }, +@@ -222,6 +223,8 @@ virArch virArchFromHost(void) + arch = VIR_ARCH_X86_64; + } else if (STREQ(ut.machine, "arm64")) { + arch = VIR_ARCH_AARCH64; ++ } 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/virarch.h b/src/util/virarch.h +index 528f84f8a5..7d396f2fff 100644 +--- a/src/util/virarch.h ++++ b/src/util/virarch.h +@@ -44,6 +44,7 @@ typedef enum { + + VIR_ARCH_MIPS64, /* MIPS 64 BE https://en.wikipedia.org/wiki/MIPS_architecture */ + VIR_ARCH_MIPS64EL, /* MIPS 64 LE https://en.wikipedia.org/wiki/MIPS_architecture */ ++ VIR_ARCH_LOONGARCH64, + VIR_ARCH_OR32, /* OpenRisc 32 BE https://en.wikipedia.org/wiki/OpenRISC#QEMU_support */ + VIR_ARCH_PARISC, /* PA-Risc 32 BE https://en.wikipedia.org/wiki/PA-RISC */ + VIR_ARCH_PARISC64, /* PA-Risc 64 BE https://en.wikipedia.org/wiki/PA-RISC */ +@@ -98,6 +99,8 @@ typedef enum { + #define ARCH_IS_MIPS64(arch) ((arch) == VIR_ARCH_MIPS64 ||\ + (arch) == VIR_ARCH_MIPS64EL) + ++#define ARCH_IS_LOONGARCH(arch) ((arch) == VIR_ARCH_LOONGARCH64) ++ + typedef enum { + VIR_ARCH_LITTLE_ENDIAN, + VIR_ARCH_BIG_ENDIAN, +diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c +index 35f41daef2..137796ea07 100644 +--- a/src/util/virhostcpu.c ++++ b/src/util/virhostcpu.c +@@ -546,7 +546,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 af9e03c5ac..9577cf1910 100644 +--- a/src/util/virsysinfo.c ++++ b/src/util/virsysinfo.c +@@ -1247,7 +1247,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(); +-- +2.27.0 + diff --git a/libvirt.spec b/libvirt.spec index 44ee06f..7205bc9 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -3,19 +3,20 @@ # This spec file assumes you are building on a Fedora or RHEL version # that's still supported by the vendor. It may work on other distros # or versions, but no effort will be made to ensure that going forward. +%define anolis_release .0.1 %define min_rhel 8 %define min_fedora 33 -%define arches_qemu_kvm %{ix86} x86_64 %{power64} %{arm} aarch64 s390x +%define arches_qemu_kvm %{ix86} x86_64 %{power64} %{arm} aarch64 s390x loongarch64 %if 0%{?rhel} %if 0%{?rhel} > 8 - %define arches_qemu_kvm x86_64 aarch64 s390x + %define arches_qemu_kvm x86_64 aarch64 s390x loongarch64 %else - %define arches_qemu_kvm x86_64 %{power64} aarch64 s390x + %define arches_qemu_kvm x86_64 %{power64} aarch64 s390x loongarch64 %endif %endif -%define arches_64bit x86_64 %{power64} aarch64 s390x riscv64 +%define arches_64bit x86_64 %{power64} aarch64 s390x riscv64 loongarch64 %define arches_x86 %{ix86} x86_64 %define arches_systemtap_64bit %{arches_64bit} @@ -23,9 +24,9 @@ %define arches_xen %{arches_x86} aarch64 %define arches_vbox %{arches_x86} %define arches_ceph %{arches_64bit} -%define arches_zfs %{arches_x86} %{power64} %{arm} -%define arches_numactl %{arches_x86} %{power64} aarch64 s390x -%define arches_numad %{arches_x86} %{power64} aarch64 +%define arches_zfs %{arches_x86} %{power64} %{arm} loongarch64 +%define arches_numactl %{arches_x86} %{power64} aarch64 s390x loongarch64 +%define arches_numad %{arches_x86} %{power64} aarch64 loongarch64 # The hypervisor drivers that run in libvirtd %define with_qemu 0%{!?_without_qemu:1} @@ -210,7 +211,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.0.0 -Release: 10.4%{?dist}%{?extra_release} +Release: 10.4%{anolis_release}%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -279,6 +280,7 @@ Patch56: libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch Patch57: libvirt-tools-Fix-install_mode-for-some-scripts.patch Patch58: libvirt-vircpi-Add-PCIe-5.0-and-6.0-link-speeds.patch Patch59: libvirt-conf-Make-VIR_DOMAIN_NET_TYPE_ETHERNET-not-share-host-view.patch +Patch1000: libvirt-Add-loongarch-support.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2152,6 +2154,9 @@ exit 0 %changelog +* Thu Apr 06 2023 zhaotianrui - 8.0.0-10.4.0.1 +- Add loongarch support + * Thu Mar 2 2023 Jiri Denemark - 8.0.0-10.4.el8 - conf: Make VIR_DOMAIN_NET_TYPE_ETHERNET not share 'host view' (rhbz#2173976) -- Gitee