qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board
@ 2025-11-11 18:29 Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 1/5] target/riscv/cpu.c: remove 'bare' condition for .profile Daniel Henrique Barboza
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Daniel Henrique Barboza

Hi,

In this new version we addressed the comments from Chao Liu in patches 2
and 4.

We're also owning up the fact that the board is being contributed in an
incomplete status, given that we're missing 'sdext'.In theory we
shouldn't try to upstream it until we have 'sdext' implemented but this
board seems to be used by a lot of folks for for firmware development
and whatnot. Thus, I changed the board description in patch 3 to add an
'EXPERIMENTAL' tag.

This is how the board is presented with -M help:

$ ./build/qemu-system-riscv64 -M help Supported machines are:
amd-microblaze-v-generic AMD Microblaze-V generic platform
microchip-icicle-kit Microchip PolarFire SoC Icicle Kit none
empty machine rvsp-ref             RISC-V Server SoC Reference board
(EXPERIMENTAL) (...)

Patch 5 adds documentation for the board. Again, making it clear that
this is an experimental board that will be subject to changes before
being 100% compliant with the spec.

Patches based on current master.

Changes in v4:
- patch 2:
  - changed rvsp-ref CPU base type to BARE
  - added a comment mentioning the lack of 'sdext'
- patch 3:
  - changed the board description to add 'experimental'
- patch 4:
  - fixed RVSP_IOMMU_SYS memmap addr: 0102000 -> 0x102000
- patch 5 (new):
  - add board documentation
- v3 link: https://lore.kernel.org/qemu-riscv/20250528200129.1548259-1-dbarboza@ventanamicro.com/ 


Daniel Henrique Barboza (3):
  target/riscv/cpu.c: remove 'bare' condition for .profile
  hw/riscv/server_platform_ref.c: add riscv-iommu-sys
  docs: add rvsp-ref.rst

Fei Wu (2):
  target/riscv: Add server platform reference cpu
  hw/riscv: experimental server platform reference machine

 configs/devices/riscv64-softmmu/default.mak |    1 +
 docs/system/riscv/rvsp-ref.rst              |   28 +
 docs/system/target-riscv.rst                |    1 +
 hw/riscv/Kconfig                            |   15 +
 hw/riscv/meson.build                        |    1 +
 hw/riscv/server_platform_ref.c              | 1346 +++++++++++++++++++
 target/riscv/cpu-qom.h                      |    1 +
 target/riscv/cpu.c                          |   15 +-
 8 files changed, 1407 insertions(+), 1 deletion(-)
 create mode 100644 docs/system/riscv/rvsp-ref.rst
 create mode 100644 hw/riscv/server_platform_ref.c

-- 
2.51.1



^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 1/5] target/riscv/cpu.c: remove 'bare' condition for .profile
  2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
@ 2025-11-11 18:29 ` Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 2/5] target/riscv: Add server platform reference cpu Daniel Henrique Barboza
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Daniel Henrique Barboza, Andrew Jones

We want to configure other CPU types to use profiles as an alternative
to adding every profile extension explicitly, i.e. a profile is nothing
more than an extension bundle.

This means that a vendor CPU can set .profile=rva23s64 while having the
same handling as any other vendor CPU. Same thing with all other CPU
types.

Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
---
 target/riscv/cpu.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 73d4280d7c..975f7953e1 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -2792,7 +2792,6 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data)
         mcc->def->bare |= def->bare;
         if (def->profile) {
             assert(profile_extends(def->profile, mcc->def->profile));
-            assert(mcc->def->bare);
             mcc->def->profile = def->profile;
         }
         if (def->misa_mxl_max) {
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v4 2/5] target/riscv: Add server platform reference cpu
  2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 1/5] target/riscv/cpu.c: remove 'bare' condition for .profile Daniel Henrique Barboza
@ 2025-11-11 18:29 ` Daniel Henrique Barboza
  2025-11-11 23:05   ` Andrew Jones
  2025-11-11 18:29 ` [PATCH v4 3/5] hw/riscv: experimental server platform reference machine Daniel Henrique Barboza
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Fei Wu, Daniel Henrique Barboza

From: Fei Wu <wu.fei9@sanechips.com.cn>

The harts requirements of RISC-V server platform [1] require RVA23 ISA
profile support, plus Sv48, Svadu, H, Sscofmpf etc.

This patch provides a CPU type (rvsp-ref) to go along with the rvsp-ref
board.

[1] https://github.com/riscv-non-isa/riscv-server-platform/blob/main/server_platform_requirements.adoc

Signed-off-by: Fei Wu <fei2.wu@intel.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 target/riscv/cpu-qom.h |  1 +
 target/riscv/cpu.c     | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 75f4e43408..07e96a14ba 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -42,6 +42,7 @@
 #define TYPE_RISCV_CPU_RVA22S64         RISCV_CPU_TYPE_NAME("rva22s64")
 #define TYPE_RISCV_CPU_RVA23U64         RISCV_CPU_TYPE_NAME("rva23u64")
 #define TYPE_RISCV_CPU_RVA23S64         RISCV_CPU_TYPE_NAME("rva23s64")
+#define TYPE_RISCV_CPU_RVSP_REF         RISCV_CPU_TYPE_NAME("rvsp-ref")
 #define TYPE_RISCV_CPU_IBEX             RISCV_CPU_TYPE_NAME("lowrisc-ibex")
 #define TYPE_RISCV_CPU_SHAKTI_C         RISCV_CPU_TYPE_NAME("shakti-c")
 #define TYPE_RISCV_CPU_SIFIVE_E         RISCV_CPU_TYPE_NAME("sifive-e")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 975f7953e1..3ddb249970 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -3305,6 +3305,20 @@ static const TypeInfo riscv_cpu_type_infos[] = {
         .cfg.max_satp_mode = VM_1_10_SV48,
     ),
 
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RVSP_REF, TYPE_RISCV_BARE_CPU,
+        .misa_mxl_max = MXL_RV64,
+        .profile = &RVA23S64,
+
+        /*
+         * ISA extensions
+         * NOTE: we're missing 'sdext'.
+         */
+        .cfg.ext_zkr = true,
+        .cfg.ext_svadu = true,
+
+        .cfg.max_satp_mode = VM_1_10_SV57,
+    ),
+
 #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
     DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU,
         .cfg.max_satp_mode = VM_1_10_SV57,
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v4 3/5] hw/riscv: experimental server platform reference machine
  2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 1/5] target/riscv/cpu.c: remove 'bare' condition for .profile Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 2/5] target/riscv: Add server platform reference cpu Daniel Henrique Barboza
@ 2025-11-11 18:29 ` Daniel Henrique Barboza
  2025-11-11 23:36   ` Andrew Jones
  2025-11-12  7:13   ` Philippe Mathieu-Daudé
  2025-11-11 18:29 ` [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys Daniel Henrique Barboza
  2025-11-11 18:29 ` [PATCH v4 5/5] docs: add rvsp-ref.rst Daniel Henrique Barboza
  4 siblings, 2 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Fei Wu, Daniel Henrique Barboza

From: Fei Wu <wu.fei9@sanechips.com.cn>

The RISC-V Server Platform specification [1] defines a standardized set
of hardware and software capabilities, that portable system software,
such as OS and hypervisors can rely on being present in a RISC-V server
platform.

We do not have all the required extensions in QEMU: we're missing
'sdext'. In theory we shouldn't go ahead with this work, but the
emulation as is now is proving to be useful for development and testing
of other parts of the SW stack (firmware, kernel) and we would like to
make it broadly available to everyone. We're contributing it as
'experimental', hopefully making it clear that the board does NOT
complies 100% with [1].

The main features included in this emulation are:

 - Based on riscv virt machine type
 - A new memory map as close as virt machine as possible
 - A new virt CPU type rvsp-ref-cpu for server platform compliance
 - AIA
 - PCIe AHCI
 - PCIe NIC
 - No virtio device
 - No fw_cfg device
 - No ACPI table provided
 - Only minimal device tree nodes

[1] https://github.com/riscv-non-isa/riscv-server-platform

Signed-off-by: Fei Wu <fei2.wu@intel.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 configs/devices/riscv64-softmmu/default.mak |    1 +
 hw/riscv/Kconfig                            |   14 +
 hw/riscv/meson.build                        |    1 +
 hw/riscv/server_platform_ref.c              | 1276 +++++++++++++++++++
 4 files changed, 1292 insertions(+)
 create mode 100644 hw/riscv/server_platform_ref.c

diff --git a/configs/devices/riscv64-softmmu/default.mak b/configs/devices/riscv64-softmmu/default.mak
index e485bbd1a3..e6075a7113 100644
--- a/configs/devices/riscv64-softmmu/default.mak
+++ b/configs/devices/riscv64-softmmu/default.mak
@@ -9,6 +9,7 @@
 # CONFIG_SIFIVE_E=n
 # CONFIG_SIFIVE_U=n
 # CONFIG_RISCV_VIRT=n
+# CONFIG_SERVER_PLATFORM_REF=n
 # CONFIG_MICROCHIP_PFSOC=n
 # CONFIG_SHAKTI_C=n
 # CONFIG_XIANGSHAN_KUNMINGHU=n
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index fc9c35bd98..6a5085c7a5 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -69,6 +69,20 @@ config RISCV_VIRT
     select ACPI
     select ACPI_PCI
 
+config SERVER_PLATFORM_REF
+    bool
+    default y
+    depends on RISCV64
+    select RISCV_NUMA
+    select GOLDFISH_RTC
+    select PCI
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select PFLASH_CFI01
+    select SERIAL
+    select RISCV_ACLINT
+    select RISCV_APLIC
+    select RISCV_IMSIC
+
 config SHAKTI_C
     bool
     default y
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 2a8d5b136c..0daf77e887 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -4,6 +4,7 @@ riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
 riscv_ss.add(files('riscv_hart.c'))
 riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
 riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
+riscv_ss.add(when: 'CONFIG_SERVER_PLATFORM_REF', if_true: files('server_platform_ref.c'))
 riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
diff --git a/hw/riscv/server_platform_ref.c b/hw/riscv/server_platform_ref.c
new file mode 100644
index 0000000000..ef2891a9d7
--- /dev/null
+++ b/hw/riscv/server_platform_ref.c
@@ -0,0 +1,1276 @@
+/*
+ * QEMU RISC-V Server Platform (RVSP) Reference Board
+ *
+ * Copyright (c) 2024 Intel, Inc.
+ * Copyright (c) 2025 Ventana Micro Systems Inc.
+ *
+ * This board is compliant RISC-V Server platform specification and leveraging
+ * a lot of riscv virt code.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qapi/error.h"
+#include "qapi/qapi-visit-common.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
+#include "hw/char/serial.h"
+#include "hw/block/flash.h"
+#include "hw/ide/pci.h"
+#include "hw/ide/ahci-pci.h"
+#include "hw/pci/pci.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/core/sysbus-fdt.h"
+#include "hw/riscv/riscv_hart.h"
+#include "hw/riscv/boot.h"
+#include "hw/riscv/numa.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/intc/riscv_aplic.h"
+#include "hw/intc/riscv_imsic.h"
+#include "chardev/char.h"
+#include "hw/char/serial-mm.h"
+#include "system/device_tree.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "system/tcg.h"
+#include "system/qtest.h"
+#include "target/riscv/cpu.h"
+#include "target/riscv/pmu.h"
+#include "net/net.h"
+
+#define RVSP_CPUS_MAX_BITS             9
+#define RVSP_CPUS_MAX                  (1 << RVSP_CPUS_MAX_BITS)
+#define RVSP_SOCKETS_MAX_BITS          2
+#define RVSP_SOCKETS_MAX               (1 << RVSP_SOCKETS_MAX_BITS)
+
+#define RVSP_IRQCHIP_NUM_MSIS 255
+#define RVSP_IRQCHIP_NUM_SOURCES 96
+#define RVSP_IRQCHIP_NUM_PRIO_BITS 3
+#define RVSP_IRQCHIP_MAX_GUESTS_BITS 3
+#define RVSP_IRQCHIP_MAX_GUESTS ((1U << RVSP_IRQCHIP_MAX_GUESTS_BITS) - 1U)
+
+#define FDT_PCI_ADDR_CELLS    3
+#define FDT_PCI_INT_CELLS     1
+#define FDT_APLIC_INT_CELLS   2
+#define FDT_IMSIC_INT_CELLS   0
+#define FDT_MAX_INT_CELLS     2
+#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+                                 1 + FDT_MAX_INT_CELLS)
+#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+                                 1 + FDT_APLIC_INT_CELLS)
+
+#define NUM_SATA_PORTS  6
+
+#define SYSCON_RESET     0x1
+#define SYSCON_POWEROFF  0x2
+
+#define TYPE_RVSP_REF_MACHINE MACHINE_TYPE_NAME("rvsp-ref")
+OBJECT_DECLARE_SIMPLE_TYPE(RVSPMachineState, RVSP_REF_MACHINE)
+
+struct RVSPMachineState {
+    /*< private >*/
+    MachineState parent;
+
+    /*< public >*/
+    Notifier machine_done;
+    RISCVHartArrayState soc[RVSP_SOCKETS_MAX];
+    DeviceState *irqchip[RVSP_SOCKETS_MAX];
+    PFlashCFI01 *flash[2];
+
+    int fdt_size;
+    int aia_guests;
+    const MemMapEntry *memmap;
+};
+
+enum {
+    RVSP_DEBUG,
+    RVSP_MROM,
+    RVSP_RESET_SYSCON,
+    RVSP_RTC,
+    RVSP_ACLINT,
+    RVSP_APLIC_M,
+    RVSP_APLIC_S,
+    RVSP_UART0,
+    RVSP_IMSIC_M,
+    RVSP_IMSIC_S,
+    RVSP_FLASH,
+    RVSP_DRAM,
+    RVSP_PCIE_MMIO,
+    RVSP_PCIE_PIO,
+    RVSP_PCIE_ECAM,
+    RVSP_PCIE_MMIO_HIGH
+};
+
+enum {
+    RVSP_UART0_IRQ = 10,
+    RVSP_RTC_IRQ = 11,
+    RVSP_PCIE_IRQ = 0x20, /* 32 to 35 */
+};
+
+/*
+ * The server soc reference machine physical address space used by some of the
+ * devices namely ACLINT, APLIC and IMSIC depend on number of Sockets, number
+ * of CPUs, and number of IMSIC guest files.
+ *
+ * Various limits defined by RVSP_SOCKETS_MAX_BITS, RVSP_CPUS_MAX_BITS, and
+ * RVSP_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization of server soc
+ * reference machine physical address space.
+ */
+
+#define RVSP_IMSIC_GROUP_MAX_SIZE      (1U << IMSIC_MMIO_GROUP_MIN_SHIFT)
+#if RVSP_IMSIC_GROUP_MAX_SIZE < \
+    IMSIC_GROUP_SIZE(RVSP_CPUS_MAX_BITS, RVSP_IRQCHIP_MAX_GUESTS_BITS)
+#error "Can't accomodate single IMSIC group in address space"
+#endif
+
+#define RVSP_IMSIC_MAX_SIZE            (RVSP_SOCKETS_MAX * \
+                                        RVSP_IMSIC_GROUP_MAX_SIZE)
+#if 0x4000000 < RVSP_IMSIC_MAX_SIZE
+#error "Can't accomodate all IMSIC groups in address space"
+#endif
+
+static const MemMapEntry rvsp_ref_memmap[] = {
+    [RVSP_DEBUG] =          {        0x0,         0x100 },
+    [RVSP_MROM] =           {     0x1000,        0xf000 },
+    [RVSP_RESET_SYSCON] =   {   0x100000,        0x1000 },
+    [RVSP_RTC] =            {   0x101000,        0x1000 },
+    [RVSP_ACLINT] =         {  0x2000000,       0x10000 },
+    [RVSP_PCIE_PIO] =       {  0x3000000,       0x10000 },
+    [RVSP_APLIC_M] =        {  0xc000000, APLIC_SIZE(RVSP_CPUS_MAX) },
+    [RVSP_APLIC_S] =        {  0xd000000, APLIC_SIZE(RVSP_CPUS_MAX) },
+    [RVSP_UART0] =          { 0x10000000,         0x100 },
+    [RVSP_FLASH] =          { 0x20000000,     0x4000000 },
+    [RVSP_IMSIC_M] =        { 0x24000000, RVSP_IMSIC_MAX_SIZE },
+    [RVSP_IMSIC_S] =        { 0x28000000, RVSP_IMSIC_MAX_SIZE },
+    [RVSP_PCIE_ECAM] =      { 0x30000000,    0x10000000 },
+    [RVSP_PCIE_MMIO] =      { 0x40000000,    0x40000000 },
+    [RVSP_DRAM] =           { 0x80000000, 0xff80000000ull },
+    [RVSP_PCIE_MMIO_HIGH] = { 0x10000000000ull, 0x10000000000ull },
+};
+
+#define RVSP_FLASH_SECTOR_SIZE (256 * KiB)
+
+static PFlashCFI01 *rvsp_flash_create(RVSPMachineState *s,
+                                      const char *name,
+                                      const char *alias_prop_name)
+{
+    /*
+     * Create a single flash device.  We use the same parameters as
+     * the flash devices on the ARM virt board.
+     */
+    DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
+
+    qdev_prop_set_uint64(dev, "sector-length", RVSP_FLASH_SECTOR_SIZE);
+    qdev_prop_set_uint8(dev, "width", 4);
+    qdev_prop_set_uint8(dev, "device-width", 2);
+    qdev_prop_set_bit(dev, "big-endian", false);
+    qdev_prop_set_uint16(dev, "id0", 0x89);
+    qdev_prop_set_uint16(dev, "id1", 0x18);
+    qdev_prop_set_uint16(dev, "id2", 0x00);
+    qdev_prop_set_uint16(dev, "id3", 0x00);
+    qdev_prop_set_string(dev, "name", name);
+
+    object_property_add_child(OBJECT(s), name, OBJECT(dev));
+    object_property_add_alias(OBJECT(s), alias_prop_name,
+                              OBJECT(dev), "drive");
+
+    return PFLASH_CFI01(dev);
+}
+
+static void rvsp_flash_map(PFlashCFI01 *flash,
+                           hwaddr base, hwaddr size,
+                           MemoryRegion *sysmem)
+{
+    DeviceState *dev = DEVICE(flash);
+
+    assert(QEMU_IS_ALIGNED(size, RVSP_FLASH_SECTOR_SIZE));
+    assert(size / RVSP_FLASH_SECTOR_SIZE <= UINT32_MAX);
+    qdev_prop_set_uint32(dev, "num-blocks", size / RVSP_FLASH_SECTOR_SIZE);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    memory_region_add_subregion(sysmem, base,
+                                sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
+                                                       0));
+}
+
+static void rvsp_flash_maps(RVSPMachineState *s,
+                            MemoryRegion *sysmem)
+{
+    hwaddr flashsize = rvsp_ref_memmap[RVSP_FLASH].size / 2;
+    hwaddr flashbase = rvsp_ref_memmap[RVSP_FLASH].base;
+
+    rvsp_flash_map(s->flash[0], flashbase, flashsize, sysmem);
+    rvsp_flash_map(s->flash[1], flashbase + flashsize, flashsize, sysmem);
+}
+
+static void create_pcie_irq_map(RVSPMachineState *s, void *fdt, char *nodename,
+                                uint32_t irqchip_phandle)
+{
+    int pin, dev;
+    uint32_t irq_map_stride = 0;
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
+                          FDT_MAX_INT_MAP_WIDTH] = {};
+    uint32_t *irq_map = full_irq_map;
+
+    /*
+     * This code creates a standard swizzle of interrupts such that
+     * each device's first interrupt is based on it's PCI_SLOT number.
+     * (See pci_swizzle_map_irq_fn())
+     *
+     * We only need one entry per interrupt in the table (not one per
+     * possible slot) seeing the interrupt-map-mask will allow the table
+     * to wrap to any number of devices.
+     */
+    for (dev = 0; dev < PCI_NUM_PINS; dev++) {
+        int devfn = dev * 0x8;
+
+        for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr = RVSP_PCIE_IRQ +
+                         ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
+            int i = 0;
+
+            /* Fill PCI address cells */
+            irq_map[i] = cpu_to_be32(devfn << 8);
+            i += FDT_PCI_ADDR_CELLS;
+
+            /* Fill PCI Interrupt cells */
+            irq_map[i] = cpu_to_be32(pin + 1);
+            i += FDT_PCI_INT_CELLS;
+
+            /* Fill interrupt controller phandle and cells */
+            irq_map[i++] = cpu_to_be32(irqchip_phandle);
+            irq_map[i++] = cpu_to_be32(irq_nr);
+            irq_map[i++] = cpu_to_be32(0x4);
+
+            if (!irq_map_stride) {
+                irq_map_stride = i;
+            }
+            irq_map += irq_map_stride;
+        }
+    }
+
+    qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
+                     PCI_NUM_PINS * PCI_NUM_PINS *
+                     irq_map_stride * sizeof(uint32_t));
+
+    qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
+                           0x1800, 0, 0, 0x7);
+}
+
+static void create_fdt_socket_cpus(RVSPMachineState *s, int socket,
+                                   char *clust_name, uint32_t *phandle,
+                                   uint32_t *intc_phandles)
+{
+    int cpu;
+    uint32_t cpu_phandle;
+    MachineState *ms = MACHINE(s);
+    bool is_32_bit = riscv_is_32bit(&s->soc[0]);
+    int8_t satp_mode_max;
+
+    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
+        RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu];
+        satp_mode_max = cpu_ptr->cfg.max_satp_mode;
+        g_autofree char *cpu_name = NULL;
+        g_autofree char *core_name = NULL;
+        g_autofree char *intc_name = NULL;
+        g_autofree char *sv_name = NULL;
+
+        cpu_phandle = (*phandle)++;
+
+        cpu_name = g_strdup_printf("/cpus/cpu@%d",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_add_subnode(ms->fdt, cpu_name);
+
+        if (satp_mode_max != -1) {
+            sv_name = g_strdup_printf("riscv,%s",
+                                      satp_mode_str(satp_mode_max, is_32_bit));
+            qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name);
+        }
+
+        riscv_isa_write_fdt(cpu_ptr, ms->fdt, cpu_name);
+
+        if (cpu_ptr->cfg.ext_zicbom) {
+            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size",
+                                  cpu_ptr->cfg.cbom_blocksize);
+        }
+
+        if (cpu_ptr->cfg.ext_zicboz) {
+            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cboz-block-size",
+                                  cpu_ptr->cfg.cboz_blocksize);
+        }
+
+        if (cpu_ptr->cfg.ext_zicbop) {
+            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbop-block-size",
+                                  cpu_ptr->cfg.cbop_blocksize);
+        }
+
+        qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv");
+        qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay");
+        qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_setprop_string(ms->fdt, cpu_name, "device_type", "cpu");
+        riscv_socket_fdt_write_id(ms, cpu_name, socket);
+        qemu_fdt_setprop_cell(ms->fdt, cpu_name, "phandle", cpu_phandle);
+
+        intc_phandles[cpu] = (*phandle)++;
+
+        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
+        qemu_fdt_add_subnode(ms->fdt, intc_name);
+        qemu_fdt_setprop_cell(ms->fdt, intc_name, "phandle",
+            intc_phandles[cpu]);
+        qemu_fdt_setprop_string(ms->fdt, intc_name, "compatible",
+            "riscv,cpu-intc");
+        qemu_fdt_setprop(ms->fdt, intc_name, "interrupt-controller", NULL, 0);
+        qemu_fdt_setprop_cell(ms->fdt, intc_name, "#interrupt-cells", 1);
+
+        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+        qemu_fdt_add_subnode(ms->fdt, core_name);
+        qemu_fdt_setprop_cell(ms->fdt, core_name, "cpu", cpu_phandle);
+    }
+}
+
+static void create_fdt_socket_memory(RVSPMachineState *s,
+                                     const MemMapEntry *memmap, int socket)
+{
+    g_autofree char *mem_name = NULL;
+    hwaddr addr, size;
+    MachineState *ms = MACHINE(s);
+
+    addr = memmap[RVSP_DRAM].base + riscv_socket_mem_offset(ms, socket);
+    size = riscv_socket_mem_size(ms, socket);
+    mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
+    qemu_fdt_add_subnode(ms->fdt, mem_name);
+    qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg",
+        addr >> 32, addr, size >> 32, size);
+    qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory");
+    riscv_socket_fdt_write_id(ms, mem_name, socket);
+}
+
+static void create_fdt_socket_aclint(RVSPMachineState *s,
+                                     const MemMapEntry *memmap, int socket,
+                                     uint32_t *intc_phandles)
+{
+    int cpu;
+    g_autofree char *name = NULL;
+    hwaddr addr, size;
+    uint32_t aclint_cells_size;
+    g_autofree uint32_t *aclint_mtimer_cells = NULL;
+    MachineState *ms = MACHINE(s);
+
+    aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
+
+    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+        aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
+    }
+    aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
+
+    addr = memmap[RVSP_ACLINT].base + RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket;
+    size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
+
+    name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx, addr);
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible",
+        "riscv,aclint-mtimer");
+    qemu_fdt_setprop_cells(ms->fdt, name, "reg",
+        0x0, addr + RISCV_ACLINT_DEFAULT_MTIME,
+        0x0, size - RISCV_ACLINT_DEFAULT_MTIME,
+        0x0, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
+        0x0, RISCV_ACLINT_DEFAULT_MTIME);
+    qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
+        aclint_mtimer_cells, aclint_cells_size);
+    riscv_socket_fdt_write_id(ms, name, socket);
+}
+
+static uint32_t imsic_num_bits(uint32_t count)
+{
+    uint32_t ret = 0;
+
+    while (BIT(ret) < count) {
+        ret++;
+    }
+
+    return ret;
+}
+
+static void create_fdt_one_imsic(RVSPMachineState *s, hwaddr base_addr,
+                                 uint32_t *intc_phandles, uint32_t msi_phandle,
+                                 bool m_mode, uint32_t imsic_guest_bits)
+{
+    int cpu, socket;
+    g_autofree char *imsic_name = NULL;
+    MachineState *ms = MACHINE(s);
+    int socket_count = riscv_socket_count(ms);
+    uint32_t imsic_max_hart_per_socket, imsic_addr, imsic_size;
+    g_autofree uint32_t *imsic_cells = NULL;
+    g_autofree uint32_t *imsic_regs = NULL;
+
+    imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2);
+    imsic_regs = g_new0(uint32_t, socket_count * 4);
+
+    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+        imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        imsic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
+    }
+
+    imsic_max_hart_per_socket = 0;
+    for (socket = 0; socket < socket_count; socket++) {
+        imsic_addr = base_addr + socket * RVSP_IMSIC_GROUP_MAX_SIZE;
+        imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
+                     s->soc[socket].num_harts;
+        imsic_regs[socket * 4 + 0] = 0;
+        imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr);
+        imsic_regs[socket * 4 + 2] = 0;
+        imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size);
+        if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
+            imsic_max_hart_per_socket = s->soc[socket].num_harts;
+        }
+    }
+
+    imsic_name = g_strdup_printf("/soc/imsics@%lx", (unsigned long)base_addr);
+    qemu_fdt_add_subnode(ms->fdt, imsic_name);
+    qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", "riscv,imsics");
+    qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells",
+                          FDT_IMSIC_INT_CELLS);
+    qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0);
+    qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended",
+                     imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2);
+    qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs,
+                     socket_count * sizeof(uint32_t) * 4);
+    qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids",
+                     RVSP_IRQCHIP_NUM_MSIS);
+
+    if (imsic_guest_bits) {
+        qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,guest-index-bits",
+                              imsic_guest_bits);
+    }
+
+    if (socket_count > 1) {
+        qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits",
+                              imsic_num_bits(imsic_max_hart_per_socket));
+        qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits",
+                              imsic_num_bits(socket_count));
+        qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift",
+                              IMSIC_MMIO_GROUP_MIN_SHIFT);
+    }
+    qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle);
+}
+
+static void create_fdt_imsic(RVSPMachineState *s, const MemMapEntry *memmap,
+                             uint32_t *phandle, uint32_t *intc_phandles,
+                             uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
+{
+    *msi_m_phandle = (*phandle)++;
+    *msi_s_phandle = (*phandle)++;
+
+    /* M-level IMSIC node */
+    create_fdt_one_imsic(s, memmap[RVSP_IMSIC_M].base, intc_phandles,
+                         *msi_m_phandle, true, 0);
+
+    /* S-level IMSIC node */
+    create_fdt_one_imsic(s, memmap[RVSP_IMSIC_S].base, intc_phandles,
+                         *msi_s_phandle, false,
+                         imsic_num_bits(s->aia_guests + 1));
+
+}
+
+static void create_fdt_one_aplic(RVSPMachineState *s, int socket,
+                                 unsigned long aplic_addr, uint32_t aplic_size,
+                                 uint32_t msi_phandle,
+                                 uint32_t *intc_phandles,
+                                 uint32_t aplic_phandle,
+                                 uint32_t aplic_child_phandle,
+                                 bool m_mode, int num_harts)
+{
+    int cpu;
+    g_autofree char *aplic_name = NULL;
+    g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2);
+    MachineState *ms = MACHINE(s);
+
+    aplic_cells = g_new0(uint32_t, num_harts * 2);
+
+    for (cpu = 0; cpu < num_harts; cpu++) {
+        aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
+    }
+
+    aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
+    qemu_fdt_add_subnode(ms->fdt, aplic_name);
+    qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic");
+    qemu_fdt_setprop_cell(ms->fdt, aplic_name,
+                          "#interrupt-cells", FDT_APLIC_INT_CELLS);
+    qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
+
+    qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle);
+
+    qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg",
+                           0x0, aplic_addr, 0x0, aplic_size);
+    qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
+                          RVSP_IRQCHIP_NUM_SOURCES);
+
+    if (aplic_child_phandle) {
+        qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
+                              aplic_child_phandle);
+        qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate",
+                               aplic_child_phandle, 0x1,
+                               RVSP_IRQCHIP_NUM_SOURCES);
+    }
+
+    riscv_socket_fdt_write_id(ms, aplic_name, socket);
+    qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle);
+}
+
+static void create_fdt_socket_aplic(RVSPMachineState *s,
+                                    const MemMapEntry *memmap, int socket,
+                                    uint32_t msi_m_phandle,
+                                    uint32_t msi_s_phandle,
+                                    uint32_t *phandle,
+                                    uint32_t *intc_phandles,
+                                    uint32_t *aplic_phandles,
+                                    int num_harts)
+{
+    unsigned long aplic_addr;
+    uint32_t aplic_m_phandle, aplic_s_phandle;
+
+    aplic_m_phandle = (*phandle)++;
+    aplic_s_phandle = (*phandle)++;
+
+    /* M-level APLIC node */
+    aplic_addr = memmap[RVSP_APLIC_M].base + memmap[RVSP_APLIC_M].size * socket;
+    create_fdt_one_aplic(s, socket, aplic_addr, memmap[RVSP_APLIC_M].size,
+                         msi_m_phandle, intc_phandles,
+                         aplic_m_phandle, aplic_s_phandle,
+                         true, num_harts);
+
+    /* S-level APLIC node */
+    aplic_addr = memmap[RVSP_APLIC_S].base + memmap[RVSP_APLIC_S].size * socket;
+    create_fdt_one_aplic(s, socket, aplic_addr, memmap[RVSP_APLIC_S].size,
+                         msi_s_phandle, intc_phandles,
+                         aplic_s_phandle, 0,
+                         false, num_harts);
+
+    aplic_phandles[socket] = aplic_s_phandle;
+}
+
+static void create_fdt_pmu(RVSPMachineState *s)
+{
+    g_autofree char *pmu_name = g_strdup_printf("/pmu");
+    MachineState *ms = MACHINE(s);
+    RISCVCPU hart = s->soc[0].harts[0];
+
+    qemu_fdt_add_subnode(ms->fdt, pmu_name);
+    qemu_fdt_setprop_string(ms->fdt, pmu_name, "compatible", "riscv,pmu");
+    riscv_pmu_generate_fdt_node(ms->fdt, hart.pmu_avail_ctrs, pmu_name);
+}
+
+static void create_fdt_sockets(RVSPMachineState *s, const MemMapEntry *memmap,
+                               uint32_t *phandle,
+                               uint32_t *irq_mmio_phandle,
+                               uint32_t *irq_pcie_phandle,
+                               uint32_t *msi_pcie_phandle)
+{
+    int socket, phandle_pos;
+    MachineState *ms = MACHINE(s);
+    uint32_t msi_m_phandle = 0, msi_s_phandle = 0;
+    uint32_t xplic_phandles[MAX_NODES];
+    g_autofree uint32_t *intc_phandles = NULL;
+    int socket_count = riscv_socket_count(ms);
+
+    qemu_fdt_add_subnode(ms->fdt, "/cpus");
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency",
+                          RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
+
+    intc_phandles = g_new0(uint32_t, ms->smp.cpus);
+
+    phandle_pos = ms->smp.cpus;
+    for (socket = (socket_count - 1); socket >= 0; socket--) {
+        g_autofree char *clust_name = NULL;
+        phandle_pos -= s->soc[socket].num_harts;
+
+        clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
+        qemu_fdt_add_subnode(ms->fdt, clust_name);
+
+        create_fdt_socket_cpus(s, socket, clust_name, phandle,
+                               &intc_phandles[phandle_pos]);
+
+        create_fdt_socket_memory(s, memmap, socket);
+
+        create_fdt_socket_aclint(s, memmap, socket,
+            &intc_phandles[phandle_pos]);
+    }
+
+    create_fdt_imsic(s, memmap, phandle, intc_phandles,
+        &msi_m_phandle, &msi_s_phandle);
+    *msi_pcie_phandle = msi_s_phandle;
+
+    phandle_pos = ms->smp.cpus;
+    for (socket = (socket_count - 1); socket >= 0; socket--) {
+        phandle_pos -= s->soc[socket].num_harts;
+
+        create_fdt_socket_aplic(s, memmap, socket,
+                                msi_m_phandle, msi_s_phandle, phandle,
+                                &intc_phandles[phandle_pos],
+                                xplic_phandles,
+                                s->soc[socket].num_harts);
+    }
+
+    for (socket = 0; socket < socket_count; socket++) {
+        if (socket == 0) {
+            *irq_mmio_phandle = xplic_phandles[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
+        }
+        if (socket == 1) {
+            *irq_pcie_phandle = xplic_phandles[socket];
+        }
+    }
+
+    riscv_socket_fdt_write_distance_matrix(ms);
+}
+
+static void create_fdt_pcie(RVSPMachineState *s, const MemMapEntry *memmap,
+                            uint32_t irq_pcie_phandle,
+                            uint32_t msi_pcie_phandle)
+{
+    g_autofree char *name = NULL;
+    MachineState *ms = MACHINE(s);
+
+    name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
+                           memmap[RVSP_PCIE_ECAM].base);
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
+        FDT_PCI_ADDR_CELLS);
+    qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
+        FDT_PCI_INT_CELLS);
+    qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible",
+        "pci-host-ecam-generic");
+    qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
+    qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
+    qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
+        memmap[RVSP_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
+    qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
+    qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle);
+    qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0,
+        memmap[RVSP_PCIE_ECAM].base, 0, memmap[RVSP_PCIE_ECAM].size);
+    qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
+        1, FDT_PCI_RANGE_IOPORT, 2, 0,
+        2, memmap[RVSP_PCIE_PIO].base, 2, memmap[RVSP_PCIE_PIO].size,
+        1, FDT_PCI_RANGE_MMIO,
+        2, memmap[RVSP_PCIE_MMIO].base,
+        2, memmap[RVSP_PCIE_MMIO].base, 2, memmap[RVSP_PCIE_MMIO].size,
+        1, FDT_PCI_RANGE_MMIO_64BIT,
+        2, memmap[RVSP_PCIE_MMIO_HIGH].base,
+        2, memmap[RVSP_PCIE_MMIO_HIGH].base, 2,
+           memmap[RVSP_PCIE_MMIO_HIGH].size);
+
+    create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
+}
+
+static void create_fdt_reset(RVSPMachineState *s, const MemMapEntry *memmap,
+                             uint32_t *phandle)
+{
+    char *name;
+    uint32_t test_phandle;
+    MachineState *ms = MACHINE(s);
+
+    test_phandle = (*phandle)++;
+    name = g_strdup_printf("/soc/reset_syscon@%"HWADDR_PRIx,
+                           memmap[RVSP_RESET_SYSCON].base);
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon");
+    qemu_fdt_setprop_cells(ms->fdt, name, "reg",
+        0x0, memmap[RVSP_RESET_SYSCON].base,
+        0x0, memmap[RVSP_RESET_SYSCON].size);
+    qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle);
+    test_phandle = qemu_fdt_get_phandle(ms->fdt, name);
+    g_free(name);
+
+    name = g_strdup_printf("/soc/reboot");
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
+    qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(ms->fdt, name, "value", SYSCON_RESET);
+    g_free(name);
+
+    name = g_strdup_printf("/soc/poweroff");
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
+    qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(ms->fdt, name, "value", SYSCON_POWEROFF);
+    g_free(name);
+}
+
+static void create_fdt_uart(RVSPMachineState *s, const MemMapEntry *memmap,
+                            uint32_t irq_mmio_phandle)
+{
+    g_autofree char *name = NULL;
+    MachineState *ms = MACHINE(s);
+
+    name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
+                           memmap[RVSP_UART0].base);
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a");
+    qemu_fdt_setprop_cells(ms->fdt, name, "reg",
+        0x0, memmap[RVSP_UART0].base,
+        0x0, memmap[RVSP_UART0].size);
+    qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400);
+    qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle);
+    qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RVSP_UART0_IRQ, 0x4);
+
+    qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
+}
+
+static void create_fdt_rtc(RVSPMachineState *s, const MemMapEntry *memmap,
+                           uint32_t irq_mmio_phandle)
+{
+    g_autofree char *name = NULL;
+    MachineState *ms = MACHINE(s);
+
+    name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx, memmap[RVSP_RTC].base);
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible",
+        "google,goldfish-rtc");
+    qemu_fdt_setprop_cells(ms->fdt, name, "reg",
+        0x0, memmap[RVSP_RTC].base, 0x0, memmap[RVSP_RTC].size);
+    qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
+        irq_mmio_phandle);
+    qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RVSP_RTC_IRQ, 0x4);
+}
+
+static void create_fdt_flash(RVSPMachineState *s, const MemMapEntry *memmap)
+{
+    MachineState *ms = MACHINE(s);
+    hwaddr flashsize = rvsp_ref_memmap[RVSP_FLASH].size / 2;
+    hwaddr flashbase = rvsp_ref_memmap[RVSP_FLASH].base;
+    g_autofree char *name = g_strdup_printf("/flash@%"HWADDR_PRIx, flashbase);
+
+    qemu_fdt_add_subnode(ms->fdt, name);
+    qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-flash");
+    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
+                                 2, flashbase, 2, flashsize,
+                                 2, flashbase + flashsize, 2, flashsize);
+    qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4);
+}
+
+static void finalize_fdt(RVSPMachineState *s)
+{
+    uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1;
+    uint32_t irq_pcie_phandle = 1;
+
+    create_fdt_sockets(s, rvsp_ref_memmap, &phandle, &irq_mmio_phandle,
+                       &irq_pcie_phandle, &msi_pcie_phandle);
+
+    create_fdt_pcie(s, rvsp_ref_memmap, irq_pcie_phandle, msi_pcie_phandle);
+
+    create_fdt_reset(s, rvsp_ref_memmap, &phandle);
+
+    create_fdt_uart(s, rvsp_ref_memmap, irq_mmio_phandle);
+
+    create_fdt_rtc(s, rvsp_ref_memmap, irq_mmio_phandle);
+}
+
+static void create_fdt(RVSPMachineState *s, const MemMapEntry *memmap)
+{
+    MachineState *ms = MACHINE(s);
+    uint8_t rng_seed[32];
+
+    ms->fdt = create_device_tree(&s->fdt_size);
+    if (!ms->fdt) {
+        error_report("create_device_tree() failed");
+        exit(1);
+    }
+
+    qemu_fdt_setprop_string(ms->fdt, "/", "model", "riscv-rvsp-ref,qemu");
+    qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "riscv-rvsp-ref");
+    qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
+
+    /*
+     * This versioning scheme is for informing platform fw only. It is neither:
+     * - A QEMU versioned machine type; a given version of QEMU will emulate
+     *   a given version of the platform.
+     * - A reflection of level of server platform support provided.
+     *
+     * machine-version-major: updated when changes breaking fw compatibility
+     *                        are introduced.
+     * machine-version-minor: updated when features are added that don't break
+     *                        fw compatibility.
+     *
+     * It's the same as the scheme in arm sbsa-ref.
+     */
+    qemu_fdt_setprop_cell(ms->fdt, "/", "machine-version-major", 0);
+    qemu_fdt_setprop_cell(ms->fdt, "/", "machine-version-minor", 0);
+
+    qemu_fdt_add_subnode(ms->fdt, "/soc");
+    qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0);
+    qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus");
+    qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2);
+
+    qemu_fdt_add_subnode(ms->fdt, "/chosen");
+
+    /* Pass seed to RNG */
+    qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+    qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed",
+                     rng_seed, sizeof(rng_seed));
+
+    create_fdt_flash(s, memmap);
+    create_fdt_pmu(s);
+
+}
+
+static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
+                                          DeviceState *irqchip,
+                                          RVSPMachineState *s)
+{
+    DeviceState *dev;
+    PCIHostState *pci;
+    PCIDevice *pdev_ahci;
+    AHCIPCIState *ich9;
+    DriveInfo *hd[NUM_SATA_PORTS];
+    MemoryRegion *ecam_alias, *ecam_reg;
+    MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
+    hwaddr ecam_base = rvsp_ref_memmap[RVSP_PCIE_ECAM].base;
+    hwaddr ecam_size = rvsp_ref_memmap[RVSP_PCIE_ECAM].size;
+    hwaddr mmio_base = rvsp_ref_memmap[RVSP_PCIE_MMIO].base;
+    hwaddr mmio_size = rvsp_ref_memmap[RVSP_PCIE_MMIO].size;
+    hwaddr high_mmio_base = rvsp_ref_memmap[RVSP_PCIE_MMIO_HIGH].base;
+    hwaddr high_mmio_size = rvsp_ref_memmap[RVSP_PCIE_MMIO_HIGH].size;
+    hwaddr pio_base = rvsp_ref_memmap[RVSP_PCIE_PIO].base;
+    hwaddr pio_size = rvsp_ref_memmap[RVSP_PCIE_PIO].size;
+    MachineClass *mc = MACHINE_GET_CLASS(s);
+    qemu_irq irq;
+    int i;
+
+    dev = qdev_new(TYPE_GPEX_HOST);
+
+    /* Set GPEX object properties for the rvsp ref machine */
+    object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_BASE,
+                            ecam_base, NULL);
+    object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_SIZE,
+                            ecam_size, NULL);
+    object_property_set_uint(OBJECT(GPEX_HOST(dev)),
+                             PCI_HOST_BELOW_4G_MMIO_BASE,
+                             mmio_base, NULL);
+    object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_BELOW_4G_MMIO_SIZE,
+                            mmio_size, NULL);
+    object_property_set_uint(OBJECT(GPEX_HOST(dev)),
+                             PCI_HOST_ABOVE_4G_MMIO_BASE,
+                             high_mmio_base, NULL);
+    object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ABOVE_4G_MMIO_SIZE,
+                            high_mmio_size, NULL);
+    object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_BASE,
+                            pio_base, NULL);
+    object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_SIZE,
+                            pio_size, NULL);
+
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    ecam_alias = g_new0(MemoryRegion, 1);
+    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+                             ecam_reg, 0, ecam_size);
+    memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
+
+    mmio_alias = g_new0(MemoryRegion, 1);
+    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+                             mmio_reg, mmio_base, mmio_size);
+    memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
+
+    /* Map high MMIO space */
+    high_mmio_alias = g_new0(MemoryRegion, 1);
+    memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
+                             mmio_reg, high_mmio_base, high_mmio_size);
+    memory_region_add_subregion(get_system_memory(), high_mmio_base,
+                                high_mmio_alias);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
+
+    for (i = 0; i < PCI_NUM_PINS; i++) {
+        irq = qdev_get_gpio_in(irqchip, RVSP_PCIE_IRQ + i);
+
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+        gpex_set_irq_num(GPEX_HOST(dev), i, RVSP_PCIE_IRQ + i);
+    }
+
+    pci = PCI_HOST_BRIDGE(dev);
+    pci_init_nic_devices(pci->bus, mc->default_nic);
+    /* IDE disk setup.  */
+    pdev_ahci = pci_create_simple(pci->bus, -1, TYPE_ICH9_AHCI);
+    ich9 = ICH9_AHCI(pdev_ahci);
+    g_assert(ARRAY_SIZE(hd) == ich9->ahci.ports);
+    ide_drive_get(hd, ich9->ahci.ports);
+    ahci_ide_create_devs(&ich9->ahci, hd);
+
+    GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(GPEX_HOST(dev))->bus;
+    return dev;
+}
+
+static DeviceState *rvsp_ref_create_aia(int aia_guests,
+                                        const MemMapEntry *memmap, int socket,
+                                        int base_hartid, int hart_count)
+{
+    int i;
+    hwaddr addr;
+    uint32_t guest_bits;
+    DeviceState *aplic_s = NULL;
+    DeviceState *aplic_m = NULL;
+    bool msimode = true;
+
+    /* Per-socket M-level IMSICs */
+    addr = memmap[RVSP_IMSIC_M].base +
+           socket * RVSP_IMSIC_GROUP_MAX_SIZE;
+    for (i = 0; i < hart_count; i++) {
+        riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
+                           base_hartid + i, true, 1,
+                           RVSP_IRQCHIP_NUM_MSIS);
+    }
+
+    /* Per-socket S-level IMSICs */
+    guest_bits = imsic_num_bits(aia_guests + 1);
+    addr = memmap[RVSP_IMSIC_S].base + socket * RVSP_IMSIC_GROUP_MAX_SIZE;
+    for (i = 0; i < hart_count; i++) {
+        riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
+                           base_hartid + i, false, 1 + aia_guests,
+                           RVSP_IRQCHIP_NUM_MSIS);
+    }
+
+    /* Per-socket M-level APLIC */
+    aplic_m = riscv_aplic_create(memmap[RVSP_APLIC_M].base +
+                                 socket * memmap[RVSP_APLIC_M].size,
+                                 memmap[RVSP_APLIC_M].size,
+                                 (msimode) ? 0 : base_hartid,
+                                 (msimode) ? 0 : hart_count,
+                                 RVSP_IRQCHIP_NUM_SOURCES,
+                                 RVSP_IRQCHIP_NUM_PRIO_BITS,
+                                 msimode, true, NULL);
+
+    /* Per-socket S-level APLIC */
+    aplic_s = riscv_aplic_create(memmap[RVSP_APLIC_S].base +
+                                 socket * memmap[RVSP_APLIC_S].size,
+                                 memmap[RVSP_APLIC_S].size,
+                                 (msimode) ? 0 : base_hartid,
+                                 (msimode) ? 0 : hart_count,
+                                 RVSP_IRQCHIP_NUM_SOURCES,
+                                 RVSP_IRQCHIP_NUM_PRIO_BITS,
+                                 msimode, false, aplic_m);
+
+    (void)aplic_s;
+    return aplic_m;
+}
+
+static uint64_t rvsp_reset_syscon_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void rvsp_reset_syscon_write(void *opaque, hwaddr addr,
+                                    uint64_t val64, unsigned int size)
+{
+    switch (val64) {
+    case SYSCON_POWEROFF:
+        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        return;
+    case SYSCON_RESET:
+        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        return;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps rvsp_reset_syscon_ops = {
+    .read = rvsp_reset_syscon_read,
+    .write = rvsp_reset_syscon_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static void rvsp_ref_machine_done(Notifier *notifier, void *data)
+{
+    RVSPMachineState *s = container_of(notifier, RVSPMachineState,
+                                       machine_done);
+    const MemMapEntry *memmap = rvsp_ref_memmap;
+    MachineState *machine = MACHINE(s);
+    hwaddr start_addr = memmap[RVSP_DRAM].base;
+    target_ulong firmware_end_addr, kernel_start_addr;
+    const char *firmware_name = riscv_default_firmware_name(&s->soc[0]);
+    uint64_t fdt_load_addr;
+    uint64_t kernel_entry = 0;
+    BlockBackend *pflash_blk0;
+    RISCVBootInfo boot_info;
+
+    /*
+     * An user provided dtb must include everything, including
+     * dynamic sysbus devices. Our FDT needs to be finalized.
+     */
+    if (machine->dtb == NULL) {
+        finalize_fdt(s);
+    }
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+                                                     &start_addr, NULL);
+
+    pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
+    if (pflash_blk0) {
+        if (machine->firmware && !strcmp(machine->firmware, "none")) {
+            /*
+             * Pflash was supplied but bios is none and not KVM guest,
+             * let's overwrite the address we jump to after reset to
+             * the base of the flash.
+             */
+            start_addr = rvsp_ref_memmap[RVSP_FLASH].base;
+        } else {
+            /*
+             * Pflash was supplied but either KVM guest or bios is not none.
+             * In this case, base of the flash would contain S-mode payload.
+             */
+            riscv_setup_firmware_boot(machine);
+            kernel_entry = rvsp_ref_memmap[RVSP_FLASH].base;
+        }
+    }
+
+    riscv_boot_info_init(&boot_info, &s->soc[0]);
+
+    if (machine->kernel_filename && !kernel_entry) {
+        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
+                                                         firmware_end_addr);
+        riscv_load_kernel(machine, &boot_info, kernel_start_addr, true, NULL);
+        kernel_entry = boot_info.image_low_addr;
+    }
+
+    fdt_load_addr = riscv_compute_fdt_addr(memmap[RVSP_DRAM].base,
+                                           memmap[RVSP_DRAM].size,
+                                           machine, &boot_info);
+
+    riscv_load_fdt(fdt_load_addr, machine->fdt);
+
+    /* load the reset vector */
+    riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr,
+                              rvsp_ref_memmap[RVSP_MROM].base,
+                              rvsp_ref_memmap[RVSP_MROM].size, kernel_entry,
+                              fdt_load_addr);
+
+}
+
+static bool rvsp_aclint_allowed(void)
+{
+    return tcg_enabled() || qtest_enabled();
+}
+
+static void rvsp_ref_machine_init(MachineState *machine)
+{
+    const MemMapEntry *memmap = rvsp_ref_memmap;
+    RVSPMachineState *s = RVSP_REF_MACHINE(machine);
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
+    MemoryRegion *reset_syscon_io = g_new(MemoryRegion, 1);
+    DeviceState *mmio_irqchip, *pcie_irqchip;
+    int i, base_hartid, hart_count;
+    int socket_count = riscv_socket_count(machine);
+
+    /* Check socket count limit */
+    if (RVSP_SOCKETS_MAX < socket_count) {
+        error_report("number of sockets/nodes should be less than %d",
+            RVSP_SOCKETS_MAX);
+        exit(1);
+    }
+
+    if (!rvsp_aclint_allowed()) {
+        error_report("'aclint' is only available with TCG acceleration");
+        exit(1);
+    }
+
+    /* Initialize sockets */
+    mmio_irqchip = pcie_irqchip = NULL;
+    for (i = 0; i < socket_count; i++) {
+        g_autofree char *soc_name = g_strdup_printf("soc%d", i);
+
+        if (!riscv_socket_check_hartids(machine, i)) {
+            error_report("discontinuous hartids in socket%d", i);
+            exit(1);
+        }
+
+        base_hartid = riscv_socket_first_hartid(machine, i);
+        if (base_hartid < 0) {
+            error_report("can't find hartid base for socket%d", i);
+            exit(1);
+        }
+
+        hart_count = riscv_socket_hart_count(machine, i);
+        if (hart_count < 0) {
+            error_report("can't find hart count for socket%d", i);
+            exit(1);
+        }
+
+        object_initialize_child(OBJECT(machine), soc_name, &s->soc[i],
+                                TYPE_RISCV_HART_ARRAY);
+        object_property_set_str(OBJECT(&s->soc[i]), "cpu-type",
+                                machine->cpu_type, &error_abort);
+        object_property_set_int(OBJECT(&s->soc[i]), "hartid-base",
+                                base_hartid, &error_abort);
+        object_property_set_int(OBJECT(&s->soc[i]), "num-harts",
+                                hart_count, &error_abort);
+        sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal);
+
+        /* Per-socket ACLINT MTIMER */
+        riscv_aclint_mtimer_create(memmap[RVSP_ACLINT].base +
+                i * RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+            RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+            base_hartid, hart_count,
+            RISCV_ACLINT_DEFAULT_MTIMECMP,
+            RISCV_ACLINT_DEFAULT_MTIME,
+            RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
+
+        /* Per-socket interrupt controller */
+        s->irqchip[i] = rvsp_ref_create_aia(s->aia_guests,
+                                            memmap, i, base_hartid,
+                                            hart_count);
+
+        /* Try to use different IRQCHIP instance based device type */
+        if (i == 0) {
+            mmio_irqchip = s->irqchip[i];
+            pcie_irqchip = s->irqchip[i];
+        }
+        if (i == 1) {
+            pcie_irqchip = s->irqchip[i];
+        }
+    }
+
+    s->memmap = rvsp_ref_memmap;
+
+    /* register system main memory (actual RAM) */
+    memory_region_add_subregion(system_memory, memmap[RVSP_DRAM].base,
+        machine->ram);
+
+    /* boot rom */
+    memory_region_init_rom(mask_rom, NULL, "riscv_rvsp_ref_board.mrom",
+                           memmap[RVSP_MROM].size, &error_fatal);
+    memory_region_add_subregion(system_memory, memmap[RVSP_MROM].base,
+                                mask_rom);
+
+    memory_region_init_io(reset_syscon_io, NULL, &rvsp_reset_syscon_ops,
+                          NULL, "reset_syscon_io",
+                          memmap[RVSP_RESET_SYSCON].size);
+    memory_region_add_subregion(system_memory,
+                                memmap[RVSP_RESET_SYSCON].base,
+                                reset_syscon_io);
+
+    gpex_pcie_init(system_memory, pcie_irqchip, s);
+
+    serial_mm_init(system_memory, memmap[RVSP_UART0].base,
+        0, qdev_get_gpio_in(mmio_irqchip, RVSP_UART0_IRQ), 399193,
+        serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
+    sysbus_create_simple("goldfish_rtc", memmap[RVSP_RTC].base,
+        qdev_get_gpio_in(mmio_irqchip, RVSP_RTC_IRQ));
+
+    for (i = 0; i < ARRAY_SIZE(s->flash); i++) {
+        /* Map legacy -drive if=pflash to machine properties */
+        pflash_cfi01_legacy_drive(s->flash[i],
+                                  drive_get(IF_PFLASH, 0, i));
+    }
+    rvsp_flash_maps(s, system_memory);
+
+    /* load/create device tree */
+    if (machine->dtb) {
+        machine->fdt = load_device_tree(machine->dtb, &s->fdt_size);
+        if (!machine->fdt) {
+            error_report("load_device_tree() failed");
+            exit(1);
+        }
+    } else {
+        create_fdt(s, memmap);
+    }
+
+    s->machine_done.notify = rvsp_ref_machine_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
+}
+
+static void rvsp_ref_machine_instance_init(Object *obj)
+{
+    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
+
+    s->flash[0] = rvsp_flash_create(s, "rvsp.flash0", "pflash0");
+    s->flash[1] = rvsp_flash_create(s, "rvsp.flash1", "pflash1");
+}
+
+static char *rvsp_ref_get_aia_guests(Object *obj, Error **errp)
+{
+    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
+    char val[32];
+
+    sprintf(val, "%d", s->aia_guests);
+    return g_strdup(val);
+}
+
+static void rvsp_ref_set_aia_guests(Object *obj, const char *val, Error **errp)
+{
+    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
+
+    s->aia_guests = atoi(val);
+    if (s->aia_guests < 0 || s->aia_guests > RVSP_IRQCHIP_MAX_GUESTS) {
+        error_setg(errp, "Invalid number of AIA IMSIC guests");
+        error_append_hint(errp, "Valid values be between 0 and %d.\n",
+                          RVSP_IRQCHIP_MAX_GUESTS);
+    }
+}
+
+static void rvsp_ref_machine_class_init(ObjectClass *oc, const void *data)
+{
+    char str[128];
+    MachineClass *mc = MACHINE_CLASS(oc);
+    static const char * const valid_cpu_types[] = {
+        TYPE_RISCV_CPU_RVSP_REF,
+    };
+
+    mc->desc = "RISC-V Server SoC Reference board (EXPERIMENTAL)";
+    mc->init = rvsp_ref_machine_init;
+    mc->max_cpus = RVSP_CPUS_MAX;
+    mc->default_cpu_type = TYPE_RISCV_CPU_RVSP_REF;
+    mc->valid_cpu_types = valid_cpu_types;
+    mc->pci_allow_0_address = true;
+    mc->default_nic = "e1000e";
+    mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids;
+    mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props;
+    mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id;
+    mc->numa_mem_supported = true;
+    /* platform instead of architectural choice */
+    mc->cpu_cluster_has_numa_boundary = true;
+    mc->default_ram_id = "riscv_rvsp_ref_board.ram";
+
+    object_class_property_add_str(oc, "aia-guests",
+                                  rvsp_ref_get_aia_guests,
+                                  rvsp_ref_set_aia_guests);
+    sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
+                 "should be between 0 and %d.", RVSP_IRQCHIP_MAX_GUESTS);
+    object_class_property_set_description(oc, "aia-guests", str);
+}
+
+static const TypeInfo rvsp_ref_typeinfo = {
+    .name       = TYPE_RVSP_REF_MACHINE,
+    .parent     = TYPE_MACHINE,
+    .class_init = rvsp_ref_machine_class_init,
+    .instance_init = rvsp_ref_machine_instance_init,
+    .instance_size = sizeof(RVSPMachineState),
+};
+
+static void rvsp_ref_init_register_types(void)
+{
+    type_register_static(&rvsp_ref_typeinfo);
+}
+
+type_init(rvsp_ref_init_register_types)
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys
  2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
                   ` (2 preceding siblings ...)
  2025-11-11 18:29 ` [PATCH v4 3/5] hw/riscv: experimental server platform reference machine Daniel Henrique Barboza
@ 2025-11-11 18:29 ` Daniel Henrique Barboza
  2025-11-12  7:13   ` Philippe Mathieu-Daudé
  2025-11-11 18:29 ` [PATCH v4 5/5] docs: add rvsp-ref.rst Daniel Henrique Barboza
  4 siblings, 1 reply; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Daniel Henrique Barboza, Andrew Jones

Add an always present IOMMU platform device for the rvsp-ref board.

The IRQs being used are similar to what the 'virt' board is using: IRQs
36 to 39, one IRQ for queue.

Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
---
 hw/riscv/Kconfig               |  1 +
 hw/riscv/server_platform_ref.c | 78 ++++++++++++++++++++++++++++++++--
 2 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 6a5085c7a5..4f8cbfe77f 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -82,6 +82,7 @@ config SERVER_PLATFORM_REF
     select RISCV_ACLINT
     select RISCV_APLIC
     select RISCV_IMSIC
+    select RISCV_IOMMU
 
 config SHAKTI_C
     bool
diff --git a/hw/riscv/server_platform_ref.c b/hw/riscv/server_platform_ref.c
index ef2891a9d7..dc6caf72a6 100644
--- a/hw/riscv/server_platform_ref.c
+++ b/hw/riscv/server_platform_ref.c
@@ -31,6 +31,8 @@
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
+#include "hw/riscv/iommu.h"
+#include "hw/riscv/riscv-iommu-bits.h"
 #include "hw/intc/riscv_aclint.h"
 #include "hw/intc/riscv_aplic.h"
 #include "hw/intc/riscv_imsic.h"
@@ -94,6 +96,7 @@ enum {
     RVSP_MROM,
     RVSP_RESET_SYSCON,
     RVSP_RTC,
+    RVSP_IOMMU_SYS,
     RVSP_ACLINT,
     RVSP_APLIC_M,
     RVSP_APLIC_S,
@@ -112,6 +115,7 @@ enum {
     RVSP_UART0_IRQ = 10,
     RVSP_RTC_IRQ = 11,
     RVSP_PCIE_IRQ = 0x20, /* 32 to 35 */
+    IOMMU_SYS_IRQ = 0x24 /* 36 to 39 */
 };
 
 /*
@@ -141,6 +145,7 @@ static const MemMapEntry rvsp_ref_memmap[] = {
     [RVSP_MROM] =           {     0x1000,        0xf000 },
     [RVSP_RESET_SYSCON] =   {   0x100000,        0x1000 },
     [RVSP_RTC] =            {   0x101000,        0x1000 },
+    [RVSP_IOMMU_SYS] =      {   0x102000,        0x1000 },
     [RVSP_ACLINT] =         {  0x2000000,       0x10000 },
     [RVSP_PCIE_PIO] =       {  0x3000000,       0x10000 },
     [RVSP_APLIC_M] =        {  0xc000000, APLIC_SIZE(RVSP_CPUS_MAX) },
@@ -638,9 +643,51 @@ static void create_fdt_sockets(RVSPMachineState *s, const MemMapEntry *memmap,
     riscv_socket_fdt_write_distance_matrix(ms);
 }
 
+static void create_fdt_iommu_sys(RVSPMachineState *s, uint32_t irq_chip,
+                                 uint32_t msi_phandle,
+                                 uint32_t *iommu_sys_phandle)
+{
+    const char comp[] = "riscv,iommu";
+    void *fdt = MACHINE(s)->fdt;
+    uint32_t iommu_phandle;
+    g_autofree char *iommu_node = NULL;
+    hwaddr addr = s->memmap[RVSP_IOMMU_SYS].base;
+    hwaddr size = s->memmap[RVSP_IOMMU_SYS].size;
+    uint32_t iommu_irq_map[RISCV_IOMMU_INTR_COUNT] = {
+        IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_CQ,
+        IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_FQ,
+        IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PM,
+        IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PQ,
+    };
+
+    iommu_node = g_strdup_printf("/soc/iommu@%"HWADDR_PRIx,
+                                 s->memmap[RVSP_IOMMU_SYS].base);
+    iommu_phandle = qemu_fdt_alloc_phandle(fdt);
+    qemu_fdt_add_subnode(fdt, iommu_node);
+
+    qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
+    qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
+    qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
+
+    qemu_fdt_setprop_cells(fdt, iommu_node, "reg",
+                           addr >> 32, addr, size >> 32, size);
+    qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip);
+
+    qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
+        iommu_irq_map[0], FDT_IRQ_TYPE_EDGE_LOW,
+        iommu_irq_map[1], FDT_IRQ_TYPE_EDGE_LOW,
+        iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW,
+        iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW);
+
+    qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent", msi_phandle);
+
+    *iommu_sys_phandle = iommu_phandle;
+}
+
 static void create_fdt_pcie(RVSPMachineState *s, const MemMapEntry *memmap,
                             uint32_t irq_pcie_phandle,
-                            uint32_t msi_pcie_phandle)
+                            uint32_t msi_pcie_phandle,
+                            uint32_t iommu_sys_phandle)
 {
     g_autofree char *name = NULL;
     MachineState *ms = MACHINE(s);
@@ -675,6 +722,10 @@ static void create_fdt_pcie(RVSPMachineState *s, const MemMapEntry *memmap,
            memmap[RVSP_PCIE_MMIO_HIGH].size);
 
     create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
+
+    qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
+                           0, iommu_sys_phandle, 0, 0, 0,
+                           iommu_sys_phandle, 0, 0xffff);
 }
 
 static void create_fdt_reset(RVSPMachineState *s, const MemMapEntry *memmap,
@@ -768,12 +819,16 @@ static void create_fdt_flash(RVSPMachineState *s, const MemMapEntry *memmap)
 static void finalize_fdt(RVSPMachineState *s)
 {
     uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1;
-    uint32_t irq_pcie_phandle = 1;
+    uint32_t irq_pcie_phandle = 1, iommu_sys_phandle;
 
     create_fdt_sockets(s, rvsp_ref_memmap, &phandle, &irq_mmio_phandle,
                        &irq_pcie_phandle, &msi_pcie_phandle);
 
-    create_fdt_pcie(s, rvsp_ref_memmap, irq_pcie_phandle, msi_pcie_phandle);
+    create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle,
+                         &iommu_sys_phandle);
+
+    create_fdt_pcie(s, rvsp_ref_memmap, irq_pcie_phandle,
+                    msi_pcie_phandle, iommu_sys_phandle);
 
     create_fdt_reset(s, rvsp_ref_memmap, &phandle);
 
@@ -1078,7 +1133,7 @@ static void rvsp_ref_machine_init(MachineState *machine)
     MemoryRegion *system_memory = get_system_memory();
     MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
     MemoryRegion *reset_syscon_io = g_new(MemoryRegion, 1);
-    DeviceState *mmio_irqchip, *pcie_irqchip;
+    DeviceState *mmio_irqchip, *pcie_irqchip, *iommu_sys;
     int i, base_hartid, hart_count;
     int socket_count = riscv_socket_count(machine);
 
@@ -1196,6 +1251,21 @@ static void rvsp_ref_machine_init(MachineState *machine)
         create_fdt(s, memmap);
     }
 
+    iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
+    object_property_set_uint(OBJECT(iommu_sys), "addr",
+                             s->memmap[RVSP_IOMMU_SYS].base,
+                             &error_fatal);
+
+    object_property_set_uint(OBJECT(iommu_sys), "base-irq",
+                             IOMMU_SYS_IRQ,
+                             &error_fatal);
+
+    object_property_set_link(OBJECT(iommu_sys), "irqchip",
+                             OBJECT(mmio_irqchip),
+                             &error_fatal);
+
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
+
     s->machine_done.notify = rvsp_ref_machine_done;
     qemu_add_machine_init_done_notifier(&s->machine_done);
 }
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v4 5/5] docs: add rvsp-ref.rst
  2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
                   ` (3 preceding siblings ...)
  2025-11-11 18:29 ` [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys Daniel Henrique Barboza
@ 2025-11-11 18:29 ` Daniel Henrique Barboza
  2025-11-11 23:39   ` Andrew Jones
  4 siblings, 1 reply; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-11 18:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Daniel Henrique Barboza

Add documentation on the new experimental board rvsp-ref.

Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 docs/system/riscv/rvsp-ref.rst | 28 ++++++++++++++++++++++++++++
 docs/system/target-riscv.rst   |  1 +
 2 files changed, 29 insertions(+)
 create mode 100644 docs/system/riscv/rvsp-ref.rst

diff --git a/docs/system/riscv/rvsp-ref.rst b/docs/system/riscv/rvsp-ref.rst
new file mode 100644
index 0000000000..3889fce413
--- /dev/null
+++ b/docs/system/riscv/rvsp-ref.rst
@@ -0,0 +1,28 @@
+Experimental RISC-V Server Platform Reference board (``rvsp-ref``)
+==================================================================
+
+The RISC-V Server Platform specification `spec`_ defines a standardized
+set of hardware and software capabilities that portable system software,
+such as OS and hypervisors, can rely on being present in a RISC-V server
+platform. This machine aims to emulate this specification, providing
+an environment for firmware/OS development and testing.
+
+The main features included in rvsp-ref are:
+
+*  a new CPU type rvsp-ref CPU for server platform compliance
+* AIA
+* PCIe AHCI
+* PCIe NIC
+* No virtio mmio bus
+* No fw_cfg device
+* No ACPI table
+* Minimal device tree nodes
+
+The board is being provisioned as *experimental* because QEMU isn't
+100% compliant with the specification at this moment - we do not have
+support for the mandatory 'sdext' extension. The existence of the board
+is beneficial to the development of the ecossystem around the specification,
+so we're choosing the make the board available even in an incomplete state.
+When 'sdext' is implemented we'll remove the 'experimental' tag from it.
+
+.. _spec: https://github.com/riscv-non-isa/riscv-server-platform
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 89b2cb732c..2ed337c8cf 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -72,6 +72,7 @@ undocumented; you can get a complete list by running
    riscv/sifive_u
    riscv/virt
    riscv/xiangshan-kunminghu
+   riscv/rvsp-ref
 
 RISC-V CPU firmware
 -------------------
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 2/5] target/riscv: Add server platform reference cpu
  2025-11-11 18:29 ` [PATCH v4 2/5] target/riscv: Add server platform reference cpu Daniel Henrique Barboza
@ 2025-11-11 23:05   ` Andrew Jones
  2025-11-17 17:57     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 14+ messages in thread
From: Andrew Jones @ 2025-11-11 23:05 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer, Fei Wu

On Tue, Nov 11, 2025 at 03:29:41PM -0300, Daniel Henrique Barboza wrote:
> From: Fei Wu <wu.fei9@sanechips.com.cn>
> 
> The harts requirements of RISC-V server platform [1] require RVA23 ISA
> profile support, plus Sv48, Svadu, H, Sscofmpf etc.
> 
> This patch provides a CPU type (rvsp-ref) to go along with the rvsp-ref
> board.
> 
> [1] https://github.com/riscv-non-isa/riscv-server-platform/blob/main/server_platform_requirements.adoc
> 
> Signed-off-by: Fei Wu <fei2.wu@intel.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
>  target/riscv/cpu-qom.h |  1 +
>  target/riscv/cpu.c     | 14 ++++++++++++++
>  2 files changed, 15 insertions(+)
> 
> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> index 75f4e43408..07e96a14ba 100644
> --- a/target/riscv/cpu-qom.h
> +++ b/target/riscv/cpu-qom.h
> @@ -42,6 +42,7 @@
>  #define TYPE_RISCV_CPU_RVA22S64         RISCV_CPU_TYPE_NAME("rva22s64")
>  #define TYPE_RISCV_CPU_RVA23U64         RISCV_CPU_TYPE_NAME("rva23u64")
>  #define TYPE_RISCV_CPU_RVA23S64         RISCV_CPU_TYPE_NAME("rva23s64")
> +#define TYPE_RISCV_CPU_RVSP_REF         RISCV_CPU_TYPE_NAME("rvsp-ref")
>  #define TYPE_RISCV_CPU_IBEX             RISCV_CPU_TYPE_NAME("lowrisc-ibex")
>  #define TYPE_RISCV_CPU_SHAKTI_C         RISCV_CPU_TYPE_NAME("shakti-c")
>  #define TYPE_RISCV_CPU_SIFIVE_E         RISCV_CPU_TYPE_NAME("sifive-e")
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 975f7953e1..3ddb249970 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -3305,6 +3305,20 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>          .cfg.max_satp_mode = VM_1_10_SV48,
>      ),
>  
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RVSP_REF, TYPE_RISCV_BARE_CPU,
> +        .misa_mxl_max = MXL_RV64,
> +        .profile = &RVA23S64,
> +
> +        /*
> +         * ISA extensions
> +         * NOTE: we're missing 'sdext'.
> +         */
> +        .cfg.ext_zkr = true,
> +        .cfg.ext_svadu = true,

Svadu is no longer required.

> +
> +        .cfg.max_satp_mode = VM_1_10_SV57,

Shouldn't this be SV48 and then allow instantiations to use
rvsp-ref,sv57=on.

We also need Ssccfg and Sdtrig.

> +    ),
> +
>  #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
>      DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU,
>          .cfg.max_satp_mode = VM_1_10_SV57,
> -- 
> 2.51.1
> 
>

Thanks,
drew


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 3/5] hw/riscv: experimental server platform reference machine
  2025-11-11 18:29 ` [PATCH v4 3/5] hw/riscv: experimental server platform reference machine Daniel Henrique Barboza
@ 2025-11-11 23:36   ` Andrew Jones
  2025-11-18 20:15     ` Daniel Henrique Barboza
  2025-11-12  7:13   ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 14+ messages in thread
From: Andrew Jones @ 2025-11-11 23:36 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer, Fei Wu

On Tue, Nov 11, 2025 at 03:29:42PM -0300, Daniel Henrique Barboza wrote:
> From: Fei Wu <wu.fei9@sanechips.com.cn>
...
> +static char *rvsp_ref_get_aia_guests(Object *obj, Error **errp)
> +{
> +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
> +    char val[32];
> +
> +    sprintf(val, "%d", s->aia_guests);
> +    return g_strdup(val);
> +}
> +
> +static void rvsp_ref_set_aia_guests(Object *obj, const char *val, Error **errp)
> +{
> +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
> +
> +    s->aia_guests = atoi(val);
> +    if (s->aia_guests < 0 || s->aia_guests > RVSP_IRQCHIP_MAX_GUESTS) {

The minimum is 5 for the server platform, so we should enforce that. Also
I suggest we bump RVSP_IRQCHIP_MAX_GUESTS since it's only 7 right now.

> +        error_setg(errp, "Invalid number of AIA IMSIC guests");
> +        error_append_hint(errp, "Valid values be between 0 and %d.\n",
> +                          RVSP_IRQCHIP_MAX_GUESTS);
> +    }
> +}
> +
> +static void rvsp_ref_machine_class_init(ObjectClass *oc, const void *data)
> +{
> +    char str[128];
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +    static const char * const valid_cpu_types[] = {
> +        TYPE_RISCV_CPU_RVSP_REF,
> +    };
> +
> +    mc->desc = "RISC-V Server SoC Reference board (EXPERIMENTAL)";

We could (and probably should) version this machine type from the get go.
If we do that, then we could simply give it a version 0.9, which would
match the current spec. When the spec is ratified and this model is
complete, then it can be bumped to 1.0. Going that route would allow us
to avoid the EXPERIMENTAL "flag".

> +    mc->init = rvsp_ref_machine_init;
> +    mc->max_cpus = RVSP_CPUS_MAX;
> +    mc->default_cpu_type = TYPE_RISCV_CPU_RVSP_REF;
> +    mc->valid_cpu_types = valid_cpu_types;
> +    mc->pci_allow_0_address = true;
> +    mc->default_nic = "e1000e";
> +    mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids;
> +    mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props;
> +    mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id;
> +    mc->numa_mem_supported = true;
> +    /* platform instead of architectural choice */
> +    mc->cpu_cluster_has_numa_boundary = true;
> +    mc->default_ram_id = "riscv_rvsp_ref_board.ram";
> +
> +    object_class_property_add_str(oc, "aia-guests",
> +                                  rvsp_ref_get_aia_guests,
> +                                  rvsp_ref_set_aia_guests);
> +    sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
> +                 "should be between 0 and %d.", RVSP_IRQCHIP_MAX_GUESTS);

Same comment about the guest file range as above (we shouldn't suggest
anything less than 5).

> +    object_class_property_set_description(oc, "aia-guests", str);
> +}
> +
> +static const TypeInfo rvsp_ref_typeinfo = {
> +    .name       = TYPE_RVSP_REF_MACHINE,
> +    .parent     = TYPE_MACHINE,
> +    .class_init = rvsp_ref_machine_class_init,
> +    .instance_init = rvsp_ref_machine_instance_init,
> +    .instance_size = sizeof(RVSPMachineState),
> +};
> +
> +static void rvsp_ref_init_register_types(void)
> +{
> +    type_register_static(&rvsp_ref_typeinfo);
> +}
> +
> +type_init(rvsp_ref_init_register_types)
> -- 
> 2.51.1
> 
>

Thanks,
drew


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 5/5] docs: add rvsp-ref.rst
  2025-11-11 18:29 ` [PATCH v4 5/5] docs: add rvsp-ref.rst Daniel Henrique Barboza
@ 2025-11-11 23:39   ` Andrew Jones
  0 siblings, 0 replies; 14+ messages in thread
From: Andrew Jones @ 2025-11-11 23:39 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer

On Tue, Nov 11, 2025 at 03:29:44PM -0300, Daniel Henrique Barboza wrote:
> Add documentation on the new experimental board rvsp-ref.
> 
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
>  docs/system/riscv/rvsp-ref.rst | 28 ++++++++++++++++++++++++++++
>  docs/system/target-riscv.rst   |  1 +
>  2 files changed, 29 insertions(+)
>  create mode 100644 docs/system/riscv/rvsp-ref.rst
> 
> diff --git a/docs/system/riscv/rvsp-ref.rst b/docs/system/riscv/rvsp-ref.rst
> new file mode 100644
> index 0000000000..3889fce413
> --- /dev/null
> +++ b/docs/system/riscv/rvsp-ref.rst
> @@ -0,0 +1,28 @@
> +Experimental RISC-V Server Platform Reference board (``rvsp-ref``)
> +==================================================================
> +
> +The RISC-V Server Platform specification `spec`_ defines a standardized
> +set of hardware and software capabilities that portable system software,
> +such as OS and hypervisors, can rely on being present in a RISC-V server
> +platform. This machine aims to emulate this specification, providing
> +an environment for firmware/OS development and testing.
> +
> +The main features included in rvsp-ref are:
> +
> +*  a new CPU type rvsp-ref CPU for server platform compliance
> +* AIA
> +* PCIe AHCI
> +* PCIe NIC
> +* No virtio mmio bus
> +* No fw_cfg device
> +* No ACPI table
> +* Minimal device tree nodes
> +
> +The board is being provisioned as *experimental* because QEMU isn't
> +100% compliant with the specification at this moment - we do not have
> +support for the mandatory 'sdext' extension. The existence of the board
> +is beneficial to the development of the ecossystem around the specification,
> +so we're choosing the make the board available even in an incomplete state.
> +When 'sdext' is implemented we'll remove the 'experimental' tag from it.

'experimental' needs to stay until the 1.0 spec is ratified. Or, see my
comments in a previous patch about versioning the board instead.

Thanks,
drew

> +
> +.. _spec: https://github.com/riscv-non-isa/riscv-server-platform
> diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
> index 89b2cb732c..2ed337c8cf 100644
> --- a/docs/system/target-riscv.rst
> +++ b/docs/system/target-riscv.rst
> @@ -72,6 +72,7 @@ undocumented; you can get a complete list by running
>     riscv/sifive_u
>     riscv/virt
>     riscv/xiangshan-kunminghu
> +   riscv/rvsp-ref
>  
>  RISC-V CPU firmware
>  -------------------
> -- 
> 2.51.1
> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 3/5] hw/riscv: experimental server platform reference machine
  2025-11-11 18:29 ` [PATCH v4 3/5] hw/riscv: experimental server platform reference machine Daniel Henrique Barboza
  2025-11-11 23:36   ` Andrew Jones
@ 2025-11-12  7:13   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 14+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-12  7:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Fei Wu

Hi Fei, Daniel,

On 11/11/25 19:29, Daniel Henrique Barboza wrote:
> From: Fei Wu <wu.fei9@sanechips.com.cn>
> 
> The RISC-V Server Platform specification [1] defines a standardized set
> of hardware and software capabilities, that portable system software,
> such as OS and hypervisors can rely on being present in a RISC-V server
> platform.
> 
> We do not have all the required extensions in QEMU: we're missing
> 'sdext'. In theory we shouldn't go ahead with this work, but the
> emulation as is now is proving to be useful for development and testing
> of other parts of the SW stack (firmware, kernel) and we would like to
> make it broadly available to everyone. We're contributing it as
> 'experimental', hopefully making it clear that the board does NOT
> complies 100% with [1].
> 
> The main features included in this emulation are:
> 
>   - Based on riscv virt machine type
>   - A new memory map as close as virt machine as possible
>   - A new virt CPU type rvsp-ref-cpu for server platform compliance
>   - AIA
>   - PCIe AHCI
>   - PCIe NIC
>   - No virtio device
>   - No fw_cfg device
>   - No ACPI table provided
>   - Only minimal device tree nodes
> 
> [1] https://github.com/riscv-non-isa/riscv-server-platform
> 
> Signed-off-by: Fei Wu <fei2.wu@intel.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
>   configs/devices/riscv64-softmmu/default.mak |    1 +
>   hw/riscv/Kconfig                            |   14 +
>   hw/riscv/meson.build                        |    1 +
>   hw/riscv/server_platform_ref.c              | 1276 +++++++++++++++++++

Too big to my taste to review and/or look back in future.

(Don't bother splitting if someone is willing to review the patch).

>   4 files changed, 1292 insertions(+)
>   create mode 100644 hw/riscv/server_platform_ref.c


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys
  2025-11-11 18:29 ` [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys Daniel Henrique Barboza
@ 2025-11-12  7:13   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-12  7:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, palmer,
	Andrew Jones

On 11/11/25 19:29, Daniel Henrique Barboza wrote:
> Add an always present IOMMU platform device for the rvsp-ref board.
> 
> The IRQs being used are similar to what the 'virt' board is using: IRQs
> 36 to 39, one IRQ for queue.
> 
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
> ---
>   hw/riscv/Kconfig               |  1 +
>   hw/riscv/server_platform_ref.c | 78 ++++++++++++++++++++++++++++++++--
>   2 files changed, 75 insertions(+), 4 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 2/5] target/riscv: Add server platform reference cpu
  2025-11-11 23:05   ` Andrew Jones
@ 2025-11-17 17:57     ` Daniel Henrique Barboza
  0 siblings, 0 replies; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-17 17:57 UTC (permalink / raw)
  To: Andrew Jones
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer, Fei Wu



On 11/11/25 8:05 PM, Andrew Jones wrote:
> On Tue, Nov 11, 2025 at 03:29:41PM -0300, Daniel Henrique Barboza wrote:
>> From: Fei Wu <wu.fei9@sanechips.com.cn>
>>
>> The harts requirements of RISC-V server platform [1] require RVA23 ISA
>> profile support, plus Sv48, Svadu, H, Sscofmpf etc.
>>
>> This patch provides a CPU type (rvsp-ref) to go along with the rvsp-ref
>> board.
>>
>> [1] https://github.com/riscv-non-isa/riscv-server-platform/blob/main/server_platform_requirements.adoc
>>
>> Signed-off-by: Fei Wu <fei2.wu@intel.com>
>> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
>> ---
>>   target/riscv/cpu-qom.h |  1 +
>>   target/riscv/cpu.c     | 14 ++++++++++++++
>>   2 files changed, 15 insertions(+)
>>
>> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
>> index 75f4e43408..07e96a14ba 100644
>> --- a/target/riscv/cpu-qom.h
>> +++ b/target/riscv/cpu-qom.h
>> @@ -42,6 +42,7 @@
>>   #define TYPE_RISCV_CPU_RVA22S64         RISCV_CPU_TYPE_NAME("rva22s64")
>>   #define TYPE_RISCV_CPU_RVA23U64         RISCV_CPU_TYPE_NAME("rva23u64")
>>   #define TYPE_RISCV_CPU_RVA23S64         RISCV_CPU_TYPE_NAME("rva23s64")
>> +#define TYPE_RISCV_CPU_RVSP_REF         RISCV_CPU_TYPE_NAME("rvsp-ref")
>>   #define TYPE_RISCV_CPU_IBEX             RISCV_CPU_TYPE_NAME("lowrisc-ibex")
>>   #define TYPE_RISCV_CPU_SHAKTI_C         RISCV_CPU_TYPE_NAME("shakti-c")
>>   #define TYPE_RISCV_CPU_SIFIVE_E         RISCV_CPU_TYPE_NAME("sifive-e")
>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>> index 975f7953e1..3ddb249970 100644
>> --- a/target/riscv/cpu.c
>> +++ b/target/riscv/cpu.c
>> @@ -3305,6 +3305,20 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>>           .cfg.max_satp_mode = VM_1_10_SV48,
>>       ),
>>   
>> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RVSP_REF, TYPE_RISCV_BARE_CPU,
>> +        .misa_mxl_max = MXL_RV64,
>> +        .profile = &RVA23S64,
>> +
>> +        /*
>> +         * ISA extensions
>> +         * NOTE: we're missing 'sdext'.
>> +         */
>> +        .cfg.ext_zkr = true,
>> +        .cfg.ext_svadu = true,
> 
> Svadu is no longer required.
> 
>> +
>> +        .cfg.max_satp_mode = VM_1_10_SV57,
> 
> Shouldn't this be SV48 and then allow instantiations to use
> rvsp-ref,sv57=on.

Makes sense.

> 
> We also need Ssccfg and Sdtrig.

Sdtrig is enabled by default, and somehow I forgot to add ssccfg. I'll add it.


Thanks,

Daniel

> 
>> +    ),
>> +
>>   #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
>>       DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU,
>>           .cfg.max_satp_mode = VM_1_10_SV57,
>> -- 
>> 2.51.1
>>
>>
> 
> Thanks,
> drew



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 3/5] hw/riscv: experimental server platform reference machine
  2025-11-11 23:36   ` Andrew Jones
@ 2025-11-18 20:15     ` Daniel Henrique Barboza
  2025-11-18 20:50       ` Andrew Jones
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Henrique Barboza @ 2025-11-18 20:15 UTC (permalink / raw)
  To: Andrew Jones
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer, Fei Wu



On 11/11/25 8:36 PM, Andrew Jones wrote:
> On Tue, Nov 11, 2025 at 03:29:42PM -0300, Daniel Henrique Barboza wrote:
>> From: Fei Wu <wu.fei9@sanechips.com.cn>
> ...
>> +static char *rvsp_ref_get_aia_guests(Object *obj, Error **errp)
>> +{
>> +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
>> +    char val[32];
>> +
>> +    sprintf(val, "%d", s->aia_guests);
>> +    return g_strdup(val);
>> +}
>> +
>> +static void rvsp_ref_set_aia_guests(Object *obj, const char *val, Error **errp)
>> +{
>> +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
>> +
>> +    s->aia_guests = atoi(val);
>> +    if (s->aia_guests < 0 || s->aia_guests > RVSP_IRQCHIP_MAX_GUESTS) {
> 
> The minimum is 5 for the server platform, so we should enforce that. Also
> I suggest we bump RVSP_IRQCHIP_MAX_GUESTS since it's only 7 right now.
> 
>> +        error_setg(errp, "Invalid number of AIA IMSIC guests");
>> +        error_append_hint(errp, "Valid values be between 0 and %d.\n",
>> +                          RVSP_IRQCHIP_MAX_GUESTS);
>> +    }
>> +}
>> +
>> +static void rvsp_ref_machine_class_init(ObjectClass *oc, const void *data)
>> +{
>> +    char str[128];
>> +    MachineClass *mc = MACHINE_CLASS(oc);
>> +    static const char * const valid_cpu_types[] = {
>> +        TYPE_RISCV_CPU_RVSP_REF,
>> +    };
>> +
>> +    mc->desc = "RISC-V Server SoC Reference board (EXPERIMENTAL)";
> 
> We could (and probably should) version this machine type from the get go.
> If we do that, then we could simply give it a version 0.9, which would
> match the current spec. When the spec is ratified and this model is
> complete, then it can be bumped to 1.0. Going that route would allow us
> to avoid the EXPERIMENTAL "flag".

There has been some discussions offline on this and I'll bring them here.

A minor point: it was suggested to rename the board to 'rvserver' instead
of 'rvsp-ref'. I like this idea mostly because I keep misspelling rvsp-ref
as rsvp-ref.

As for the "version this machine type": in this case is different with what we do
with other QEMU machines. They have a new version for every QEMU release, e.g.
ARM's newest virt board is virt-10.2, in the next QEMU release it will be virt-11.0
and so on. We wouldn't do the same thing here - 'versioning' in this case is name
the board in a way that makes reference to the spec it implements. So this current
emulation would be named 'rvsp-ref-0.9', with an alias 'rvsp-ref' pointing to it.

Changing the emulation to comply with spec version 1.0 will create a rvsp-ref-1.0
board while keeping rvsp-ref-0.9 as is. Usually QEMU does that by using compat flags
that changes the behavior of the board, and we'll probably go this route.

One thing worth considering is that we can't just version stamp the board, we need to
do the same with the CPU. So we would have a rvsp-ref-cpu-0.9, rvsp-ref-cpu-1.0 and
an alias to point to the newest available emulation.

Also note that we're not 0.9 compliant either since we're missing sdext. So unless
we're willing to name this current board as rvsp-ref-0.9-beta or something like that,
maybe it's a good idea to postpone this work until we have 'sdext' implemented.


Thoughts always welcome. Thanks,

Daniel
   





> 
>> +    mc->init = rvsp_ref_machine_init;
>> +    mc->max_cpus = RVSP_CPUS_MAX;
>> +    mc->default_cpu_type = TYPE_RISCV_CPU_RVSP_REF;
>> +    mc->valid_cpu_types = valid_cpu_types;
>> +    mc->pci_allow_0_address = true;
>> +    mc->default_nic = "e1000e";
>> +    mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids;
>> +    mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props;
>> +    mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id;
>> +    mc->numa_mem_supported = true;
>> +    /* platform instead of architectural choice */
>> +    mc->cpu_cluster_has_numa_boundary = true;
>> +    mc->default_ram_id = "riscv_rvsp_ref_board.ram";
>> +
>> +    object_class_property_add_str(oc, "aia-guests",
>> +                                  rvsp_ref_get_aia_guests,
>> +                                  rvsp_ref_set_aia_guests);
>> +    sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
>> +                 "should be between 0 and %d.", RVSP_IRQCHIP_MAX_GUESTS);
> 
> Same comment about the guest file range as above (we shouldn't suggest
> anything less than 5).
> 
>> +    object_class_property_set_description(oc, "aia-guests", str);
>> +}
>> +
>> +static const TypeInfo rvsp_ref_typeinfo = {
>> +    .name       = TYPE_RVSP_REF_MACHINE,
>> +    .parent     = TYPE_MACHINE,
>> +    .class_init = rvsp_ref_machine_class_init,
>> +    .instance_init = rvsp_ref_machine_instance_init,
>> +    .instance_size = sizeof(RVSPMachineState),
>> +};
>> +
>> +static void rvsp_ref_init_register_types(void)
>> +{
>> +    type_register_static(&rvsp_ref_typeinfo);
>> +}
>> +
>> +type_init(rvsp_ref_init_register_types)
>> -- 
>> 2.51.1
>>
>>
> 
> Thanks,
> drew



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 3/5] hw/riscv: experimental server platform reference machine
  2025-11-18 20:15     ` Daniel Henrique Barboza
@ 2025-11-18 20:50       ` Andrew Jones
  0 siblings, 0 replies; 14+ messages in thread
From: Andrew Jones @ 2025-11-18 20:50 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	palmer, Fei Wu

On Tue, Nov 18, 2025 at 05:15:54PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 11/11/25 8:36 PM, Andrew Jones wrote:
> > On Tue, Nov 11, 2025 at 03:29:42PM -0300, Daniel Henrique Barboza wrote:
> > > From: Fei Wu <wu.fei9@sanechips.com.cn>
> > ...
> > > +static char *rvsp_ref_get_aia_guests(Object *obj, Error **errp)
> > > +{
> > > +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
> > > +    char val[32];
> > > +
> > > +    sprintf(val, "%d", s->aia_guests);
> > > +    return g_strdup(val);
> > > +}
> > > +
> > > +static void rvsp_ref_set_aia_guests(Object *obj, const char *val, Error **errp)
> > > +{
> > > +    RVSPMachineState *s = RVSP_REF_MACHINE(obj);
> > > +
> > > +    s->aia_guests = atoi(val);
> > > +    if (s->aia_guests < 0 || s->aia_guests > RVSP_IRQCHIP_MAX_GUESTS) {
> > 
> > The minimum is 5 for the server platform, so we should enforce that. Also
> > I suggest we bump RVSP_IRQCHIP_MAX_GUESTS since it's only 7 right now.
> > 
> > > +        error_setg(errp, "Invalid number of AIA IMSIC guests");
> > > +        error_append_hint(errp, "Valid values be between 0 and %d.\n",
> > > +                          RVSP_IRQCHIP_MAX_GUESTS);
> > > +    }
> > > +}
> > > +
> > > +static void rvsp_ref_machine_class_init(ObjectClass *oc, const void *data)
> > > +{
> > > +    char str[128];
> > > +    MachineClass *mc = MACHINE_CLASS(oc);
> > > +    static const char * const valid_cpu_types[] = {
> > > +        TYPE_RISCV_CPU_RVSP_REF,
> > > +    };
> > > +
> > > +    mc->desc = "RISC-V Server SoC Reference board (EXPERIMENTAL)";
> > 
> > We could (and probably should) version this machine type from the get go.
> > If we do that, then we could simply give it a version 0.9, which would
> > match the current spec. When the spec is ratified and this model is
> > complete, then it can be bumped to 1.0. Going that route would allow us
> > to avoid the EXPERIMENTAL "flag".
> 
> There has been some discussions offline on this and I'll bring them here.
> 
> A minor point: it was suggested to rename the board to 'rvserver' instead
> of 'rvsp-ref'. I like this idea mostly because I keep misspelling rvsp-ref
> as rsvp-ref.

I do like the '-ref' suffix though.

> 
> As for the "version this machine type": in this case is different with what we do
> with other QEMU machines. They have a new version for every QEMU release, e.g.
> ARM's newest virt board is virt-10.2, in the next QEMU release it will be virt-11.0
> and so on. We wouldn't do the same thing here - 'versioning' in this case is name
> the board in a way that makes reference to the spec it implements. So this current
> emulation would be named 'rvsp-ref-0.9', with an alias 'rvsp-ref' pointing to it.
> 
> Changing the emulation to comply with spec version 1.0 will create a rvsp-ref-1.0
> board while keeping rvsp-ref-0.9 as is. Usually QEMU does that by using compat flags
> that changes the behavior of the board, and we'll probably go this route.

Yes, as long as we point out what the version numbers mean somewhere, e.g.
in the machine description, then I guess people will get it.

I'm not sure I want a 0.9 board to live on after a ratified 1.0 is
released, though. So maybe an 'experimental'  board makes more sense
if we need to call it that in order to reserve the right to delete it.

> 
> One thing worth considering is that we can't just version stamp the board, we need to
> do the same with the CPU. So we would have a rvsp-ref-cpu-0.9, rvsp-ref-cpu-1.0 and
> an alias to point to the newest available emulation.

ack

> 
> Also note that we're not 0.9 compliant either since we're missing sdext. So unless
> we're willing to name this current board as rvsp-ref-0.9-beta or something like that,
> maybe it's a good idea to postpone this work until we have 'sdext' implemented.

Yes, let's prioritize sdext so we can match the current spec (which is
unlikely to change much before ratification) before we merge the reference
board at all.

Thanks,
drew


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2025-11-18 20:51 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-11 18:29 [PATCH v4 0/5] hw/riscv: Experimental Server Platform Reference Board Daniel Henrique Barboza
2025-11-11 18:29 ` [PATCH v4 1/5] target/riscv/cpu.c: remove 'bare' condition for .profile Daniel Henrique Barboza
2025-11-11 18:29 ` [PATCH v4 2/5] target/riscv: Add server platform reference cpu Daniel Henrique Barboza
2025-11-11 23:05   ` Andrew Jones
2025-11-17 17:57     ` Daniel Henrique Barboza
2025-11-11 18:29 ` [PATCH v4 3/5] hw/riscv: experimental server platform reference machine Daniel Henrique Barboza
2025-11-11 23:36   ` Andrew Jones
2025-11-18 20:15     ` Daniel Henrique Barboza
2025-11-18 20:50       ` Andrew Jones
2025-11-12  7:13   ` Philippe Mathieu-Daudé
2025-11-11 18:29 ` [PATCH v4 4/5] hw/riscv/server_platform_ref.c: add riscv-iommu-sys Daniel Henrique Barboza
2025-11-12  7:13   ` Philippe Mathieu-Daudé
2025-11-11 18:29 ` [PATCH v4 5/5] docs: add rvsp-ref.rst Daniel Henrique Barboza
2025-11-11 23:39   ` Andrew Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).