This patch provides RV64 support for the RISC-V architecture. Signed-off-by: Yu Gu <guyu2876@xxxxxxxxx> --- po/POTFILES | 1 + src/cpu/cpu.c | 2 + src/cpu/cpu.h | 2 + src/cpu/cpu_riscv64.c | 116 ++++++++++++++++++++++++ src/cpu/cpu_riscv64.h | 25 ++++++ src/cpu/cpu_riscv64_data.h | 37 ++++++++ src/cpu/meson.build | 1 + src/cpu_map/index.xml | 4 + src/cpu_map/meson.build | 1 + src/cpu_map/riscv64_vendors.xml | 3 + src/util/virarch.c | 2 + src/util/virhostcpu.c | 2 +- src/util/virsysinfo.c | 150 ++++++++++++++++++++++++++++++++ src/util/virsysinfopriv.h | 3 + 14 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 src/cpu/cpu_riscv64.c create mode 100644 src/cpu/cpu_riscv64.h create mode 100644 src/cpu/cpu_riscv64_data.h create mode 100644 src/cpu_map/riscv64_vendors.xml diff --git a/po/POTFILES b/po/POTFILES index 169e2a41dc..a52795e7c1 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -72,6 +72,7 @@ src/cpu/cpu_map.c src/cpu/cpu_ppc64.c src/cpu/cpu_s390.c src/cpu/cpu_x86.c +src/cpu/cpu_riscv64.c src/datatypes.c src/driver.c src/esx/esx_driver.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d97ef5e873..8fdc42e719 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_riscv64.h" #include "capabilities.h" @@ -39,6 +40,7 @@ static struct cpuArchDriver *drivers[] = { &cpuDriverPPC64, &cpuDriverS390, &cpuDriverArm, + &cpuDriverRISCV64, }; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 41a62ce486..6e0a06fce4 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_riscv64_data.h" typedef struct _virCPUData virCPUData; @@ -36,6 +37,7 @@ struct _virCPUData { virCPUx86Data x86; virCPUppc64Data ppc64; virCPUarmData arm; + virCPUriscv64Data riscv64; /* generic driver needs no data */ } data; }; diff --git a/src/cpu/cpu_riscv64.c b/src/cpu/cpu_riscv64.c new file mode 100644 index 0000000000..9b90ae87d5 --- /dev/null +++ b/src/cpu/cpu_riscv64.c @@ -0,0 +1,116 @@ +/* + * cpu_riscv64.c: CPU driver for riscv64(x) CPUs + * + * 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 "cpu.h" + +#define VIR_FROM_THIS VIR_FROM_CPU + +static const virArch archs[] = { VIR_ARCH_RISCV64 }; + +static virCPUCompareResult +virCPUriscv64Compare(virCPUDef *host G_GNUC_UNUSED, + virCPUDef *cpu G_GNUC_UNUSED, + bool failMessages G_GNUC_UNUSED) +{ + /* riscv64 relies on QEMU to perform all runability checking. Return + * VIR_CPU_COMPARE_IDENTICAL to bypass Libvirt checking. + */ + return VIR_CPU_COMPARE_IDENTICAL; +} + +static int +virCPUriscv64Update(virCPUDef *guest, + const virCPUDef *host, + bool relative) +{ + g_autoptr(virCPUDef) updated = NULL; + size_t i; + + if (!relative) + return 0; + + if (guest->mode == VIR_CPU_MODE_CUSTOM) { + if (guest->match == VIR_CPU_MATCH_MINIMUM) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("match mode %s not supported"), + virCPUMatchTypeToString(guest->match)); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("optional CPU features are not supported")); + } + return -1; + } + + if (!host) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("unknown host CPU model")); + return -1; + } + + if (!(updated = virCPUDefCopyWithoutModel(guest))) + return -1; + + updated->mode = VIR_CPU_MODE_CUSTOM; + if (virCPUDefCopyModel(updated, host, true) < 0) + return -1; + + for (i = 0; i < guest->nfeatures; i++) { + if (virCPUDefUpdateFeature(updated, + guest->features[i].name, + guest->features[i].policy) < 0) + return -1; + } + + virCPUDefStealModel(guest, updated, false); + guest->mode = VIR_CPU_MODE_CUSTOM; + guest->match = VIR_CPU_MATCH_EXACT; + + return 0; +} + + +static int +virCPUriscv64ValidateFeatures(virCPUDef *cpu) +{ + size_t i; + + for (i = 0; i < cpu->nfeatures; i++) { + if (cpu->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("only cpu feature policies 'require' and 'disable' are supported for %s"), + cpu->features[i].name); + return -1; + } + } + + return 0; +} + +struct cpuArchDriver cpuDriverRISCV64 = { + .name = "riscv64", + .arch = archs, + .narch = G_N_ELEMENTS(archs), + .compare = virCPUriscv64Compare, + .decode = NULL, + .encode = NULL, + .baseline = NULL, + .update = virCPUriscv64Update, + .validateFeatures = virCPUriscv64ValidateFeatures, +}; diff --git a/src/cpu/cpu_riscv64.h b/src/cpu/cpu_riscv64.h new file mode 100644 index 0000000000..2ab43a9f95 --- /dev/null +++ b/src/cpu/cpu_riscv64.h @@ -0,0 +1,25 @@ +/* + * cpu_riscv64.h: CPU driver for 64-bit RISC-V 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 + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "cpu.h" + +extern struct cpuArchDriver cpuDriverRISCV64; diff --git a/src/cpu/cpu_riscv64_data.h b/src/cpu/cpu_riscv64_data.h new file mode 100644 index 0000000000..71c9dbf832 --- /dev/null +++ b/src/cpu/cpu_riscv64_data.h @@ -0,0 +1,37 @@ +/* + * cpu_riscv64_data.h: 64-bit riscv64 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 + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdint.h> + +typedef struct _virCPUriscv64Prid virCPUriscv64Prid; +struct _virCPUriscv64Prid { + uint32_t value; + uint32_t mask; +}; + +# define VIR_CPU_riscv64_DATA_INIT { 0 } + +typedef struct _virCPUriscv64Data virCPUriscv64Data; +struct _virCPUriscv64Data { + size_t len; + virCPUriscv64Prid *prid; +}; diff --git a/src/cpu/meson.build b/src/cpu/meson.build index b4ad95e46d..eba1d45743 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_riscv64.c', ] cpu_lib = static_library( diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml index d533a28865..f2c4b1c62a 100644 --- a/src/cpu_map/index.xml +++ b/src/cpu_map/index.xml @@ -89,6 +89,10 @@ <include filename='ppc64_POWERPC_e6500.xml'/> </arch> + <arch name='riscv64'> + <include filename='riscv64_vendors.xml'/> + </arch> + <arch name='arm'> <include filename='arm_vendors.xml'/> <include filename='arm_features.xml'/> diff --git a/src/cpu_map/meson.build b/src/cpu_map/meson.build index 99264289e2..1a02df8268 100644 --- a/src/cpu_map/meson.build +++ b/src/cpu_map/meson.build @@ -19,6 +19,7 @@ cpumap_data = [ 'ppc64_POWERPC_e5500.xml', 'ppc64_POWERPC_e6500.xml', 'ppc64_vendors.xml', + 'riscv64_vendors.xml', 'x86_486.xml', 'x86_athlon.xml', 'x86_Broadwell-IBRS.xml', diff --git a/src/cpu_map/riscv64_vendors.xml b/src/cpu_map/riscv64_vendors.xml new file mode 100644 index 0000000000..24476bd20b --- /dev/null +++ b/src/cpu_map/riscv64_vendors.xml @@ -0,0 +1,3 @@ +<cpus> + <vendor name='RISC-V'/> +</cpus> diff --git a/src/util/virarch.c b/src/util/virarch.c index 2134dd6a9d..3d14ecd193 100644 --- a/src/util/virarch.c +++ b/src/util/virarch.c @@ -190,6 +190,8 @@ virArch virArchFromHost(void) return VIR_ARCH_ALPHA; case PROCESSOR_ARCHITECTURE_PPC: return VIR_ARCH_PPC; + case PROCESSOR_ARCHITECTURE_RISCV: + return VIR_ARCH_RISCV64; case PROCESSOR_ARCHITECTURE_SHX: return VIR_ARCH_SH4; case PROCESSOR_ARCHITECTURE_ARM: diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index c1e8dc8078..08c2290f00 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -544,7 +544,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_RISCV(arch)) return 0; if (ARCH_IS_X86(arch)) diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 376d5d4816..afa480ead4 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -624,6 +624,154 @@ virSysinfoReadS390(void) } +static const char * +virSysinfoParseRISCVDelimited(const char *base, const char *name, char **value, + char delim1, char delim2) +{ + const char *start; + const char *end; + + if (delim1 != delim2 && + (start = strstr(base, name)) && + (start = strchr(start, delim1))) { + start += 1; + end = strchr(start, delim2); + if (!end) + end = start + strlen(start); + virSkipSpaces(&start); + *value = g_strndup(start, end - start); + virTrimSpaces(*value, NULL); + return end; + } + return NULL; +} + +static const char * +virSysinfoParseRISCVLine(const char *base, const char *name, char **value) +{ + return virSysinfoParseRISCVDelimited(base, name, value, ':', '\n'); +} + +static int +virSysinfoParseRISCVSystem(const char *base, virSysinfoSystemDef **sysdef) +{ + int ret = -1; + virSysinfoSystemDef *def; + + def = g_new0(virSysinfoSystemDef, 1); + + if (!virSysinfoParseRISCVLine(base, "Manufacturer", &def->manufacturer)) + goto cleanup; + + if (!virSysinfoParseRISCVLine(base, "Type", &def->family)) + goto cleanup; + def->manufacturer = g_strndup("Virt-RISC-V", sizeof("Virt RISC-V")); + + if (!def->manufacturer && !def->product && !def->version && + !def->serial && !def->uuid && !def->sku && !def->family) { + g_clear_pointer(&def, virSysinfoSystemDefFree); + } + + *sysdef = g_steal_pointer(&def); + ret = 0; + cleanup: + virSysinfoSystemDefFree(def); + return ret; +} + +static int +virSysinfoParseRISCVProcessor(const char *base, virSysinfoDef *ret) +{ + const char *tmp_base; + char *manufacturer = NULL; + char *procline = NULL; + char *ncpu = NULL; + int result = -1; + virSysinfoProcessorDef *processor; + + if (!(tmp_base = virSysinfoParseRISCVLine(base, "uarch", &manufacturer))) + goto error; + + /* Find processor N: line and gather the processor manufacturer, + version, serial number, and family */ + while ((tmp_base = strstr(tmp_base, "processor ")) + && (tmp_base = virSysinfoParseRISCVLine(tmp_base, "processor ", + &procline))) { + VIR_EXPAND_N(ret->processor, ret->nprocessor, 1); + processor = &ret->processor[ret->nprocessor - 1]; + processor->processor_manufacturer = g_strdup(manufacturer); + + VIR_FREE(procline); + } + + /* now, for each processor found, extract the frequency information */ + tmp_base = base; + + while ((tmp_base = strstr(tmp_base, "cpu number")) && + (tmp_base = virSysinfoParseRISCVLine(tmp_base, "cpu number", &ncpu))) { + unsigned int n; + char *mhz = NULL; + + if (virStrToLong_uip(ncpu, NULL, 10, &n) < 0) + goto error; + + if (n >= ret->nprocessor) { + VIR_DEBUG("CPU number '%u' out of range", n); + goto cleanup; + } + + if (!(tmp_base = strstr(tmp_base, "cpu MHz static")) || + !virSysinfoParseRISCVLine(tmp_base, "cpu MHz static", &mhz)) + goto cleanup; + + ret->processor[n].processor_max_speed = mhz; + + VIR_FREE(ncpu); + } + + cleanup: + result = 0; + + error: + VIR_FREE(manufacturer); + VIR_FREE(procline); + VIR_FREE(ncpu); + return result; +} + +virSysinfoDef * +virSysinfoReadRISCV(void) +{ + g_autoptr(virSysinfoDef) ret = NULL; + g_autofree char *outbuf = NULL; + + ret = g_new0(virSysinfoDef, 1); + + /* Gather info from /proc/cpuinfo */ + if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open %s"), CPUINFO); + return NULL; + } + + if (virSysinfoParseRISCVProcessor(outbuf, ret) < 0) + return NULL; + + /* Free buffer before reading next file */ + VIR_FREE(outbuf); + + /* Gather info from /proc/sysinfo */ + if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open %s"), SYSINFO); + return NULL; + } + + if (virSysinfoParseRISCVSystem(outbuf, &ret->system) < 0) + return NULL; + return g_steal_pointer(&ret); +} + static int virSysinfoParseBIOS(const char *base, virSysinfoBIOSDef **bios) { @@ -1243,6 +1391,8 @@ virSysinfoRead(void) return virSysinfoReadPPC(); #elif defined(__arm__) || defined(__aarch64__) return virSysinfoReadARM(); +#elif defined(__riscv) && __riscv_xlen == 64 + return virSysinfoReadRISCV(); #elif defined(__s390__) || defined(__s390x__) return virSysinfoReadS390(); #elif !defined(WIN32) && \ diff --git a/src/util/virsysinfopriv.h b/src/util/virsysinfopriv.h index e47bd3c361..33c8ceeddb 100644 --- a/src/util/virsysinfopriv.h +++ b/src/util/virsysinfopriv.h @@ -36,5 +36,8 @@ virSysinfoReadARM(void); virSysinfoDef * virSysinfoReadS390(void); +virSysinfoDef * +virSysinfoReadRISCV(void); + virSysinfoDef * virSysinfoReadDMI(void); -- 2.38.1