On Thu, 2026-09-17 at 10:52 +0530, Subrahmanya Lingappa wrote:
> Add the virt machine rpmi=on/off option and wire the initial RPMI
> Base
> transport into machine realization.
>
> The option remains disabled by default and requires TCG plus librpmi.
> Invalid accelerator/build combinations fail during machine
> initialization. When enabled, virt allocates the RPMI shared-memory
> transport, creates the RPMI device, configures Base service metadata,
> and emits the corresponding device-tree nodes for firmware discovery.
>
> Signed-off-by: Subrahmanya Lingappa
> <[email protected]>
My review bot says (sorry about the line wrapping):
- [HIGH] In hw/riscv/virt.c (finalize_fdt), the new else branch calls
create_fdt_reset, a symbol with no declaration or definition anywhere
in
the tree at this commit. Since rpmi defaults to off, this is the
default
path, so every qemu-system-riscv64/riscv32 build of this revision
fails:
the implicit declaration is a hard error under -Werror, and the link
would fail regardless. A later series patch removes the call by
folding
reset-node control into riscv_create_fdt_syscon, fixing the final
state,
but every patch in a series must compile on its own or git-bisect
breaks.
Move the reset-node handling into this patch or drop the else branch.
- [LOW] Commit message for hw/riscv/virt.c rpmi option overclaims and
under-justifies. The RISC-V subsystem rules require justification for
new
board features, but no use case (e.g. RPMI client or firmware
testing) is
given. It claims the patch emits device-tree nodes (plural), yet only
a
single mailbox node is added here; service nodes arrive in later
patches.
It claims the option requires TCG plus librpmi, but the code only
rejects
KVM and non-librpmi builds, never positively requiring TCG. It also
omits
that the reset FDT node is made conditional on !have_rpmi.
- [LOW] In hw/riscv/virt.c (create_fdt_rpmi), the msi_phandle parameter
receives msi_pcie_phandle from finalize_fdt but is never referenced
in
the body, here or at the end of the series. Passing an MSI phandle
implies the RPMI mailbox is MSI-wired when the transport uses a
doorbell
MMIO region; drop the parameter. nit: virt_rpmi_config(s, NULL, 0) is
called only to fetch shmem/doorbell addresses; reading s->memmap
directly
would avoid coupling the FDT path to the device-config builder.
- [LOW] In hw/riscv/virt.c (virt_machine_class_init), the rpmi property
description says only Set on/off to enable/disable RISC-V RPMI
devices,
while the adjacent aclint property carries a (TCG only) qualifier.
Users discovering the option via -machine virt,help or QMP get no
hint
that enabling it aborts machine init under KVM or non-librpmi builds;
add the constraint to the description, still missing at series end.
Which seems to be true (I didn't test to make sure though).
I see the call to create_fdt_reset() in this patch is removed in patch
5. Please make sure you test all patches before sending them
Alistair
> ---
> hw/riscv/Kconfig | 1 +
> hw/riscv/virt.c | 96
> +++++++++++++++++++++++++++++++++++++++++
> include/hw/riscv/virt.h | 3 ++
> 3 files changed, 100 insertions(+)
>
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index d06ac26648..c3f9d7580b 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -49,6 +49,7 @@ config RISCV_VIRT
> imply VIRTIO_VGA
> imply TEST_DEVICES
> imply TPM_TIS_SYSBUS
> + imply RISCV_RPMI
> select DEVICE_TREE
> select RISCV_NUMA
> select GOLDFISH_RTC
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index d58656f70d..c822cc15ca 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -44,6 +44,8 @@
> #include "hw/intc/riscv_aplic.h"
> #include "hw/intc/sifive_plic.h"
> #include "hw/misc/sifive_test.h"
> +#include "hw/misc/riscv_rpmi.h"
> +#include "hw/riscv/rpmi-fdt.h"
> #include "hw/core/platform-bus.h"
> #include "chardev/char.h"
> #include "system/device_tree.h"
> @@ -100,6 +102,8 @@ static const MemMapEntry virt_memmap[] = {
> /* UART1 supports page isolation from UART0 */
> [VIRT_UART1] = { 0x1000a000, 0x100 },
> [VIRT_FW_CFG] = { 0x10100000, 0x18 },
> + [VIRT_RPMI_SHMEM] = { 0x10200000, 0x20000 },
> + [VIRT_RPMI_DOORBELL] = { 0x10230000, 0x1000 },
> [VIRT_FLASH] = { 0x20000000, 0x4000000 },
> [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE },
> [VIRT_IMSIC_S] = { 0x28000000, VIRT_IMSIC_MAX_SIZE },
> @@ -988,6 +992,40 @@ static void create_fdt_iommu(RISCVVirtState *s,
> uint16_t bdf)
> s->pci_iommu_bdf = bdf;
> }
>
> +
> +static RiscvRpmiConfig virt_rpmi_config(RISCVVirtState *s,
> + const uint32_t *hart_ids,
> + uint32_t hart_count)
> +{
> + return (RiscvRpmiConfig) {
> + .doorbell_base = s->memmap[VIRT_RPMI_DOORBELL].base,
> + .shmem_base = s->memmap[VIRT_RPMI_SHMEM].base,
> + .shmem_size = s->memmap[VIRT_RPMI_SHMEM].size,
> + .a2p_req_size = VIRT_RPMI_A2P_REQ_SIZE,
> + .p2a_req_size = VIRT_RPMI_P2A_REQ_SIZE,
> + .platform_info = "QEMU RISC-V virt RPMI",
> + .hart_ids = hart_ids,
> + .hart_count = hart_count,
> + };
> +}
> +
> +static void create_fdt_rpmi(RISCVVirtState *s, uint32_t *phandle,
> + uint32_t msi_phandle)
> +{
> + RiscvRpmiConfig rpmi_cfg = virt_rpmi_config(s, NULL, 0);
> + uint32_t rpmi_mbox_handle;
> + RiscvRpmiFdtMboxConfig cfg = {
> + .shmem_base = rpmi_cfg.shmem_base,
> + .doorbell_base = rpmi_cfg.doorbell_base,
> + .a2p_req_size = rpmi_cfg.a2p_req_size,
> + .p2a_req_size = rpmi_cfg.p2a_req_size,
> + .doorbell_size = s->memmap[VIRT_RPMI_DOORBELL].size,
> + };
> +
> + riscv_rpmi_fdt_add_mbox(MACHINE(s)->fdt, &cfg, phandle,
> + &rpmi_mbox_handle);
> +}
> +
> static void finalize_fdt(RISCVVirtState *s)
> {
> uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle =
> 1;
> @@ -1007,6 +1045,10 @@ static void finalize_fdt(RISCVVirtState *s)
> create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> iommu_sys_phandle);
>
> + if (s->have_rpmi) {
> + create_fdt_rpmi(s, &phandle, msi_pcie_phandle);
> + }
> +
> create_fdt_reset(s, &phandle);
>
> create_fdt_uarts(s, irq_mmio_phandle);
> @@ -1334,6 +1376,18 @@ static void virt_machine_init(MachineState
> *machine)
> exit(1);
> }
>
> +
> + if (s->have_rpmi) {
> +#ifndef CONFIG_LIBRPMI
> + error_report("RISC-V RPMI support is not compiled in");
> + exit(1);
> +#else
> + if (kvm_enabled()) {
> + error_report("RISC-V RPMI support is not available with
> KVM");
> + exit(1);
> + }
> +#endif
> + }
> /* Initialize sockets */
> mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL;
> for (i = 0; i < socket_count; i++) {
> @@ -1484,6 +1538,25 @@ static void virt_machine_init(MachineState
> *machine)
> /* SiFive Test MMIO device */
> sifive_test_create(s->memmap[VIRT_TEST].base);
>
> + if (s->have_rpmi) {
> + MachineClass *mc = MACHINE_GET_CLASS(machine);
> + const CPUArchIdList *possible_cpus = mc-
> >possible_cpu_arch_ids(machine);
> + g_autofree uint32_t *rpmi_hart_ids =
> + g_new0(uint32_t, machine->smp.cpus);
> + RiscvRpmiConfig rpmi_cfg;
> + Error *local_err = NULL;
> +
> + for (i = 0; i < machine->smp.cpus; i++) {
> + rpmi_hart_ids[i] = possible_cpus->cpus[i].arch_id;
> + }
> +
> + rpmi_cfg = virt_rpmi_config(s, rpmi_hart_ids, machine-
> >smp.cpus);
> + if (!riscv_rpmi_create(&rpmi_cfg, &local_err)) {
> + error_report_err(local_err);
> + exit(1);
> + }
> + }
> +
> /* VirtIO MMIO devices */
> for (i = 0; i < VIRTIO_COUNT; i++) {
> sysbus_create_simple("virtio-mmio",
> @@ -1575,6 +1648,7 @@ static void virt_machine_instance_init(Object
> *obj)
>
> s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
> s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
> + s->have_rpmi = false;
> s->acpi = ON_OFF_AUTO_AUTO;
> s->iommu_sys = ON_OFF_AUTO_AUTO;
> s->num_sources = VIRT_IRQCHIP_NUM_SOURCES;
> @@ -1650,6 +1724,21 @@ static void virt_set_aclint(Object *obj, bool
> value, Error **errp)
> s->have_aclint = value;
> }
>
> +
> +static bool virt_get_rpmi(Object *obj, Error **errp)
> +{
> + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
> +
> + return s->have_rpmi;
> +}
> +
> +static void virt_set_rpmi(Object *obj, bool value, Error **errp)
> +{
> + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
> +
> + s->have_rpmi = value;
> +}
> +
> bool virt_is_iommu_sys_enabled(RISCVVirtState *s)
> {
> return s->iommu_sys == ON_OFF_AUTO_ON;
> @@ -1771,6 +1860,13 @@ static void
> virt_machine_class_init(ObjectClass *oc, const void *data)
> "enable/disable emulating
> "
> "ACLINT devices");
>
> +
> + object_class_property_add_bool(oc, "rpmi", virt_get_rpmi,
> + virt_set_rpmi);
> + object_class_property_set_description(oc, "rpmi",
> + "Set on/off to
> enable/disable "
> + "RISC-V RPMI devices");
> +
> object_class_property_add_str(oc, "aia", virt_get_aia,
> virt_set_aia);
> object_class_property_set_description(oc, "aia",
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 7c862b0da2..76b5a57001 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -55,6 +55,7 @@ struct RISCVVirtState {
>
> int fdt_size;
> bool have_aclint;
> + bool have_rpmi;
> RISCVVirtAIAType aia_type;
> int aia_guests;
> char *oem_id;
> @@ -82,6 +83,8 @@ enum {
> VIRT_VIRTIO,
> VIRT_UART1,
> VIRT_FW_CFG,
> + VIRT_RPMI_SHMEM,
> + VIRT_RPMI_DOORBELL,
> VIRT_IMSIC_M,
> VIRT_IMSIC_S,
> VIRT_FLASH,