On Thu, Jun 11, 2026 at 7:44 AM Daniel Henrique Barboza
<[email protected]> wrote:
>
> 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]>

Reviewed-by: Alistair Francis <[email protected]>

Alistair

> ---
>  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
>
>

Reply via email to