On 9/10/2026 12:36 PM, Andrew Jones wrote:
On Wed, Sep 09, 2026 at 06:07:53PM -0300, Daniel Henrique Barboza wrote:
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index d06ac26648..da59eb2155 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -69,6 +69,22 @@ config RISCV_VIRT
select ACPI
select ACPI_PCI
+config RISCV_SERVER_PLATFORM_REF
+ bool
+ default y
+ depends on RISCV64
+ imply TPM_TIS_SYSBUS
+ select RISCV_NUMA
+ select GOLDFISH_RTC
+ select PCI
+ select PCI_EXPRESS_GENERIC_BRIDGE
+ select PFLASH_CFI01
+ select SERIAL
This needs to select SERIAL_MM rather than SERIAL, since the machine calls
serial_mm_init(). It also directly uses the platform bus, so it needs
select PLATFORM_BUS
The machine also creates an ICH9 AHCI controller, so keeping it would require
selecting AHCI_ICH9.
However, SATA is optional for Server Platform v1.0, so I suggest dropping the
default ICH9 AHCI controller instead. That would also remove the IDE/AHCI
includes, NUM_SATA_PORTS, the AHCI-specific state, and its initialization.
The base machine would then have no default storage controller, and users
could add NVMe explicitly when needed.
I'll play around and see if we can still use SATA + ICH9 via the platform bus.
We'll probably need to update the docs and tests too.
Note that this might imply adding additional stuff to support SATA hotplug as
well. If the resulting code is more complex than what we have then I'd rather
keep SATA + ich9 by default.
Likewise, networking hardware is optional, so I suggest dropping the e1000e
default NIC. pci_init_nic_devices() may remain for explicit -nic requests.
Same as above.
To make suitable optional devices such as NVMe available, I suggest
imply PCIE_DEVICES
rather than the broader PCI_DEVICES set.
+#include "system/kvm.h"
+#include "system/qtest.h"
+#include "system/tcg.h"
+#include "kvm/kvm_riscv.h"
+#include "system/tpm.h"
+#include "system/qtest.h"
Duplicate system/qtest.h include.
+#define RVSERVER_IRQCHIP_NUM_MSIS 255
+#define RVSERVER_IRQCHIP_NUM_SOURCES 96
+#define RVSERVER_IRQCHIP_NUM_PRIO_BITS 3
+#define RVSERVER_IRQCHIP_MAX_GUESTS_BITS 3
+#define RVSERVER_IRQCHIP_MAX_GUESTS \
+ ((1U << RVSERVER_IRQCHIP_MAX_GUESTS_BITS) - 1U)
+#define RVSERVER_IRQCHIP_DEFAULT_AIA_GUESTS 5
nit: Please align these definitions with the related definitions above.
I suppose you're talking about aligning the macros.
Also, the two nearby #error strings have "accomodate" rather than
"accommodate".
+enum {
+ RVSERVER_UART0_IRQ = 10,
+ RVSERVER_RTC_IRQ = 11,
+ RVSERVER_PCIE_IRQ = 32, /* 32 to 35 */
+ IOMMU_SYS_IRQ = 36, /* 36 to 39 */
+ RVSERVER_PLATFORM_BUS_IRQ = 40, /* 40 to 48 */
+};
RVSERVER_PLATFORM_BUS_NUM_IRQS is 8, so this should say 40 to 47. Please
also align the assignments.
+static const MemMapEntry rvserver_ref_memmap[] = {
+ [RVSERVER_DEBUG] = { 0x0, 0x100 },
RVSERVER_DEBUG does not appear to be used.
+ riscv_aclint_mtimer_create(memmap[RVSERVER_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);
Server SoC v1.0 CTI_010 requires the time CSR to count in units of 1 ns,
so we should define a machine-specific 1 GHz timebase rather than using
the 10 MHz virt default, for example
#define RVSERVER_ACLINT_TIMEBASE_FREQ 1000000000
and use RVSERVER_ACLINT_TIMEBASE_FREQ in this call. The CPU FDT
timebase-frequency property should use
kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
RVSERVER_ACLINT_TIMEBASE_FREQ
The FDT code is doing all that, so in the end what we want is just a new
RVSERVER macro with the 1Gb clock.
+ if (!rvserver_aclint_allowed()) {
+ error_report("'aclint' is only available with TCG acceleration");
+ exit(1);
+ }
This makes the machine TCG/qtest only. We can follow virt's support of KVM
to enable it. The documentation can state that a conformant guest requires
a conformant host, while allowing nonconformant hosts to be used for
functional KVM testing.
I don't want to hold upstreaming of the base emulation because of KVM, in
particular
because there's a very, very high chance that we do not have KVM support for
all the
riscv-server-ref extensions anyway.
My idea is to implement KVM support for this board as a follow-up. We'll mark
it as
"experimental" since we'll boot with a KVM cpu that doesn't have all the
required
extensions (again, most likely).
We'll probably need to discuss if we're going to stick with just the "host" CPU
type
or if we want a riscv-server-ref type for KVM too.
+static void rvserver_ref_machine_instance_init(Object *obj)
+{
+ RISCVServerRefMachineState *s = RISCV_SERVER_REF_MACHINE(obj);
+
+ s->flash[0] = riscv_flash_create(OBJECT(s),
+ "riscv-server-ref.flash0",
+ "pflash0",
+ RVSERVER_FLASH_SECTOR_SIZE);
+ s->flash[1] = riscv_flash_create(OBJECT(s),
+ "riscv-server-ref.flash1",
+ "pflash1",
+ RVSERVER_FLASH_SECTOR_SIZE);
virt has an instance finalizer which unreferences either flash device when
initialization fails before realization. This machine should have the same
cleanup and set instance_finalize in its TypeInfo.
+ static const char * const valid_cpu_types[] = {
+ TYPE_RISCV_CPU_RVSERVER_REF,
+ };
This needs a NULL terminator. MachineClass.valid_cpu_types is walked until
NULL. For example, testing this with "-cpu max" printed:
The valid models are: riscv-server-ref, (null), (null)
That's a good catch.
KVM also needs TYPE_RISCV_CPU_HOST in the valid CPU types.
True. We'll do it as a follow-up when we're sure which KVM types we're going to
support
Thanks,
Daniel
Thanks,
drew