From: lixianglai <lixianglai@xxxxxxxxxxx> Add loongarch cpu support, Define new cpu type 'loongarch64' and implement it's driver functions. Signed-off-by: lixianglai <lixianglai@xxxxxxxxxxx> --- po/POTFILES | 1 + src/conf/schemas/basictypes.rng | 1 + src/cpu/cpu.c | 2 + src/cpu/cpu.h | 2 + src/cpu/cpu_loongarch.c | 742 ++++++++++++++++++++++++++++++++ src/cpu/cpu_loongarch.h | 25 ++ src/cpu/cpu_loongarch_data.h | 37 ++ src/cpu/meson.build | 1 + src/qemu/qemu_capabilities.c | 1 + src/qemu/qemu_domain.c | 4 + src/util/virarch.c | 2 + src/util/virarch.h | 4 + 12 files changed, 822 insertions(+) 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/po/POTFILES b/po/POTFILES index 3a51aea5cb..c0e66d563e 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -70,6 +70,7 @@ src/cpu/cpu.c src/cpu/cpu_arm.c src/cpu/cpu_map.c src/cpu/cpu_ppc64.c +src/cpu/cpu_loongarch.c src/cpu/cpu_riscv64.c src/cpu/cpu_s390.c src/cpu/cpu_x86.c diff --git a/src/conf/schemas/basictypes.rng b/src/conf/schemas/basictypes.rng index 26eb538077..04f032b3ab 100644 --- a/src/conf/schemas/basictypes.rng +++ b/src/conf/schemas/basictypes.rng @@ -470,6 +470,7 @@ <value>x86_64</value> <value>xtensa</value> <value>xtensaeb</value> + <value>loongarch64</value> </choice> </define> diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index bc43aa4e93..1e7c879ca5 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -27,6 +27,7 @@ #include "cpu_ppc64.h" #include "cpu_s390.h" #include "cpu_arm.h" +#include "cpu_loongarch.h" #include "cpu_riscv64.h" #include "capabilities.h" @@ -41,6 +42,7 @@ static struct cpuArchDriver *drivers[] = { &cpuDriverS390, &cpuDriverArm, &cpuDriverRiscv64, + &cpuDriverLoongArch, }; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index a4cdb37f03..9ec0a109b8 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -27,6 +27,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; @@ -36,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..0f96535606 --- /dev/null +++ b/src/cpu/cpu_loongarch.c @@ -0,0 +1,742 @@ +/* + * 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/stat.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 _virCPULoongArchVendor virCPULoongArchVendor; +struct _virCPULoongArchVendor { + char *name; +}; + +typedef struct _virCPULoongArchModel virCPULoongArchModel; +struct _virCPULoongArchModel { + char *name; + const virCPULoongArchVendor *vendor; + virCPULoongArchData data; +}; + +typedef struct _virCPULoongArchMap virCPULoongArchMap; +struct _virCPULoongArchMap { + size_t nvendors; + virCPULoongArchVendor **vendors; + size_t nmodels; + virCPULoongArchModel **models; +}; + +static void +virCPULoongArchDataClear(virCPULoongArchData *data) +{ + if (!data) + return; + + VIR_FREE(data->prid); +} + +static int +virCPULoongArchDataCopy(virCPULoongArchData *dst, + const virCPULoongArchData *src) +{ + size_t i; + + dst->prid = g_new0(virCPULoongArchPrid, src->len); + if (!dst->prid) + 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 +virCPULoongArchVendorFree(virCPULoongArchVendor *vendor) +{ + if (!vendor) + return; + + VIR_FREE(vendor->name); + VIR_FREE(vendor); +} + +static virCPULoongArchVendor * +virCPULoongArchVendorFind(const virCPULoongArchMap *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 +virCPULoongArchModelFree(virCPULoongArchModel *model) +{ + if (!model) + return; + + virCPULoongArchDataClear(&model->data); + VIR_FREE(model->name); + VIR_FREE(model); +} + +static virCPULoongArchModel * +virCPULoongArchModelCopy(const virCPULoongArchModel *model) +{ + virCPULoongArchModel *copy; + + copy = g_new0(virCPULoongArchModel, 1); + if (!copy) + goto cleanup; + + copy->name = g_strdup(model->name); + + if (virCPULoongArchDataCopy(©->data, &model->data) < 0) + goto cleanup; + + copy->vendor = model->vendor; + + return copy; + + cleanup: + virCPULoongArchModelFree(copy); + return NULL; +} + +static virCPULoongArchModel * +virCPULoongArchModelFind(const virCPULoongArchMap *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 virCPULoongArchModel * +virCPULoongArchModelFindPrid(const virCPULoongArchMap *map, + uint32_t prid) +{ + size_t i; + size_t j; + + for (i = 0; i < map->nmodels; i++) { + virCPULoongArchModel *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 virCPULoongArchModel * +virCPULoongArchModelFromCPU(const virCPUDef *cpu, + const virCPULoongArchMap *map) +{ + virCPULoongArchModel *model; + + if (!cpu->model) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("no CPU model specified")); + return NULL; + } + + if (!(model = virCPULoongArchModelFind(map, cpu->model))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %1$s"), cpu->model); + return NULL; + } + + return virCPULoongArchModelCopy(model); +} + +static void +virCPULoongArchMapFree(virCPULoongArchMap *map) +{ + size_t i; + + if (!map) + return; + + for (i = 0; i < map->nmodels; i++) + virCPULoongArchModelFree(map->models[i]); + VIR_FREE(map->models); + + for (i = 0; i < map->nvendors; i++) + virCPULoongArchVendorFree(map->vendors[i]); + VIR_FREE(map->vendors); + + VIR_FREE(map); +} + +static int +virCPULoongArchVendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED, + const char *name, + void *data) +{ + virCPULoongArchMap *map = data; + virCPULoongArchVendor *vendor; + int ret = -1; + + vendor = g_new0(virCPULoongArchVendor, 1); + if (!vendor) + return ret; + vendor->name = g_strdup(name); + + if (virCPULoongArchVendorFind(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %1$s already defined"), vendor->name); + goto cleanup; + } + + VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor); + + ret = 0; + + cleanup: + virCPULoongArchVendorFree(vendor); + return ret; +} + +static int +virCPULoongArchModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPULoongArchMap *map = data; + virCPULoongArchModel *model; + xmlNodePtr *nodes = NULL; + char *vendor = NULL; + uint32_t prid; + size_t i; + int n; + int ret = -1; + + model = g_new0(virCPULoongArchModel, 1); + if (!model) + goto cleanup; + + model->name = g_strdup(name); + + if (virCPULoongArchModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %1$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 %1$s"), + model->name); + goto cleanup; + } + + if (!(model->vendor = virCPULoongArchVendorFind(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %1$s referenced by CPU model %2$s"), + vendor, model->name); + goto cleanup; + } + } + + if ((n = virXPathNodeSet("./prid", ctxt, &nodes)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing Prid information for CPU model %1$s"), + model->name); + goto cleanup; + } + + model->data.prid = g_new0(virCPULoongArchPrid, n); + if (!model->data.prid) + goto cleanup; + + model->data.len = n; + + for (i = 0; i < n; i++) { + + if (virXMLPropUInt(nodes[i], "value", 16, VIR_XML_PROP_REQUIRED, + &prid) < 0) + { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid Prid value in CPU model %1$s"), + model->name); + goto cleanup; + } + model->data.prid[i].value = prid; + + if (virXMLPropUInt(nodes[i], "mask", 16, VIR_XML_PROP_REQUIRED, + &prid) < 0) + { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR mask in CPU model %1$s"), + model->name); + goto cleanup; + } + model->data.prid[i].mask = prid; + } + + VIR_APPEND_ELEMENT(map->models, map->nmodels, model); + + ret = 0; + + cleanup: + virCPULoongArchModelFree(model); + VIR_FREE(vendor); + VIR_FREE(nodes); + return ret; +} + +static virCPULoongArchMap * +virCPULoongArchLoadMap(void) +{ + virCPULoongArchMap *map; + + map = g_new0(virCPULoongArchMap, 1); + if (!map) + goto cleanup; + + if (cpuMapLoad("loongarch64", virCPULoongArchVendorParse, NULL, + virCPULoongArchModelParse, map) < 0) + goto cleanup; + + return map; + + cleanup: + virCPULoongArchMapFree(map); + return NULL; +} + +static virCPUData * +virCPULoongArchMakeCPUData(virArch arch, + virCPULoongArchData *data) +{ + virCPUData * cpuData; + + cpuData = g_new0(virCPUData, 1); + if (!cpuData) + return NULL; + + cpuData->arch = arch; + + if (virCPULoongArchDataCopy(&cpuData->data.loongarch, data) < 0) + VIR_FREE(cpuData); + + return cpuData; +} + +static virCPUCompareResult +virCPULoongArchCompute(virCPUDef *host, + const virCPUDef *other, + virCPUData **guestData, + char **message) +{ + virCPULoongArchMap *map = NULL; + virCPULoongArchModel *host_model = NULL; + virCPULoongArchModel *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 %1$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 %1$s"), + cpu->vendor); + } + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (!(map = virCPULoongArchLoadMap())) + goto cleanup; + + /* Host CPU information */ + if (!(host_model = virCPULoongArchModelFromCPU(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 = virCPULoongArchModelCopy(host_model); + break; + + case VIR_CPU_MODE_CUSTOM: + /* custom: + * look up guest CPU information */ + guest_model = virCPULoongArchModelFromCPU(cpu, map); + break; + } + } else { + /* Other host CPU information */ + guest_model = virCPULoongArchModelFromCPU(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 %1$s"), + guest_model->name); + } + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (guestData) + if (!(*guestData = virCPULoongArchMakeCPUData(arch, &guest_model->data))) + goto cleanup; + + ret = VIR_CPU_COMPARE_IDENTICAL; + + cleanup: + virCPUDefFree(cpu); + virCPULoongArchMapFree(map); + virCPULoongArchModelFree(host_model); + virCPULoongArchModelFree(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 = virCPULoongArchCompute(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 +virCPULoongArchDriverDecode(virCPUDef *cpu, + const virCPUData *data, + virDomainCapsCPUModels *models) +{ + int ret = -1; + virCPULoongArchMap *map; + const virCPULoongArchModel *model; + + if (!data || !(map = virCPULoongArchLoadMap())) + return -1; + + if (!(model = virCPULoongArchModelFindPrid(map, data->data.loongarch.prid[0].value))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with Prid 0x%1$08x"), + data->data.loongarch.prid[0].value); + goto cleanup; + } + + if (!virCPUModelIsAllowed(model->name, models)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %1$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: + virCPULoongArchMapFree(map); + + return ret; +} + +static void +virCPULoongArchDataFree(virCPUData *data) +{ + if (!data) + return; + + virCPULoongArchDataClear(&data->data.loongarch); + VIR_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); + if (!data->prid) + goto cleanup; + + + data->len = 1; + + data->prid[0].value = virCPULoongArchGetHostPRID(); + data->prid[0].mask = 0xffff00ul; + + ret = virCPULoongArchDriverDecode(cpu, cpuData, models); + + cleanup: + virCPULoongArchDataFree(cpuData); + return ret; +} + + +static int +virCPULoongArchUpdate(virCPUDef *guest, + const virCPUDef *host ATTRIBUTE_UNUSED, + bool relative G_GNUC_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 virCPUDef * +virCPULoongArchDriverBaseline(virCPUDef **cpus, + unsigned int ncpus, + virDomainCapsCPUModels *models ATTRIBUTE_UNUSED, + const char **features ATTRIBUTE_UNUSED, + bool migratable ATTRIBUTE_UNUSED) +{ + virCPULoongArchMap *map; + const virCPULoongArchModel *model; + const virCPULoongArchVendor *vendor = NULL; + virCPUDef *cpu = NULL; + size_t i; + + if (!(map = virCPULoongArchLoadMap())) + goto error; + + if (!(model = virCPULoongArchModelFind(map, cpus[0]->model))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %1$s"), cpus[0]->model); + goto error; + } + + for (i = 0; i < ncpus; i++) { + const virCPULoongArchVendor *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 = virCPULoongArchVendorFind(map, cpus[i]->vendor))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Unknown CPU vendor %1$s"), cpus[i]->vendor); + goto error; + } + + if (model->vendor) { + if (model->vendor != vnd) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("CPU vendor %1$s of model %2$s differs from vendor %3$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: + virCPULoongArchMapFree(map); + return cpu; + + error: + virCPUDefFree(cpu); + cpu = NULL; + goto cleanup; +} + +static int +virCPULoongArchDriverGetModels(char ***models) +{ + virCPULoongArchMap *map; + size_t i; + int ret = -1; + + if (!(map = virCPULoongArchLoadMap())) { + return -1; + } + + if (models) { + *models = g_new0(char *, map->nmodels + 1); + if (!(*models)) + return -1; + + for (i = 0; i < map->nmodels; i++) { + (*models)[i] = g_strdup(map->models[i]->name); + } + } + + ret = map->nmodels; + + return ret; +} + +struct cpuArchDriver cpuDriverLoongArch = { + .name = "LoongArch", + .arch = archs, + .narch = G_N_ELEMENTS(archs), + .compare = virCPULoongArchCompare, + .decode = virCPULoongArchDriverDecode, + .encode = NULL, + .dataFree = virCPULoongArchDataFree, + .getHost = virCPULoongArchGetHost, + .baseline = virCPULoongArchDriverBaseline, + .update = virCPULoongArchUpdate, + .getModels = virCPULoongArchDriverGetModels, +}; diff --git a/src/cpu/cpu_loongarch.h b/src/cpu/cpu_loongarch.h new file mode 100644 index 0000000000..bebc16a242 --- /dev/null +++ b/src/cpu/cpu_loongarch.h @@ -0,0 +1,25 @@ +/* + * 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/>. + */ + +#pragma once + +# include "cpu.h" + +extern struct cpuArchDriver cpuDriverLoongArch; diff --git a/src/cpu/cpu_loongarch_data.h b/src/cpu/cpu_loongarch_data.h new file mode 100644 index 0000000000..43ae044838 --- /dev/null +++ b/src/cpu/cpu_loongarch_data.h @@ -0,0 +1,37 @@ +/* + * 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/>. + */ + +#pragma once + +# 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; +}; diff --git a/src/cpu/meson.build b/src/cpu/meson.build index 55396903b9..254d6b4545 100644 --- a/src/cpu/meson.build +++ b/src/cpu/meson.build @@ -6,6 +6,7 @@ cpu_sources = [ 'cpu_riscv64.c', 'cpu_s390.c', 'cpu_x86.c', + 'cpu_loongarch.c' ] cpu_lib = static_library( diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 83119e871a..118d3429c3 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2697,6 +2697,7 @@ static const char *preferredMachines[] = "sim", /* VIR_ARCH_XTENSA */ "sim", /* VIR_ARCH_XTENSAEB */ + "virt", /* 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 953808fcfe..00e38950b6 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -4222,6 +4222,10 @@ qemuDomainDefAddDefaultDevices(virQEMUDriver *driver, addPCIRoot = 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 01e520de73..289bd80d90 100644 --- a/src/util/virarch.c +++ b/src/util/virarch.c @@ -83,6 +83,8 @@ static const struct virArchData { { "xtensa", 32, VIR_ARCH_LITTLE_ENDIAN }, { "xtensaeb", 32, VIR_ARCH_BIG_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 747f77c48e..638e519fe6 100644 --- a/src/util/virarch.h +++ b/src/util/virarch.h @@ -69,6 +69,8 @@ typedef enum { VIR_ARCH_XTENSA, /* XTensa 32 LE https://en.wikipedia.org/wiki/Xtensa#Processor_Cores */ VIR_ARCH_XTENSAEB, /* XTensa 32 BE https://en.wikipedia.org/wiki/Xtensa#Processor_Cores */ + VIR_ARCH_LOONGARCH64, /* LoongArch 64 LE */ + VIR_ARCH_LAST, } virArch; @@ -106,6 +108,8 @@ typedef enum { #define ARCH_IS_SH4(arch) ((arch) == VIR_ARCH_SH4 ||\ (arch) == VIR_ARCH_SH4EB) +#define ARCH_IS_LOONGARCH(arch) ((arch) == VIR_ARCH_LOONGARCH64) + typedef enum { VIR_ARCH_LITTLE_ENDIAN, VIR_ARCH_BIG_ENDIAN, -- 2.27.0 _______________________________________________ Devel mailing list -- devel@xxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx