[libvirt PATCH v2] Add basically RISC-V support

Yu Gu posted 1 patch 1 year, 7 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20220928085406.2790794-1-guyu2876@gmail.com
po/POTFILES                     |   1 +
src/cpu/cpu.c                   |   2 +
src/cpu/cpu.h                   |   2 +
src/cpu/cpu_riscv64.c           | 118 +++++++++++++++++++++++++++++++
src/cpu/cpu_riscv64.h           |  28 ++++++++
src/cpu/cpu_riscv64_data.h      |  40 +++++++++++
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           | 121 ++++++++++++++++++++++++++++++++
13 files changed, 324 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
[libvirt PATCH v2] Add basically RISC-V support
Posted by Yu Gu 1 year, 7 months ago
This patch provides basic support for the RISC-V architecture, so
libvirt can run in RISC-V machine.

Signed-off-by: Yu Gu <guyu2876@gmail.com>
---
 po/POTFILES                     |   1 +
 src/cpu/cpu.c                   |   2 +
 src/cpu/cpu.h                   |   2 +
 src/cpu/cpu_riscv64.c           | 118 +++++++++++++++++++++++++++++++
 src/cpu/cpu_riscv64.h           |  28 ++++++++
 src/cpu/cpu_riscv64_data.h      |  40 +++++++++++
 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           | 121 ++++++++++++++++++++++++++++++++
 13 files changed, 324 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..21f7178cc2
--- /dev/null
+++ b/src/cpu/cpu_riscv64.c
@@ -0,0 +1,118 @@
+/*
+ * 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..67528415fe
--- /dev/null
+++ b/src/cpu/cpu_riscv64.h
@@ -0,0 +1,28 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __VIR_CPU_RISCV64_H__
+# define __VIR_CPU_RISCV64_H__
+
+# include "cpu.h"
+
+extern struct cpuArchDriver cpuDriverRISCV64;
+
+#endif
diff --git a/src/cpu/cpu_riscv64_data.h b/src/cpu/cpu_riscv64_data.h
new file mode 100644
index 0000000000..819b9e8fde
--- /dev/null
+++ b/src/cpu/cpu_riscv64_data.h
@@ -0,0 +1,40 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __VIR_CPU_RISCV64_DATA_H__
+# define __VIR_CPU_RISCV64_DATA_H__
+
+# 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;
+};
+
+#endif
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..478a23a467
--- /dev/null
+++ b/src/cpu_map/riscv64_vendors.xml
@@ -0,0 +1,3 @@
+<cpus>
+  <vendor name='RISC-V'/>
+</cpus>
\ No newline at end of file
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..e281d928c7 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -623,6 +623,125 @@ virSysinfoReadS390(void)
     return g_steal_pointer(&ret);
 }
 
+#if 0
+static int
+virSysinfoParseRISCVSystem(const char *base, virSysinfoSystemDef **sysdef)
+{
+    int ret = -1;
+    virSysinfoSystemDef *def;
+
+    def = g_new0(virSysinfoSystemDef, 1);
+
+#if 0
+    if (!virSysinfoParseS390Line(base, "Manufacturer", &def->manufacturer))
+        goto cleanup;
+
+    if (!virSysinfoParseS390Line(base, "Type", &def->family))
+        goto cleanup;
+#endif
+    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;
+}
+#endif
+
+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 = virSysinfoParseS390Line(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 = virSysinfoParseS390Line(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, "hart")) &&
+           (tmp_base = virSysinfoParseS390Line(tmp_base, "hart", &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;
+        }
+
+        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);
+
+#if 0
+    /* 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;
+#endif
+    return g_steal_pointer(&ret);
+}
 
 static int
 virSysinfoParseBIOS(const char *base, virSysinfoBIOSDef **bios)
@@ -1243,6 +1362,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) && \
-- 
2.37.3
Re: [libvirt PATCH v2] Add basically RISC-V support
Posted by Michal Prívozník 1 year, 6 months ago
On 9/28/22 10:54, Yu Gu wrote:
> This patch provides basic support for the RISC-V architecture, so
> libvirt can run in RISC-V machine.
> 
> Signed-off-by: Yu Gu <guyu2876@gmail.com>
> ---
>  po/POTFILES                     |   1 +
>  src/cpu/cpu.c                   |   2 +
>  src/cpu/cpu.h                   |   2 +
>  src/cpu/cpu_riscv64.c           | 118 +++++++++++++++++++++++++++++++
>  src/cpu/cpu_riscv64.h           |  28 ++++++++
>  src/cpu/cpu_riscv64_data.h      |  40 +++++++++++
>  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           | 121 ++++++++++++++++++++++++++++++++
>  13 files changed, 324 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

Hey, this is just an RFC, right? Because there are couple of issues with
this patch. And I don't have RISCV anywhere handy, so I'd appreciate if
you'd add a sysinfotest test case.

And for your next version, please make sure the code compiles with:

meson -Dexpensive_tests=enabled _build && ninja -C _build/ test

> 
> 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..21f7178cc2
> --- /dev/null
> +++ b/src/cpu/cpu_riscv64.c
> @@ -0,0 +1,118 @@
> +/*
> + * 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)

Alignment. Here and in couple of other places.

> +{
> +    /* 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"),

Error messages are exempt from the 80chars rule. In other words, It's
desired to put the whole message onto a single line. The reason is
simple: easier git grep. I know you'll find a lot of old code which
still breaks error messages, but we change that whenever the old code is
changed and surely we want to already have that for any new code.

> +                           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..67528415fe
> --- /dev/null
> +++ b/src/cpu/cpu_riscv64.h
> @@ -0,0 +1,28 @@
> +/*
> + * 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/>.
> + */
> +
> +#ifndef __VIR_CPU_RISCV64_H__
> +# define __VIR_CPU_RISCV64_H__

We use #pragma once nowadays.

> +
> +# include "cpu.h"
> +
> +extern struct cpuArchDriver cpuDriverRISCV64;
> +
> +#endif
> diff --git a/src/cpu/cpu_riscv64_data.h b/src/cpu/cpu_riscv64_data.h
> new file mode 100644
> index 0000000000..819b9e8fde
> --- /dev/null
> +++ b/src/cpu/cpu_riscv64_data.h
> @@ -0,0 +1,40 @@
> +/*
> + * 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/>.
> + */
> +
> +#ifndef __VIR_CPU_RISCV64_DATA_H__
> +# define __VIR_CPU_RISCV64_DATA_H__
> +
> +# 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;
> +};
> +
> +#endif

I wonder what's the purpose for this file, because nothing it declares
is ever used.

> 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..478a23a467
> --- /dev/null
> +++ b/src/cpu_map/riscv64_vendors.xml
> @@ -0,0 +1,3 @@
> +<cpus>
> +  <vendor name='RISC-V'/>
> +</cpus>
> \ No newline at end of file
> 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..e281d928c7 100644
> --- a/src/util/virsysinfo.c
> +++ b/src/util/virsysinfo.c
> @@ -623,6 +623,125 @@ virSysinfoReadS390(void)
>      return g_steal_pointer(&ret);
>  }
>  
> +#if 0
> +static int
> +virSysinfoParseRISCVSystem(const char *base, virSysinfoSystemDef **sysdef)
> +{
> +    int ret = -1;
> +    virSysinfoSystemDef *def;
> +
> +    def = g_new0(virSysinfoSystemDef, 1);
> +
> +#if 0
> +    if (!virSysinfoParseS390Line(base, "Manufacturer", &def->manufacturer))

At this point, maube the function should be renamed? It feels very weird
that a RISCV function calls an S390 function.

> +        goto cleanup;
> +
> +    if (!virSysinfoParseS390Line(base, "Type", &def->family))

Ditto. And I believe this is going to be uncommented so that you can
detect the manufacturer for the sysinfotest, right?

> +        goto cleanup;
> +#endif
> +    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;
> +}
> +#endif
> +
> +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 = virSysinfoParseS390Line(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 = virSysinfoParseS390Line(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, "hart")) &&
> +           (tmp_base = virSysinfoParseS390Line(tmp_base, "hart", &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;
> +        }
> +
> +        VIR_FREE(ncpu);
> +    }
> +
> + cleanup:
> +    result = 0;
> +
> + error:
> +    VIR_FREE(manufacturer);
> +    VIR_FREE(procline);
> +    VIR_FREE(ncpu);
> +    return result;
> +}
> +
> +virSysinfoDef *
> +virSysinfoReadRISCV(void)

You need to add a declaration for this function into
src/util/virsysinfopriv.h.

Michal
[libvirt PATCH v3] Add RV64 support
Posted by Yu Gu 1 year, 5 months ago
This patch provides RV64 support for the RISC-V architecture.

Signed-off-by: Yu Gu <guyu2876@gmail.com>
---
 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