From nobody Mon Feb 9 19:08:53 2026 Delivered-To: importer@patchew.org Received-SPF: none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; spf=none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) smtp.mailfrom=devel-bounces@lists.libvirt.org Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1702535569106207.19187183994916; Wed, 13 Dec 2023 22:32:49 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id D9A3117CA; Thu, 14 Dec 2023 01:32:47 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 53EE517AF; Thu, 14 Dec 2023 01:23:49 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id 1CDAA1864; Thu, 14 Dec 2023 01:23:35 -0500 (EST) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 04BF81700 for ; Thu, 14 Dec 2023 01:23:26 -0500 (EST) Received: by mx1.osci.io (Postfix, from userid 994) id DB2B921F21; Thu, 14 Dec 2023 01:23:25 -0500 (EST) Received: from mx2.osci.io (francine.osci.io [IPv6:2620:52:3:1:5054:ff:fe8c:ad7a]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id E484721EE7 for ; Thu, 14 Dec 2023 01:23:24 -0500 (EST) Received: by mx2.osci.io (Postfix, from userid 994) id 6282040BF3; Thu, 14 Dec 2023 01:23:24 -0500 (EST) Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx2.osci.io (Postfix) with ESMTP id C82D840C75 for ; Thu, 14 Dec 2023 01:23:19 -0500 (EST) Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8BxbOn6nnplo+4AAA--.5323S3; Thu, 14 Dec 2023 14:21:46 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by localhost.localdomain (Coremail) with SMTP id AQAAf8AxGXP3nnplWMADAA--.5886S3; Thu, 14 Dec 2023 14:21:45 +0800 (CST) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 X-Greylist: delayed 83 seconds by postgrey-1.37 at francine.osci.io; Thu, 14 Dec 2023 01:23:19 EST From: xianglai li To: devel@lists.libvirt.org Subject: [libvirt PATCH 1/5] Add loongarch cpu support Date: Thu, 14 Dec 2023 14:08:45 +0800 Message-Id: <5dcb70783a2738a2b3dd182c6fec094b4b1297bb.1702455593.git.lixianglai@loongson.cn> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: AQAAf8AxGXP3nnplWMADAA--.5886S3 X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== Message-ID-Hash: 73P6CGVGMM5WS52HGTH2M7DWO6E6SS25 X-Message-ID-Hash: 73P6CGVGMM5WS52HGTH2M7DWO6E6SS25 X-MailFrom: SRS0=vjgz=HZ=loongson.cn=lixianglai@osci.io X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: lixianglai@loongson.cn, maobibo@loongson.cn, jiyin@redhat.com X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1702535569584100001 From: lixianglai Add loongarch cpu support, Define new cpu type 'loongarch64' and implement it's driver functions. Signed-off-by: lixianglai --- 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 @@ x86_64 xtensa xtensaeb + loongarch64 =20 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" =20 @@ -41,6 +42,7 @@ static struct cpuArchDriver *drivers[] =3D { &cpuDriverS390, &cpuDriverArm, &cpuDriverRiscv64, + &cpuDriverLoongArch, }; =20 =20 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" =20 =20 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 + * . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "virlog.h" +#include "viralloc.h" +#include "cpu.h" +#include "virstring.h" +#include "cpu_map.h" +#include "virbuffer.h" + +#define VIR_FROM_THIS VIR_FROM_CPU + +VIR_LOG_INIT("cpu.cpu_loongarch"); + +static const virArch archs[] =3D { 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 =3D g_new0(virCPULoongArchPrid, src->len); + if (!dst->prid) + return -1; + + dst->len =3D src->len; + + for (i =3D 0; i < src->len; i++) { + dst->prid[i].value =3D src->prid[i].value; + dst->prid[i].mask =3D 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 =3D 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 =3D g_new0(virCPULoongArchModel, 1); + if (!copy) + goto cleanup; + + copy->name =3D g_strdup(model->name); + + if (virCPULoongArchDataCopy(©->data, &model->data) < 0) + goto cleanup; + + copy->vendor =3D model->vendor; + + return copy; + + cleanup: + virCPULoongArchModelFree(copy); + return NULL; +} + +static virCPULoongArchModel * +virCPULoongArchModelFind(const virCPULoongArchMap *map, + const char *name) +{ + size_t i; + + for (i =3D 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 =3D 0; i < map->nmodels; i++) { + virCPULoongArchModel *model =3D map->models[i]; + for (j =3D 0; j < model->data.len; j++) { + if ((prid & model->data.prid[j].mask) =3D=3D 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 =3D 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 =3D 0; i < map->nmodels; i++) + virCPULoongArchModelFree(map->models[i]); + VIR_FREE(map->models); + + for (i =3D 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 =3D data; + virCPULoongArchVendor *vendor; + int ret =3D -1; + + vendor =3D g_new0(virCPULoongArchVendor, 1); + if (!vendor) + return ret; + vendor->name =3D 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 =3D 0; + + cleanup: + virCPULoongArchVendorFree(vendor); + return ret; +} + +static int +virCPULoongArchModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPULoongArchMap *map =3D data; + virCPULoongArchModel *model; + xmlNodePtr *nodes =3D NULL; + char *vendor =3D NULL; + uint32_t prid; + size_t i; + int n; + int ret =3D -1; + + model =3D g_new0(virCPULoongArchModel, 1); + if (!model) + goto cleanup; + + model->name =3D 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 =3D 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 =3D 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 =3D virXPathNodeSet("./prid", ctxt, &nodes)) <=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing Prid information for CPU model %1$s"), + model->name); + goto cleanup; + } + + model->data.prid =3D g_new0(virCPULoongArchPrid, n); + if (!model->data.prid) + goto cleanup; + + model->data.len =3D n; + + for (i =3D 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 =3D 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 =3D prid; + } + + VIR_APPEND_ELEMENT(map->models, map->nmodels, model); + + ret =3D 0; + + cleanup: + virCPULoongArchModelFree(model); + VIR_FREE(vendor); + VIR_FREE(nodes); + return ret; +} + +static virCPULoongArchMap * +virCPULoongArchLoadMap(void) +{ + virCPULoongArchMap *map; + + map =3D 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 =3D g_new0(virCPUData, 1); + if (!cpuData) + return NULL; + + cpuData->arch =3D 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 =3D NULL; + virCPULoongArchModel *host_model =3D NULL; + virCPULoongArchModel *guest_model =3D NULL; + virCPUDef *cpu =3D NULL; + virCPUCompareResult ret =3D VIR_CPU_COMPARE_ERROR; + virArch arch; + size_t i; + + /* Ensure existing configurations are handled correctly */ + if (!(cpu =3D virCPUDefCopy(other))) + goto cleanup; + + if (cpu->arch !=3D VIR_ARCH_NONE) { + bool found =3D false; + + for (i =3D 0; i < G_N_ELEMENTS(archs); i++) { + if (archs[i] =3D=3D cpu->arch) { + found =3D true; + break; + } + } + + if (!found) { + VIR_DEBUG("CPU arch %s does not match host arch", + virArchToString(cpu->arch)); + if (message) { + *message =3D g_strdup_printf(_("CPU arch %1$s does not mat= ch host arch"), + virArchToString(cpu->arch)); + } + ret =3D VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + arch =3D cpu->arch; + } else { + arch =3D 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 =3D g_strdup_printf(_("host CPU vendor does not match= required CPU vendor %1$s"), + cpu->vendor); + } + ret =3D VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (!(map =3D virCPULoongArchLoadMap())) + goto cleanup; + + /* Host CPU information */ + if (!(host_model =3D virCPULoongArchModelFromCPU(host, map))) + goto cleanup; + + if (cpu->type =3D=3D 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 =3D virCPULoongArchModelCopy(host_model); + break; + + case VIR_CPU_MODE_CUSTOM: + /* custom: + * look up guest CPU information */ + guest_model =3D virCPULoongArchModelFromCPU(cpu, map); + break; + } + } else { + /* Other host CPU information */ + guest_model =3D 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 =3D g_strdup_printf(_("host CPU model does not match = required CPU model %1$s"), + guest_model->name); + } + ret =3D VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (guestData) + if (!(*guestData =3D virCPULoongArchMakeCPUData(arch, &guest_model= ->data))) + goto cleanup; + + ret =3D 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 =3D NULL; + + if (!host || !host->model) { + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", + _("unknown host CPU")); + } else { + VIR_WARN("unknown host CPU"); + ret =3D VIR_CPU_COMPARE_INCOMPATIBLE; + } + return -1; + } + + ret =3D virCPULoongArchCompute(host, cpu, NULL, &message); + + if (failIncompatible && ret =3D=3D VIR_CPU_COMPARE_INCOMPATIBLE) { + ret =3D 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 =3D -1; + virCPULoongArchMap *map; + const virCPULoongArchModel *model; + + if (!data || !(map =3D virCPULoongArchLoadMap())) + return -1; + + if (!(model =3D 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 =3D g_strdup(model->name); + if (model->vendor) { + cpu->vendor =3D g_strdup(model->vendor->name); + } + ret =3D 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 =3D NULL; + virCPULoongArchData *data; + int ret =3D -1; + + if (!(cpuData =3D virCPUDataNew(archs[0]))) + goto cleanup; + + data =3D &cpuData->data.loongarch; + data->prid =3D g_new0(virCPULoongArchPrid, 1); + if (!data->prid) + goto cleanup; + + + data->len =3D 1; + + data->prid[0].value =3D virCPULoongArchGetHostPRID(); + data->prid[0].mask =3D 0xffff00ul; + + ret =3D 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 a= nd + * it needs to remain unchanged + * - custom doesn't support any optional features, there's nothing to + * update + */ + + if (guest->mode =3D=3D VIR_CPU_MODE_CUSTOM) + guest->match =3D 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 =3D NULL; + virCPUDef *cpu =3D NULL; + size_t i; + + if (!(map =3D virCPULoongArchLoadMap())) + goto error; + + if (!(model =3D virCPULoongArchModelFind(map, cpus[0]->model))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %1$s"), cpus[0]->model); + goto error; + } + + for (i =3D 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 =3D 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 !=3D vnd) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("CPU vendor %1$s of model %2$s differs fr= om vendor %3$s"), + model->vendor->name, model->name, + vnd->name); + goto error; + } + } else if (vendor) { + if (vendor !=3D vnd) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("CPU vendors do not match")); + goto error; + } + } else { + vendor =3D vnd; + } + } + + cpu =3D virCPUDefNew(); + cpu->model =3D g_strdup(model->name); + if (vendor) { + cpu->vendor =3D g_strdup(vendor->name); + } + cpu->type =3D VIR_CPU_TYPE_GUEST; + cpu->match =3D VIR_CPU_MATCH_EXACT; + cpu->fallback =3D VIR_CPU_FALLBACK_FORBID; + + cleanup: + virCPULoongArchMapFree(map); + return cpu; + + error: + virCPUDefFree(cpu); + cpu =3D NULL; + goto cleanup; +} + +static int +virCPULoongArchDriverGetModels(char ***models) +{ + virCPULoongArchMap *map; + size_t i; + int ret =3D -1; + + if (!(map =3D virCPULoongArchLoadMap())) { + return -1; + } + + if (models) { + *models =3D g_new0(char *, map->nmodels + 1); + if (!(*models)) + return -1; + + for (i =3D 0; i < map->nmodels; i++) { + (*models)[i] =3D g_strdup(map->models[i]->name); + } + } + + ret =3D map->nmodels; + + return ret; +} + +struct cpuArchDriver cpuDriverLoongArch =3D { + .name =3D "LoongArch", + .arch =3D archs, + .narch =3D G_N_ELEMENTS(archs), + .compare =3D virCPULoongArchCompare, + .decode =3D virCPULoongArchDriverDecode, + .encode =3D NULL, + .dataFree =3D virCPULoongArchDataFree, + .getHost =3D virCPULoongArchGetHost, + .baseline =3D virCPULoongArchDriverBaseline, + .update =3D virCPULoongArchUpdate, + .getModels =3D 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 + * . + */ + +#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 + * . + */ + +#pragma once + +# 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; +}; 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 =3D [ 'cpu_riscv64.c', 'cpu_s390.c', 'cpu_x86.c', + 'cpu_loongarch.c' ] =20 cpu_lib =3D 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[] =3D =20 "sim", /* VIR_ARCH_XTENSA */ "sim", /* VIR_ARCH_XTENSAEB */ + "virt", /* VIR_ARCH_LOONGARCH64 */ }; G_STATIC_ASSERT(G_N_ELEMENTS(preferredMachines) =3D=3D VIR_ARCH_LAST); =20 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 =3D true; break; =20 + case VIR_ARCH_LOONGARCH64: + addPCIeRoot =3D 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 { =20 { "xtensa", 32, VIR_ARCH_LITTLE_ENDIAN }, { "xtensaeb", 32, VIR_ARCH_BIG_ENDIAN }, + + { "loongarch64", 64, VIR_ARCH_LITTLE_ENDIAN }, }; =20 G_STATIC_ASSERT(G_N_ELEMENTS(virArchData) =3D=3D 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/w= iki/Xtensa#Processor_Cores */ VIR_ARCH_XTENSAEB, /* XTensa 32 BE https://en.wikipedia.org/w= iki/Xtensa#Processor_Cores */ =20 + VIR_ARCH_LOONGARCH64, /* LoongArch 64 LE */ + VIR_ARCH_LAST, } virArch; =20 @@ -106,6 +108,8 @@ typedef enum { #define ARCH_IS_SH4(arch) ((arch) =3D=3D VIR_ARCH_SH4 ||\ (arch) =3D=3D VIR_ARCH_SH4EB) =20 +#define ARCH_IS_LOONGARCH(arch) ((arch) =3D=3D VIR_ARCH_LOONGARCH64) + typedef enum { VIR_ARCH_LITTLE_ENDIAN, VIR_ARCH_BIG_ENDIAN, --=20 2.27.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org