The RISC-V Server Platform spec requires a TPM device. TPM devices in
QEMU comes usually in two flavors: emulated or passthrough. A
passthrough device requires a host TPM device that the QEMU process can
borrow and it's usually coupled with KVM acceleration.
To use the TPM emulator we'll need help from an external TPM emulator
called swtpm. More info can be found in [1]. For our purposes this is
a process that, if running Ubuntu, can be installed via 'swtpm' package.
We'll go back to it shortly.
For now, adding support for the emulated TPM device 'tpm-tis' (other TPM
flavors might work as well, 'tpm-tis' is the one tested with this work)
requires a platform bus. Adding a platform bus will open the door for
more devices to be added in the board. This is ok - a reference board
isn't a restricted board and users are free to add devices at their
leisure.
Here's how to use tpm-tis with the riscv-server-ref board after applying
this patch:
- in a separated shell/term run 'swtpm' (--log is optional):
$ mkdir /tmp/mytpm1
$ swtpm socket --tpmstate dir=/tmp/mytpm1 \
--ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
--tpm2 \
--log level=20
Then start QEMU with:
$ qemu-system-riscv64 -M riscv-server-ref (...) \
-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
-tpmdev emulator,id=tpm0,chardev=chrtpm\
-device tpm-tis-device,tpmdev=tpm0
[1] https://qemu-project.gitlab.io/qemu/specs/tpm.html
Signed-off-by: Daniel Henrique Barboza <[email protected]>
---
hw/riscv/Kconfig | 1 +
hw/riscv/server_platform_ref.c | 92 +++++++++++++++++++++++++++++++++-
2 files changed, 91 insertions(+), 2 deletions(-)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 1807c423ff..d3912cbb1e 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -73,6 +73,7 @@ config RISCV_SERVER_PLATFORM_REF
bool
default y
depends on RISCV64
+ imply TPM_TIS_SYSBUS
select RISCV_NUMA
select GOLDFISH_RTC
select PCI
diff --git a/hw/riscv/server_platform_ref.c b/hw/riscv/server_platform_ref.c
index 7e626c6eb7..790d9861f3 100644
--- a/hw/riscv/server_platform_ref.c
+++ b/hw/riscv/server_platform_ref.c
@@ -14,6 +14,7 @@
#include "qapi/error.h"
#include "qapi/qapi-visit-common.h"
#include "hw/core/boards.h"
+#include "hw/core/platform-bus.h"
#include "hw/core/loader.h"
#include "hw/core/sysbus.h"
#include "hw/core/qdev-properties.h"
@@ -39,6 +40,7 @@
#include "system/runstate.h"
#include "system/system.h"
#include "system/tcg.h"
+#include "system/tpm.h"
#include "system/qtest.h"
#include "target/riscv/cpu.h"
#include "target/riscv/pmu.h"
@@ -72,6 +74,8 @@
#define SYSCON_RESET 0x1
#define SYSCON_POWEROFF 0x2
+#define RVSERVER_PLATFORM_BUS_NUM_IRQS 8
+
#define TYPE_RISCV_SERVER_REF_MACHINE MACHINE_TYPE_NAME("riscv-server-ref")
OBJECT_DECLARE_SIMPLE_TYPE(RISCVServerRefMachineState,
RISCV_SERVER_REF_MACHINE)
@@ -88,6 +92,8 @@ struct RISCVServerRefMachineState {
int fdt_size;
int aia_guests;
const MemMapEntry *memmap;
+
+ DeviceState *platform_bus_dev;
};
enum {
@@ -106,6 +112,7 @@ enum {
RVSERVER_DRAM,
RVSERVER_PCIE_MMIO,
RVSERVER_PCIE_PIO,
+ RVSERVER_PLATFORM_BUS,
RVSERVER_PCIE_ECAM,
RVSERVER_PCIE_MMIO_HIGH
};
@@ -114,7 +121,8 @@ enum {
RVSERVER_UART0_IRQ = 10,
RVSERVER_RTC_IRQ = 11,
RVSERVER_PCIE_IRQ = 0x20, /* 32 to 35 */
- IOMMU_SYS_IRQ = 0x24 /* 36 to 39 */
+ IOMMU_SYS_IRQ = 0x24, /* 36 to 39 */
+ RVSERVER_PLATFORM_BUS_IRQ = 40, /* 40 to 48 */
};
/*
@@ -147,6 +155,7 @@ static const MemMapEntry rvserver_ref_memmap[] = {
[RVSERVER_IOMMU_SYS] = { 0x102000, 0x1000 },
[RVSERVER_ACLINT] = { 0x2000000, 0x10000 },
[RVSERVER_PCIE_PIO] = { 0x3000000, 0x10000 },
+ [RVSERVER_PLATFORM_BUS] = { 0x4000000, 0x2000000 },
[RVSERVER_APLIC_M] = { 0xc000000, APLIC_SIZE(RVSERVER_CPUS_MAX) },
[RVSERVER_APLIC_S] = { 0xd000000, APLIC_SIZE(RVSERVER_CPUS_MAX) },
[RVSERVER_UART0] = { 0x10000000, 0x100 },
@@ -214,6 +223,34 @@ static void rvserver_flash_maps(RISCVServerRefMachineState
*s,
rvserver_flash_map(s->flash[1], flashbase + flashsize, flashsize, sysmem);
}
+static void create_platform_bus(RISCVServerRefMachineState *s,
+ DeviceState *irqchip)
+{
+ DeviceState *dev;
+ SysBusDevice *sysbus;
+ int i;
+ MemoryRegion *sysmem = get_system_memory();
+
+ dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
+ dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
+ qdev_prop_set_uint32(dev, "num_irqs", RVSERVER_PLATFORM_BUS_NUM_IRQS);
+ qdev_prop_set_uint32(dev, "mmio_size",
+ s->memmap[RVSERVER_PLATFORM_BUS].size);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ s->platform_bus_dev = dev;
+
+ sysbus = SYS_BUS_DEVICE(dev);
+ for (i = 0; i < RVSERVER_PLATFORM_BUS_NUM_IRQS; i++) {
+ int irq = RVSERVER_PLATFORM_BUS_IRQ + i;
+ sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
+ }
+
+ memory_region_add_subregion(sysmem,
+ s->memmap[RVSERVER_PLATFORM_BUS].base,
+ sysbus_mmio_get_region(sysbus, 0));
+}
+
static void create_pcie_irq_map(RISCVServerRefMachineState *s,
void *fdt, char *nodename,
uint32_t irqchip_phandle)
@@ -585,6 +622,16 @@ static void
create_fdt_socket_aplic(RISCVServerRefMachineState *s,
aplic_s_phandle, 0,
false, num_harts);
+ if (socket == 0) {
+ g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
+ MachineState *ms = MACHINE(s);
+
+ platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
+ s->memmap[RVSERVER_PLATFORM_BUS].base,
+ s->memmap[RVSERVER_PLATFORM_BUS].size,
+ RVSERVER_PLATFORM_BUS_IRQ);
+ }
+
aplic_phandles[socket] = aplic_s_phandle;
}
@@ -1265,6 +1312,8 @@ static void rvserver_ref_machine_init(MachineState
*machine)
gpex_pcie_init(system_memory, pcie_irqchip, s);
+ create_platform_bus(s, mmio_irqchip);
+
serial_mm_init(system_memory, memmap[RVSERVER_UART0].base,
0, qdev_get_gpio_in(mmio_irqchip, RVSERVER_UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN);
@@ -1341,10 +1390,38 @@ static void rvserver_ref_set_aia_guests(Object *obj,
const char *val,
}
}
+static HotplugHandler *rvserver_machine_get_hotplug_handler(MachineState *ms,
+ DeviceState *dev)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if (device_is_dynamic_sysbus(mc, dev)) {
+ return HOTPLUG_HANDLER(ms);
+ }
+
+ return NULL;
+}
+
+static void rvserver_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ RISCVServerRefMachineState *s = RISCV_SERVER_REF_MACHINE(hotplug_dev);
+
+ if (s->platform_bus_dev) {
+ MachineClass *mc = MACHINE_GET_CLASS(s);
+
+ if (device_is_dynamic_sysbus(mc, dev)) {
+ platform_bus_link_device(PLATFORM_BUS_DEVICE(s->platform_bus_dev),
+ SYS_BUS_DEVICE(dev));
+ }
+ }
+}
+
static void rvserver_ref_machine_class_init(ObjectClass *oc, const void *data)
{
char str[128];
MachineClass *mc = MACHINE_CLASS(oc);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
static const char * const valid_cpu_types[] = {
TYPE_RISCV_CPU_RVSERVER_REF,
};
@@ -1370,6 +1447,13 @@ static void rvserver_ref_machine_class_init(ObjectClass
*oc, const void *data)
sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
"should be between 0 and %d.", RVSERVER_IRQCHIP_MAX_GUESTS);
object_class_property_set_description(oc, "aia-guests", str);
+
+ assert(!mc->get_hotplug_handler);
+ mc->get_hotplug_handler = rvserver_machine_get_hotplug_handler;
+ hc->plug = rvserver_machine_device_plug_cb;
+#ifdef CONFIG_TPM
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
+#endif
}
static const TypeInfo rvserver_ref_typeinfo = {
@@ -1378,7 +1462,11 @@ static const TypeInfo rvserver_ref_typeinfo = {
.class_init = rvserver_ref_machine_class_init,
.instance_init = rvserver_ref_machine_instance_init,
.instance_size = sizeof(RISCVServerRefMachineState),
- .interfaces = riscv64_machine_interfaces,
+ .interfaces = (const InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { TYPE_TARGET_RISCV64_MACHINE },
+ { }
+ },
};
static void rvserver_ref_init_register_types(void)
--
2.43.0