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]>
---
hw/riscv/Kconfig | 1 +
hw/riscv/virt.c | 96 ++++++++++++++++++++++++++++++++++++
include/hw/misc/riscv_rpmi.h | 10 ++++
include/hw/riscv/virt.h | 3 ++
4 files changed, 110 insertions(+)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 54e41a6afc..4e25be113a 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 33775a61fd..e52ccfae1f 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -45,6 +45,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"
@@ -97,6 +99,8 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_UART0] = { 0x10000000, 0x100 },
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
[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 },
@@ -1002,6 +1006,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;
@@ -1021,6 +1059,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_uart(s, irq_mmio_phandle);
@@ -1410,6 +1452,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++) {
@@ -1552,6 +1606,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",
@@ -1636,6 +1709,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;
}
@@ -1710,6 +1784,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;
@@ -1831,6 +1920,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/misc/riscv_rpmi.h b/include/hw/misc/riscv_rpmi.h
index cb2658e57e..b5d8a32f9b 100644
--- a/include/hw/misc/riscv_rpmi.h
+++ b/include/hw/misc/riscv_rpmi.h
@@ -85,6 +85,16 @@ struct RiscvRpmiState {
bool has_shmem;
};
+#ifdef CONFIG_LIBRPMI
DeviceState *riscv_rpmi_create(const RiscvRpmiConfig *cfg, Error **errp);
+#else
+static inline DeviceState *riscv_rpmi_create(const RiscvRpmiConfig *cfg,
+ Error **errp)
+{
+ (void)cfg;
+ (void)errp;
+ return NULL;
+}