computing-offload/generic_vdpa/libvirt/Add-loongarch-cpu-support.patch
jiangdongxu 79c4324644 add generic_vdpa basecode
Change-Id: I2d302dda68298877c65c99147f5bf22186a59aac
2024-09-19 17:19:46 +08:00

995 lines
26 KiB
Diff

From c0b26612cf12d5f0594a9dfa5bd97fcf7acfe9da Mon Sep 17 00:00:00 2001
From: zhaotianrui <zhaotianrui@loongson.cn>
Date: Wed, 11 Jan 2023 10:53:08 -0500
Subject: [PATCH 1/4] Add loongarch cpu support
Add loongarch cpu support: Define new cpu type 'loongarch64'
and implement it's driver functions.
Signed-off-by: zhaotianrui <zhaotianrui@loongson.cn>
---
docs/schemas/basictypes.rng | 1 +
po/POTFILES.in | 1 +
src/cpu/Makefile.inc.am | 3 +
src/cpu/cpu.c | 2 +
src/cpu/cpu.h | 3 +-
src/cpu/cpu_loongarch.c | 739 +++++++++++++++++++++++++++++++++++
src/cpu/cpu_loongarch.h | 28 ++
src/cpu/cpu_loongarch_data.h | 40 ++
src/qemu/qemu_capabilities.c | 1 +
src/qemu/qemu_domain.c | 4 +
src/util/virarch.c | 1 +
src/util/virarch.h | 3 +
12 files changed, 825 insertions(+), 1 deletion(-)
create mode 100644 src/cpu/cpu_loongarch.c
create mode 100644 src/cpu/cpu_loongarch.h
create mode 100644 src/cpu/cpu_loongarch_data.h
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 81465273c8..34d285db48 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -444,6 +444,7 @@
<value>x86_64</value>
<value>xtensa</value>
<value>xtensaeb</value>
+ <value>loongarch64</value>
</choice>
</define>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 197ff2f3d3..24dc8087d6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -60,6 +60,7 @@
@SRCDIR@/src/cpu/cpu_arm.c
@SRCDIR@/src/cpu/cpu_map.c
@SRCDIR@/src/cpu/cpu_ppc64.c
+@SRCDIR@/src/cpu/cpu_loongarch.c
@SRCDIR@/src/cpu/cpu_s390.c
@SRCDIR@/src/cpu/cpu_x86.c
@SRCDIR@/src/datatypes.c
diff --git a/src/cpu/Makefile.inc.am b/src/cpu/Makefile.inc.am
index 1ee1290c2d..e2219bbc1c 100644
--- a/src/cpu/Makefile.inc.am
+++ b/src/cpu/Makefile.inc.am
@@ -15,6 +15,9 @@ CPU_SOURCES = \
cpu/cpu_ppc64.h \
cpu/cpu_ppc64.c \
cpu/cpu_ppc64_data.h \
+ cpu/cpu_loongarch.h \
+ cpu/cpu_loongarch.c \
+ cpu/cpu_loongarch_data.h \
cpu/cpu_map.h \
cpu/cpu_map.c \
$(NULL)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 89c06aceeb..df78a0d33f 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -30,6 +30,7 @@
#include "cpu_s390.h"
#include "cpu_arm.h"
#include "cpu_sw64.h"
+#include "cpu_loongarch.h"
#include "capabilities.h"
#include "virstring.h"
@@ -44,6 +45,7 @@ static struct cpuArchDriver *drivers[] = {
&cpuDriverS390,
&cpuDriverArm,
&cpuDriverSW64,
+ &cpuDriverLoongArch,
};
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index ec22a183a1..307c85fb61 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -28,7 +28,7 @@
#include "cpu_x86_data.h"
#include "cpu_ppc64_data.h"
#include "cpu_arm_data.h"
-
+#include "cpu_loongarch_data.h"
typedef struct _virCPUData virCPUData;
typedef virCPUData *virCPUDataPtr;
@@ -38,6 +38,7 @@ struct _virCPUData {
virCPUx86Data x86;
virCPUppc64Data ppc64;
virCPUarmData arm;
+ virCPULoongArchData loongarch;
/* generic driver needs no data */
} data;
};
diff --git a/src/cpu/cpu_loongarch.c b/src/cpu/cpu_loongarch.c
new file mode 100644
index 0000000000..953316bf78
--- /dev/null
+++ b/src/cpu/cpu_loongarch.c
@@ -0,0 +1,739 @@
+/*
+ * cpu_loongarch.c: CPU driver for 64-bit LOONGARCH CPUs
+ *
+ * Copyright (C) 2023 Loongson Technology.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "virlog.h"
+#include "viralloc.h"
+#include "cpu.h"
+#include "virstring.h"
+#include "cpu_map.h"
+#include "virbuffer.h"
+
+#define VIR_FROM_THIS VIR_FROM_CPU
+
+VIR_LOG_INIT("cpu.cpu_loongarch");
+
+static const virArch archs[] = { VIR_ARCH_LOONGARCH64 };
+
+typedef struct {
+ char *name;
+} LoongArch_vendor;
+
+typedef struct {
+ char *name;
+ const LoongArch_vendor *vendor;
+ virCPULoongArchData data;
+} LoongArch_model;
+
+typedef struct {
+ size_t nvendors;
+ LoongArch_vendor **vendors;
+ size_t nmodels;
+ LoongArch_model **models;
+} LoongArch_map;
+
+static void
+LoongArchDataClear(virCPULoongArchData *data)
+{
+ if (!data)
+ return;
+
+ VIR_FREE(data->prid);
+}
+
+static int
+LoongArchDataCopy(virCPULoongArchData *dst, const virCPULoongArchData *src)
+{
+ size_t i;
+
+ if (VIR_ALLOC_N(dst->prid, src->len) < 0)
+ return -1;
+
+ dst->len = src->len;
+
+ for (i = 0; i < src->len; i++) {
+ dst->prid[i].value = src->prid[i].value;
+ dst->prid[i].mask = src->prid[i].mask;
+ }
+
+ return 0;
+}
+
+static void
+LoongArchVendorFree(LoongArch_vendor *vendor)
+{
+ if (!vendor)
+ return;
+
+ VIR_FREE(vendor->name);
+ VIR_FREE(vendor);
+}
+
+static LoongArch_vendor *
+LoongArchVendorFind(const LoongArch_map *map,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < map->nvendors; i++) {
+ if (STREQ(map->vendors[i]->name, name))
+ return map->vendors[i];
+ }
+
+ return NULL;
+}
+
+static void
+LoongArchModelFree(LoongArch_model *model)
+{
+ if (!model)
+ return;
+
+ LoongArchDataClear(&model->data);
+ VIR_FREE(model->name);
+ VIR_FREE(model);
+}
+
+static LoongArch_model *
+LoongArchModelCopy(const LoongArch_model *model)
+{
+ LoongArch_model *copy;
+
+ if (VIR_ALLOC(copy) < 0)
+ goto cleanup;
+
+ copy->name = g_strdup(model->name);
+
+ if (LoongArchDataCopy(&copy->data, &model->data) < 0)
+ goto cleanup;
+
+ copy->vendor = model->vendor;
+
+ return copy;
+
+ cleanup:
+ LoongArchModelFree(copy);
+ return NULL;
+}
+
+static LoongArch_model *
+LoongArchModelFind(const LoongArch_map *map,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < map->nmodels; i++) {
+ if (STREQ(map->models[i]->name, name))
+ return map->models[i];
+ }
+
+ return NULL;
+}
+
+static LoongArch_model *
+LoongArchModelFindPrid(const LoongArch_map *map,
+ uint32_t prid)
+{
+ size_t i;
+ size_t j;
+
+ for (i = 0; i < map->nmodels; i++) {
+ LoongArch_model *model = map->models[i];
+ for (j = 0; j < model->data.len; j++) {
+ if ((prid & model->data.prid[j].mask) == model->data.prid[j].value)
+ return model;
+ }
+ }
+
+ return NULL;
+}
+
+static LoongArch_model *
+LoongArchModelFromCPU(const virCPUDef *cpu,
+ const LoongArch_map *map)
+{
+ LoongArch_model *model;
+
+ if (!cpu->model) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("no CPU model specified"));
+ return NULL;
+ }
+
+ if (!(model = LoongArchModelFind(map, cpu->model))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown CPU model %s"), cpu->model);
+ return NULL;
+ }
+
+ return LoongArchModelCopy(model);
+}
+
+static void
+LoongArchMapFree(LoongArch_map *map)
+{
+ size_t i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < map->nmodels; i++)
+ LoongArchModelFree(map->models[i]);
+ VIR_FREE(map->models);
+
+ for (i = 0; i < map->nvendors; i++)
+ LoongArchVendorFree(map->vendors[i]);
+ VIR_FREE(map->vendors);
+
+ VIR_FREE(map);
+}
+
+static int
+LoongArchVendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
+ const char *name,
+ void *data)
+{
+ LoongArch_map *map = data;
+ LoongArch_vendor *vendor;
+ int ret = -1;
+
+ if (VIR_ALLOC(vendor) < 0)
+ return ret;
+ vendor->name = g_strdup(name);
+
+ if (LoongArchVendorFind(map, vendor->name)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("CPU vendor %s already defined"), vendor->name);
+ goto cleanup;
+ }
+
+ if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ LoongArchVendorFree(vendor);
+ return ret;
+}
+
+static int
+LoongArchModelParse(xmlXPathContextPtr ctxt,
+ const char *name,
+ void *data)
+{
+ LoongArch_map *map = data;
+ LoongArch_model *model;
+ xmlNodePtr *nodes = NULL;
+ char *vendor = NULL;
+ unsigned long prid;
+ size_t i;
+ int n;
+ int ret = -1;
+
+ if (VIR_ALLOC(model) < 0)
+ goto cleanup;
+
+ model->name = g_strdup(name);
+
+ if (LoongArchModelFind(map, model->name)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("CPU model %s already defined"), model->name);
+ goto cleanup;
+ }
+
+ if (virXPathBoolean("boolean(./vendor)", ctxt)) {
+ vendor = virXPathString("string(./vendor/@name)", ctxt);
+ if (!vendor) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid vendor element in CPU model %s"),
+ model->name);
+ goto cleanup;
+ }
+
+ if (!(model->vendor = LoongArchVendorFind(map, vendor))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown vendor %s referenced by CPU model %s"),
+ vendor, model->name);
+ goto cleanup;
+ }
+ }
+
+ if ((n = virXPathNodeSet("./prid", ctxt, &nodes)) <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing Prid information for CPU model %s"),
+ model->name);
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(model->data.prid, n) < 0)
+ goto cleanup;
+
+ model->data.len = n;
+
+ for (i = 0; i < n; i++) {
+ ctxt->node = nodes[i];
+
+ if (virXPathULongHex("string(./@value)", ctxt, &prid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing or invalid Prid value in CPU model %s"),
+ model->name);
+ goto cleanup;
+ }
+ model->data.prid[i].value = prid;
+
+ if (virXPathULongHex("string(./@mask)", ctxt, &prid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing or invalid PVR mask in CPU model %s"),
+ model->name);
+ goto cleanup;
+ }
+ model->data.prid[i].mask = prid;
+ }
+
+ if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ LoongArchModelFree(model);
+ VIR_FREE(vendor);
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static LoongArch_map *
+LoongArchLoadMap(void)
+{
+ LoongArch_map *map;
+
+ if (VIR_ALLOC(map) < 0)
+ goto cleanup;
+
+ if (cpuMapLoad("loongarch64", LoongArchVendorParse, NULL, LoongArchModelParse, map) < 0)
+ goto cleanup;
+
+ return map;
+
+ cleanup:
+ LoongArchMapFree(map);
+ return NULL;
+}
+
+static virCPUDataPtr
+LoongArchMakeCPUData(virArch arch,
+ virCPULoongArchData *data)
+{
+ virCPUDataPtr cpuData;
+
+ if (VIR_ALLOC(cpuData) < 0)
+ return NULL;
+
+ cpuData->arch = arch;
+
+ if (LoongArchDataCopy(&cpuData->data.loongarch, data) < 0)
+ VIR_FREE(cpuData);
+
+ return cpuData;
+}
+
+static virCPUCompareResult
+LoongArchCompute(virCPUDefPtr host,
+ const virCPUDef *other,
+ virCPUDataPtr *guestData,
+ char **message)
+{
+ LoongArch_map *map = NULL;
+ LoongArch_model *host_model = NULL;
+ LoongArch_model *guest_model = NULL;
+ virCPUDefPtr cpu = NULL;
+ virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
+ virArch arch;
+ size_t i;
+
+ /* Ensure existing configurations are handled correctly */
+ if (!(cpu = virCPUDefCopy(other)))
+ goto cleanup;
+
+ if (cpu->arch != VIR_ARCH_NONE) {
+ bool found = false;
+
+ for (i = 0; i < G_N_ELEMENTS(archs); i++) {
+ if (archs[i] == cpu->arch) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ VIR_DEBUG("CPU arch %s does not match host arch",
+ virArchToString(cpu->arch));
+ if (message) {
+ *message = g_strdup_printf(_("CPU arch %s does not match host arch"),
+ virArchToString(cpu->arch));
+ }
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+ arch = cpu->arch;
+ } else {
+ arch = host->arch;
+ }
+
+ if (cpu->vendor &&
+ (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
+ VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
+ cpu->vendor);
+ if (message) {
+ *message = g_strdup_printf(_("host CPU vendor does not match required "
+ "CPU vendor %s"), cpu->vendor);
+ }
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+
+ if (!(map = LoongArchLoadMap()))
+ goto cleanup;
+
+ /* Host CPU information */
+ if (!(host_model = LoongArchModelFromCPU(host, map)))
+ goto cleanup;
+
+ if (cpu->type == VIR_CPU_TYPE_GUEST) {
+ /* Guest CPU information */
+ switch (cpu->mode) {
+ case VIR_CPU_MODE_HOST_MODEL:
+ case VIR_CPU_MODE_HOST_PASSTHROUGH:
+ /* host-model and host-passthrough:
+ * the guest CPU is the same as the host */
+ guest_model = LoongArchModelCopy(host_model);
+ break;
+
+ case VIR_CPU_MODE_CUSTOM:
+ /* custom:
+ * look up guest CPU information */
+ guest_model = LoongArchModelFromCPU(cpu, map);
+ break;
+ }
+ } else {
+ /* Other host CPU information */
+ guest_model = LoongArchModelFromCPU(cpu, map);
+ }
+
+ if (!guest_model)
+ goto cleanup;
+
+ if (STRNEQ(guest_model->name, host_model->name)) {
+ VIR_DEBUG("host CPU model does not match required CPU model %s",
+ guest_model->name);
+ if (message) {
+ *message = g_strdup_printf(_("host CPU model does not match required "
+ "CPU model %s"),guest_model->name);
+ }
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+
+ if (guestData)
+ if (!(*guestData = LoongArchMakeCPUData(arch, &guest_model->data)))
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_IDENTICAL;
+
+ cleanup:
+ virCPUDefFree(cpu);
+ LoongArchMapFree(map);
+ LoongArchModelFree(host_model);
+ LoongArchModelFree(guest_model);
+ return ret;
+}
+
+static virCPUCompareResult
+virCPULoongArchCompare(virCPUDefPtr host,
+ virCPUDefPtr cpu,
+ bool failIncompatible)
+{
+ virCPUCompareResult ret;
+ char *message = NULL;
+
+ if (!host || !host->model) {
+ if (failIncompatible) {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
+ _("unknown host CPU"));
+ } else {
+ VIR_WARN("unknown host CPU");
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ }
+ return -1;
+ }
+
+ ret = LoongArchCompute(host, cpu, NULL, &message);
+
+ if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
+ ret = VIR_CPU_COMPARE_ERROR;
+ if (message) {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
+ } else {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
+ }
+ }
+ VIR_FREE(message);
+
+ return ret;
+}
+
+static int
+LoongArchDriverDecode(virCPUDefPtr cpu,
+ const virCPUData *data,
+ virDomainCapsCPUModelsPtr models)
+{
+ int ret = -1;
+ LoongArch_map *map;
+ const LoongArch_model *model;
+
+ if (!data || !(map = LoongArchLoadMap()))
+ return -1;
+
+ if (!(model = LoongArchModelFindPrid(map, data->data.loongarch.prid[0].value))) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Cannot find CPU model with Prid 0x%08x"),
+ data->data.loongarch.prid[0].value);
+ goto cleanup;
+ }
+
+ if (!virCPUModelIsAllowed(model->name, models)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU model %s is not supported by hypervisor"),
+ model->name);
+ goto cleanup;
+ }
+
+ cpu->model = g_strdup(model->name);
+ if (model->vendor) {
+ cpu->vendor = g_strdup(model->vendor->name);
+ }
+ ret = 0;
+
+ cleanup:
+ LoongArchMapFree(map);
+
+ return ret;
+}
+
+static void
+virCPULoongArchDataFree(virCPUDataPtr data)
+{
+ if (!data)
+ return;
+
+ LoongArchDataClear(&data->data.loongarch);
+ VIR_FREE(data);
+}
+
+static int
+virCPULoongArchGetHostPRID(void)
+{
+ return 0x14c010;
+}
+
+static int
+virCPULoongArchGetHost(virCPUDefPtr cpu,
+ virDomainCapsCPUModelsPtr models)
+{
+ virCPUDataPtr cpuData = NULL;
+ virCPULoongArchData *data;
+ int ret = -1;
+
+ if (!(cpuData = virCPUDataNew(archs[0])))
+ goto cleanup;
+
+ data = &cpuData->data.loongarch;
+ if (VIR_ALLOC(data->prid) < 0)
+ goto cleanup;
+
+
+ data->len = 1;
+
+ data->prid[0].value = virCPULoongArchGetHostPRID();
+ data->prid[0].mask = 0xffff00ul;
+
+ ret = LoongArchDriverDecode(cpu, cpuData, models);
+
+ cleanup:
+ virCPULoongArchDataFree(cpuData);
+ return ret;
+}
+
+
+static int
+virCPULoongArchUpdate(virCPUDefPtr guest,
+ const virCPUDef *host ATTRIBUTE_UNUSED)
+{
+ /*
+ * - host-passthrough doesn't even get here
+ * - host-model is used for host CPU running in a compatibility mode and
+ * it needs to remain unchanged
+ * - custom doesn't support any optional features, there's nothing to
+ * update
+ */
+
+ if (guest->mode == VIR_CPU_MODE_CUSTOM)
+ guest->match = VIR_CPU_MATCH_EXACT;
+
+ return 0;
+}
+
+static virCPUDefPtr
+LoongArchDriverBaseline(virCPUDefPtr *cpus,
+ unsigned int ncpus,
+ virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED,
+ const char **features ATTRIBUTE_UNUSED,
+ bool migratable ATTRIBUTE_UNUSED)
+{
+ LoongArch_map *map;
+ const LoongArch_model *model;
+ const LoongArch_vendor *vendor = NULL;
+ virCPUDefPtr cpu = NULL;
+ size_t i;
+
+ if (!(map = LoongArchLoadMap()))
+ goto error;
+
+ if (!(model = LoongArchModelFind(map, cpus[0]->model))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown CPU model %s"), cpus[0]->model);
+ goto error;
+ }
+
+ for (i = 0; i < ncpus; i++) {
+ const LoongArch_vendor *vnd;
+
+ if (STRNEQ(cpus[i]->model, model->name)) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("CPUs are incompatible"));
+ goto error;
+ }
+
+ if (!cpus[i]->vendor)
+ continue;
+
+ if (!(vnd = LoongArchVendorFind(map, cpus[i]->vendor))) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), cpus[i]->vendor);
+ goto error;
+ }
+
+ if (model->vendor) {
+ if (model->vendor != vnd) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("CPU vendor %s of model %s differs from "
+ "vendor %s"),
+ model->vendor->name, model->name,
+ vnd->name);
+ goto error;
+ }
+ } else if (vendor) {
+ if (vendor != vnd) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("CPU vendors do not match"));
+ goto error;
+ }
+ } else {
+ vendor = vnd;
+ }
+ }
+
+ cpu = virCPUDefNew();
+ cpu->model = g_strdup(model->name);
+ if (vendor) {
+ cpu->vendor = g_strdup(vendor->name);
+ }
+ cpu->type = VIR_CPU_TYPE_GUEST;
+ cpu->match = VIR_CPU_MATCH_EXACT;
+ cpu->fallback = VIR_CPU_FALLBACK_FORBID;
+
+ cleanup:
+ LoongArchMapFree(map);
+ return cpu;
+
+ error:
+ virCPUDefFree(cpu);
+ cpu = NULL;
+ goto cleanup;
+}
+
+static int
+virCPULoongArchDriverGetModels(char ***models)
+{
+ LoongArch_map *map;
+ size_t i;
+ int ret = -1;
+
+ if (!(map = LoongArchLoadMap())) {
+ goto error;
+ }
+
+ if (models) {
+ if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
+ goto error;
+
+ for (i = 0; i < map->nmodels; i++) {
+ (*models)[i] = g_strdup(map->models[i]->name);
+ }
+ }
+
+ ret = map->nmodels;
+
+ cleanup:
+ LoongArchMapFree(map);
+ return ret;
+
+ error:
+ if (models) {
+ virStringListFree(*models);
+ *models = NULL;
+ }
+ goto cleanup;
+}
+
+struct cpuArchDriver cpuDriverLoongArch = {
+ .name = "LoongArch",
+ .arch = archs,
+ .narch = G_N_ELEMENTS(archs),
+ .compare = virCPULoongArchCompare,
+ .decode = LoongArchDriverDecode,
+ .encode = NULL,
+ .dataFree = virCPULoongArchDataFree,
+ .getHost = virCPULoongArchGetHost,
+ .baseline = LoongArchDriverBaseline,
+ .update = virCPULoongArchUpdate,
+ .getModels = virCPULoongArchDriverGetModels,
+};
diff --git a/src/cpu/cpu_loongarch.h b/src/cpu/cpu_loongarch.h
new file mode 100644
index 0000000000..304af628d4
--- /dev/null
+++ b/src/cpu/cpu_loongarch.h
@@ -0,0 +1,28 @@
+/*
+ * cpu_loongarch.h: CPU driver for 64-bit LOONGARCH CPUs
+ *
+ * Copyright (C) 2023 Loongson Technology.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_CPU_LOONGARCH_H__
+# define __VIR_CPU_LOONGARCH_H__
+
+# include "cpu.h"
+
+extern struct cpuArchDriver cpuDriverLoongArch;
+
+#endif /* __VIR_CPU_LOONGARCH_H__ */
diff --git a/src/cpu/cpu_loongarch_data.h b/src/cpu/cpu_loongarch_data.h
new file mode 100644
index 0000000000..c640a0c6b4
--- /dev/null
+++ b/src/cpu/cpu_loongarch_data.h
@@ -0,0 +1,40 @@
+/*
+ * cpu_loongarch_data.h: 64-bit LOONGARCH CPU specific data
+ *
+ * Copyright (C) 2023 Loongson Technology.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_CPU_LOONGARCH_DATA_H__
+# define __VIR_CPU_LOONGARCH_DATA_H__
+
+# include <stdint.h>
+
+typedef struct _virCPULoongArchPrid virCPULoongArchPrid;
+struct _virCPULoongArchPrid {
+ uint32_t value;
+ uint32_t mask;
+};
+
+# define VIR_CPU_LOONGARCH_DATA_INIT { 0 }
+
+typedef struct _virCPULoongArchData virCPULoongArchData;
+struct _virCPULoongArchData {
+ size_t len;
+ virCPULoongArchPrid *prid;
+};
+
+#endif /* __VIR_CPU_MIPS64_DATA_H__ */
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 2e9f2025ba..0c3eb148b2 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -2692,6 +2692,7 @@ static const char *preferredMachines[] =
"sim", /* VIR_ARCH_XTENSAEB */
"core3", /* VIR_ARCH_SW_64 */
+ "loongson7a", /* VIR_ARCH_LOONGARCH64 */
};
G_STATIC_ASSERT(G_N_ELEMENTS(preferredMachines) == VIR_ARCH_LAST);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 70835e4efd..37dac3694b 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -4361,6 +4361,10 @@ qemuDomainDefAddDefaultDevices(virDomainDefPtr def,
addPCIeRoot = true;
break;
+ case VIR_ARCH_LOONGARCH64:
+ addPCIeRoot = true;
+ break;
+
case VIR_ARCH_ARMV7B:
case VIR_ARCH_CRIS:
case VIR_ARCH_ITANIUM:
diff --git a/src/util/virarch.c b/src/util/virarch.c
index 653136cc73..decdbdd7ac 100644
--- a/src/util/virarch.c
+++ b/src/util/virarch.c
@@ -85,6 +85,7 @@ static const struct virArchData {
{ "xtensaeb", 32, VIR_ARCH_BIG_ENDIAN },
{ "sw_64", 64, VIR_ARCH_LITTLE_ENDIAN},
+ { "loongarch64", 64, VIR_ARCH_LITTLE_ENDIAN },
};
G_STATIC_ASSERT(G_N_ELEMENTS(virArchData) == VIR_ARCH_LAST);
diff --git a/src/util/virarch.h b/src/util/virarch.h
index 5eb146eb1b..a7834ae799 100644
--- a/src/util/virarch.h
+++ b/src/util/virarch.h
@@ -70,6 +70,7 @@ typedef enum {
VIR_ARCH_XTENSAEB, /* XTensa 32 BE http://en.wikipedia.org/wiki/Xtensa#Processor_Cores */
VIR_ARCH_SW_64, /* SW64 64 LE XHB*/
+ VIR_ARCH_LOONGARCH64, /* LoongArch 64 LE */
VIR_ARCH_LAST,
} virArch;
@@ -99,6 +100,8 @@ typedef enum {
#define ARCH_IS_SW64(arch) ((arch) == VIR_ARCH_SW_64)
+#define ARCH_IS_LOONGARCH(arch) ((arch) == VIR_ARCH_LOONGARCH64)
+
typedef enum {
VIR_ARCH_LITTLE_ENDIAN,
VIR_ARCH_BIG_ENDIAN,
--
2.25.1