riscv: add initial RPMI virt support
Subsystems (2)
v15 cover riscv: add initial RPMI virt support
This series adds initial librpmi-backed RPMI support for the RISC-V virt machine. It covers the optional librpmi build dependency, RPMI transport and Base support, virt FDT wiring, System Reset, HSM, System Suspend, documentation, qtests, and a Linux guest smoke test.
librpmi provides the host-side RPMI service-group implementation used by this QEMU device model:
https://github.com/riscv-software-src/librpmi
Dependencies:
- librpmi 1.0.0 or newer, available from the upstream repository above or from the distribution packages documented in docs/system/riscv/virt.rst.
- A RISC-V toolchain and the firmware/kernel/rootfs artifacts required by the functional guest smoke test.
Changes since v14:
- [07/10] riscv: add RPMI system suspend service:
- Ran sashiko locally to weedout the review warnings.
- Check the callback hart index and target CPU before dereferencing configured hart state.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Check invalid System Suspend hart-ID rejection without a suspend event.
- [10/10] tests/functional: add initial RPMI virt guest smoke:
- Raise the outer Meson timeout above the test's 360-second timeout.
- Fail on the suspend failure marker without matching echoed shell input.
Changes since v13:
- Series-wide:
- Rebase onto QEMU master at
74f7bf4c59e6b6d50dbc6e124d93440be8be4386.
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Size each A2P request/ack queue from one quarter of shared memory after an 8 KiB allowance, increasing it from 1 KiB to 30 KiB. Retain the existing two-queue transport.
- [07/10] riscv: add RPMI system suspend service:
- Reject misaligned resume addresses and addresses outside the target hart's address width before accepting suspend, and require the resume PC to be backed by RAM in the active system-memory map.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Check resume-address alignment with and without compressed instructions, MMIO and unmapped-address rejection, RAM-backed addresses, RV32 width rejection for mapped RAM above 4 GiB, and recovery after rejection/reset without suspend side effects.
- Verify the enlarged DT queue ranges and last-data-slot wraparound, accounting for the head/tail metadata slots.
Changes since v12:
- Series-wide:
- Fix HSM stop completion after guest tests exposed divergence between cached RPMI hart state and actual WFI state, including HART_STOP failures after suspend/wakeup.
- Fold post-v12 review fixes and build corrections into their owning commits; retain the v12 FDT hierarchy/schema fix and earlier fixes.
- Drop earlier Reviewed-by tags from the materially rewritten HSM, System Suspend, and qtest patches.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Keep librpmi calls under existing BQL ownership because its environment lock hooks are no-ops.
- Remove unrelated global event polling from doorbell handling; service state transitions now drive their own event processing.
- Reject request queues too small to hold queue metadata and a data slot.
- Name the minimum queue size RPMI_DATA_SLOT_SIZE instead of repeating the head, tail, and data-slot size expression in queue validation.
- [03/10] hw/riscv: add RPMI FDT helpers:
- Remove duplicate helper arguments by passing the service configuration directly, and allow Base-only callers to omit the mailbox phandle.
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Keep this intermediate commit independently buildable before the reset service lands; retain legacy reset nodes until [05/10].
- Keep queue sizing local, drop the unused MSI phandle argument, and document the librpmi and TCG requirements.
- [05/10] riscv: add RPMI system reset service:
- Include the runstate API here so the callback-introducing commit builds independently.
- Preserve little-endian responses without alignment-unsafe buffer casts.
- [06/10] riscv: add RPMI HSM service:
- Complete accepted stop and suspend requests only when the target hart actually enters WFI; no later RPMI request is needed to publish the new state.
- Observe WFI persistently and replay the observer on the target CPU so stop requests arriving after WFI are not missed.
- Run HART_START on the target CPU, keep stopped harts off until that request, publish RPMI state under the BQL, and drain target-CPU work during teardown.
- Reconstruct HSM state on machine reset to avoid stale service state.
- [07/10] riscv: add RPMI system suspend service:
- Align suspend completion and wakeup with the corrected HSM transitions; process only its accepted event and avoid stale wakeup work on teardown.
- Recreate the suspend group around HSM reset reconstruction.
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Remove the obsolete RFC caveat now that the binding names are settled.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Match the non-executing qtest accelerator: expect pending states, reject HART_START while stop is pending, and check reset recovery.
- Remove an invalid target-PC assertion and use the negotiated response slot for variable-length replies.
- [10/10] tests/functional: add initial RPMI virt guest smoke:
- Bound the wait for online after CPU death: Linux's offline mask can precede firmware STOPPED. Keep transient errors visible and require eventual successful start; STOP_PENDING start rejection remains tested.
- Verify completed stop/start transitions, repeated stops, busy-hart stop, reboot recovery, and HSM operation after suspend/wakeup.
- Tighten console checks to prevent echoed commands or stale prompts from producing false passes, and fail on fatal firmware HSM diagnostics.
Changes since v11:
- Series-wide:
- Rebase the complete series onto QEMU master at
d73149283205645625bfa9fe029cfb68e4c4a9ae.
- Fold the FDT/schema review fix into the original commits.
- [03/10] hw/riscv: add RPMI FDT helpers:
- Emit RPMI service nodes as /soc siblings of the shared-memory mailbox.
- Remove shmem_base from the FDT service helper API.
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Update virt FDT wiring for the sibling service-node layout.
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Document the sibling service-node hierarchy and updated helper behavior.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Add DTB regression checks for sibling paths, mailbox phandles, service IDs, and rejection of the old mailbox-child hierarchy.
- [10/10] tests/functional: add initial RPMI virt guest smoke:
- Revalidate librpmi and no-librpmi builds, RPMI qtests, and real guest smoke tests after the FDT/schema fix.
Changes since v10:
- Series-wide:
- Fold the post-v10 mailing-list review fixes into the original commits.
- [01/10] build: add optional librpmi dependency:
- Add Reviewed-by tags from Alistair Francis and Sunil V L.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Replace legacy physical-memory helpers with QEMU address-space APIs.
- Propagate failed shared-memory transactions as RPMI_ERR_IO.
- Use address_space_set() for bulk shared-memory fills.
- Log failures from the void librpmi_env_writel() hook.
- Document the external librpmi_env.h environment-hook contract.
Changes since v9:
- Series-wide:
- Rebase on current QEMU master, commit 0a1ebd448b38.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Move the no-librpmi riscv_rpmi_create() stub into this patch where the public RPMI device API is introduced.
- Use enum rpmi_servicegroup_id for service-group identifiers from the first RPMI config definition, with no-librpmi fallback enum values for optional builds.
- [03/10] hw/riscv: add RPMI FDT helpers:
- Move the no-librpmi RPMI FDT helper stub into this patch where the helper prototypes are introduced.
- [05/10] riscv: add RPMI system reset service:
- Use the librpmi RPMI_SRVGRP_SYSTEM_RESET value directly instead of a QEMU-local service-group alias.
- Introduce the service-ops dispatch table in this patch, with the initial System Reset entry.
- [06/10] riscv: add RPMI HSM service:
- Use the librpmi RPMI_SRVGRP_HSM value directly instead of a QEMU-local service-group alias.
- Add only the HSM service entry on top of the System Reset service ops infrastructure.
- [07/10] riscv: add RPMI system suspend service:
- Use the librpmi RPMI_SRVGRP_SYSTEM_SUSPEND value directly instead of a QEMU-local service-group alias.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Drop future/unimplemented service-group definitions and probes from the qtest coverage. The test now covers only the initial Base, System Reset, HSM and System Suspend services.
Changes since v8:
- Series-wide:
- Rebase on current QEMU master, commit 539bc315538a.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Update the RPMI transport shared-memory helpers for the current physical_memory_read()/physical_memory_write() APIs.
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Add qtest coverage documentation alongside the existing firmware and guest smoke test notes.
Changes since v7:
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Drop the redundant internal RiscvRpmiServiceKind field from RiscvRpmiServiceConfig and use service_group as the single dispatch and FDT service identifier.
- [05/10] riscv: add RPMI system reset service:
- Move the RiscvRpmiServiceOps table and service_group lookup infrastructure into this patch, so the HSM and System Suspend patches only add their own service entries.
- [06/10] riscv: add RPMI HSM service:
- Build on the System Reset patch's service_group lookup infrastructure instead of introducing it here.
Changes since v6:
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- When RPMI is enabled, advertise reboot and shutdown through the RPMI System Reset service instead of the syscon reset nodes.
- [10/10] tests/functional: add initial RPMI virt guest smoke:
- Extend the functional guest smoke test to check the RPMI reboot and shutdown devices reported by firmware and exercise reboot.
Changes since v5:
- [01/10] build: add optional librpmi dependency:
- Fix the librpmi configure probe to check the system suspend service group API used by this initial series instead of the later logging API.
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Keep later SBI MPXY/FDT stubs out of the initial no-librpmi stub file; those stubs now live in the later stack layer where their prototypes are introduced.
Changes since v4:
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Drop the unused machine-opaque argument from the RPMI machine callback API.
- Move the no-librpmi riscv_rpmi_create() fallback out of the public header into hw/misc/riscv_rpmi-stub.c.
- Add a matching RPMI FDT helper stub for no-librpmi builds, while keeping the real rpmi-fdt.c source gated on CONFIG_RISCV_RPMI.
- [05/10] riscv: add RPMI system reset service:
- Drop the unused machine-opaque argument from the callback API.
- [06/10] riscv: add RPMI HSM service:
- Drop the unused machine-opaque argument from the callback API.
- [07/10] riscv: add RPMI system suspend service:
- Drop the unused machine-opaque argument from the callback API.
Changes since v3:
- [01/10] build: add optional librpmi dependency:
- Use "RPMI support" for librpmi-related Meson option and summary text.
- Add Reviewed-by tags from Daniel Henrique Barboza and Philippe Mathieu-Daude.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Use the Resettable API instead of device_class_set_legacy_reset().
- [03/10] hw/riscv: add RPMI FDT helpers:
- Gate the RPMI FDT helper source on CONFIG_RISCV_RPMI.
- Add Reviewed-by from Daniel Henrique Barboza.
- [04/10] hw/riscv/virt: add opt-in RPMI base support:
- Mark no-librpmi stub parameters with G_GNUC_UNUSED.
- [05/10] riscv: add RPMI system reset service:
- Add Reviewed-by from Daniel Henrique Barboza.
- [06/10] riscv: add RPMI HSM service:
- Add Reviewed-by from Daniel Henrique Barboza.
- [07/10] riscv: add RPMI system suspend service:
- Add Reviewed-by from Daniel Henrique Barboza.
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Add Reviewed-by from Daniel Henrique Barboza.
- [09/10] tests/qtest: cover initial RISC-V RPMI services:
- Add Reviewed-by from Daniel Henrique Barboza.
- [10/10] tests/functional: add initial RPMI virt guest smoke:
- Drop the stale Ventana copyright line.
Changes since v2:
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Document how to obtain and install librpmi for QEMU builds, including source builds, Debian/RPM packages, pkg-config setup, and the minimum librpmi version.
Changes since v1:
- Series-wide:
- Fold reviewer fixes into the original commits.
- [02/10] hw/misc: add RISC-V RPMI transport and Base support:
- Move Base service configuration into the Base support commit.
- [08/10] docs/system/riscv: document initial virt RPMI support:
- Document the RPMI v1.0 ratified context and specification references.
Testing:
- RISC-V builds with and without librpmi: passed.
- Without librpmi, the default virt machine realizes and explicit RPMI enablement rejects with the expected unsupported-build error.
- RPMI qtest suite: 20/20 subtests passed, including invalid hart-ID rejection and the existing resume-address, HSM and reset coverage.
- Linux guest functional suite: 6/6 tests passed, covering repeated and busy-hart HSM stop/start, stopped-hart reboot recovery, service enumeration, poweroff, reboot, and suspend/wakeup followed by HSM stop/start.
Subrahmanya Lingappa (10):
build: add optional librpmi dependency hw/misc: add RISC-V RPMI transport and Base support hw/riscv: add RPMI FDT helpers hw/riscv/virt: add opt-in RPMI base support
riscv: add RPMI system reset service
riscv: add RPMI HSM service
riscv: add RPMI system suspend service docs/system/riscv: document initial virt RPMI support tests/qtest: cover initial RISC-V RPMI services tests/functional: add initial RPMI virt guest smoke
Kconfig.host | 3 + MAINTAINERS | 3 + docs/system/riscv/virt.rst | 79 +++ hw/misc/Kconfig | 4 + hw/misc/meson.build | 8 + hw/misc/riscv_rpmi-stub.c | 16 + hw/misc/riscv_rpmi.c | 599 +++++++++++++++++++++++ hw/misc/riscv_rpmi_hsm.c | 359 ++++++++++++++ hw/misc/riscv_rpmi_internal.h | 43 ++ hw/misc/riscv_rpmi_sysreset.c | 185 +++++++ hw/misc/riscv_rpmi_syssusp.c | 210 ++++++++ hw/riscv/Kconfig | 1 + hw/riscv/fdt-common.c | 8 +- hw/riscv/meson.build | 3 + hw/riscv/rpmi-fdt-stub.c | 24 + hw/riscv/rpmi-fdt.c | 92 ++++ hw/riscv/server_platform_ref.c | 2 +- hw/riscv/virt.c | 144 +++++- include/hw/misc/riscv_rpmi.h | 112 +++++ include/hw/riscv/fdt-common.h | 3 +- include/hw/riscv/rpmi-fdt.h | 34 ++ include/hw/riscv/virt.h | 3 + meson.build | 14 + meson_options.txt | 2 + scripts/meson-buildoptions.sh | 3 + target/riscv/cpu-qom.h | 16 + target/riscv/cpu.c | 61 +++ target/riscv/cpu.h | 7 + target/riscv/tcg/op_helper.c | 4 + target/riscv/tcg/tcg-cpu.c | 1 + tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_rpmi_virt.py | 269 ++++++++++ tests/qtest/meson.build | 3 + tests/qtest/riscv-rpmi-test.c | 762 +++++++++++++++++++++++++++++++ 34 files changed, 3075 insertions(+), 4 deletions(-) create mode 100644 hw/misc/riscv_rpmi-stub.c create mode 100644 hw/misc/riscv_rpmi.c create mode 100644 hw/misc/riscv_rpmi_hsm.c create mode 100644 hw/misc/riscv_rpmi_internal.h create mode 100644 hw/misc/riscv_rpmi_sysreset.c create mode 100644 hw/misc/riscv_rpmi_syssusp.c create mode 100644 hw/riscv/rpmi-fdt-stub.c create mode 100644 hw/riscv/rpmi-fdt.c create mode 100644 include/hw/misc/riscv_rpmi.h create mode 100644 include/hw/riscv/rpmi-fdt.h create mode 100644 tests/functional/riscv64/test_rpmi_virt.py create mode 100644 tests/qtest/riscv-rpmi-test.c
base-commit: 74f7bf4c59e6b6d50dbc6e124d93440be8be4386
PATCH v15 1/10 build: add optional librpmi dependency
Add a meson option and config probe for librpmi so RISC-V machines can opt into RPMI support when the library is available. Keep the dependency optional so default builds without librpmi continue to work.
--- Kconfig.host | 3 +++ meson.build | 14 ++++++++++++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 4 files changed, 22 insertions(+)
Kconfig.host +3 -0
@@ -8,6 +8,9 @@ config LINUX config LIBCBOR bool +config LIBRPMI + bool + config GNUTLS bool
meson.build +14 -0
@@ -2026,6 +2026,17 @@ if lzo.found() and not cc.links(''' endif endif +librpmi = not_found +if not get_option('librpmi').auto() or have_system + librpmi = dependency('librpmi', required: get_option('librpmi'), + method: 'pkg-config') + if librpmi.found() and not cc.has_header_symbol('librpmi.h', + 'rpmi_service_group_syssusp_create', + dependencies: librpmi) + error('librpmi support requires the RPMI system suspend service group API') + endif +endif + numa = not_found if not get_option('numa').auto() or have_system or have_tools numa = cc.find_library('numa', has_headers: ['numa.h'],
@@ -2449,6 +2460,7 @@ config_host_data.set('CONFIG_LINUX', host_os == 'linux') config_host_data.set('CONFIG_POSIX', host_os != 'windows') config_host_data.set('CONFIG_WIN32', host_os == 'windows') config_host_data.set('CONFIG_LZO', lzo.found()) +config_host_data.set('CONFIG_LIBRPMI', librpmi.found()) config_host_data.set('CONFIG_MPATH', mpathpersist.found()) config_host_data.set('CONFIG_BLKIO', blkio.found()) if blkio.found()
@@ -3286,6 +3298,7 @@ host_kconfig = \ (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \ (vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \ (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \ + (librpmi.found() ? ['CONFIG_LIBRPMI=y'] : []) + \ (have_rust ? ['CONFIG_HAVE_RUST=y'] : []) ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR' ]
@@ -5036,6 +5049,7 @@ summary_info += {'TPM support': have_tpm} summary_info += {'IGVM support': igvm} summary_info += {'libssh support': libssh} summary_info += {'lzo support': lzo} +summary_info += {'RPMI support': librpmi} summary_info += {'snappy support': snappy} summary_info += {'bzip2 support': libbzip2} summary_info += {'lzfse support': liblzfse}
meson_options.txt +2 -0
@@ -208,6 +208,8 @@ option('lzfse', type : 'feature', value : 'auto', description: 'lzfse support for DMG images') option('lzo', type : 'feature', value : 'auto', description: 'lzo compression support') +option('librpmi', type : 'feature', value : 'auto', + description: 'RPMI support') option('pvg', type: 'feature', value: 'auto', description: 'macOS paravirtualized graphics support') option('rbd', type : 'feature', value : 'auto',
scripts/meson-buildoptions.sh +3 -0
@@ -147,6 +147,7 @@ meson_options_help() { printf "%s\n" ' libkeyutils Linux keyutils support' printf "%s\n" ' libnfs libnfs block device driver' printf "%s\n" ' libpmem libpmem support' + printf "%s\n" ' librpmi RPMI support' printf "%s\n" ' libssh ssh block device support' printf "%s\n" ' libudev Use libudev to enumerate host devices' printf "%s\n" ' libusb libusb support for USB passthrough'
@@ -390,6 +391,8 @@ _meson_option_parse() { --disable-libnfs) printf "%s" -Dlibnfs=disabled ;; --enable-libpmem) printf "%s" -Dlibpmem=enabled ;; --disable-libpmem) printf "%s" -Dlibpmem=disabled ;; + --enable-librpmi) printf "%s" -Dlibrpmi=enabled ;; + --disable-librpmi) printf "%s" -Dlibrpmi=disabled ;; --enable-libssh) printf "%s" -Dlibssh=enabled ;; --disable-libssh) printf "%s" -Dlibssh=disabled ;; --enable-libudev) printf "%s" -Dlibudev=enabled ;;
PATCH v15 2/10 hw/misc: add RISC-V RPMI transport and Base support
In reply to Subrahmanya LingappaRPMI (RISC-V Platform Management Interface) is the RISC-V non-ISA platform management specification. It defines a shared-memory transport, message protocol, and service groups for platform management.
Add the QEMU transport backend and Base service plumbing for virt using librpmi. Keep context lifecycle, service-group changes, and request dispatch under the existing device paths' BQL ownership. Document that the librpmi environment lock hooks are no-ops because QEMU provides synchronization at the call sites that need it.
This implementation targets the RISC-V Platform Management Interface (RPMI) Specification v1.0 Ratified:
https://github.com/riscv-non-isa/riscv-rpmi/releases/download/v1.0/riscv-rpmi.pdf
The librpmi backend is maintained at:
https://github.com/riscv-software-src/librpmi
--- MAINTAINERS | 2 + hw/misc/Kconfig | 4 + hw/misc/meson.build | 4 + hw/misc/riscv_rpmi-stub.c | 16 ++ hw/misc/riscv_rpmi.c | 514 ++++++++++++++++++++++++++++++++++ hw/misc/riscv_rpmi_internal.h | 25 ++ include/hw/misc/riscv_rpmi.h | 92 ++++++ 7 files changed, 657 insertions(+) create mode 100644 hw/misc/riscv_rpmi-stub.c create mode 100644 hw/misc/riscv_rpmi.c create mode 100644 hw/misc/riscv_rpmi_internal.h create mode 100644 include/hw/misc/riscv_rpmi.h
MAINTAINERS +2 -0
@@ -379,6 +379,8 @@ F: gdbstub/gdb-xml/riscv*.xml F: hw/char/riscv_htif.c F: hw/riscv/ F: hw/intc/riscv* +F: hw/misc/riscv_rpmi* +F: include/hw/misc/riscv_rpmi.h F: include/hw/char/riscv_htif.h F: include/hw/riscv/ F: common-user/host/riscv*
hw/misc/Kconfig +4 -0
@@ -303,3 +303,7 @@ source macio/Kconfig config QCOM_QDSP6SS_CLK bool + +config RISCV_RPMI + bool + depends on LIBRPMI
hw/misc/meson.build +4 -0
@@ -182,3 +182,7 @@ system_ss.add(when: 'CONFIG_AXIADO_CLK', if_true: files('axiado_clk.c')) # Qualcomm Hexagon DSP subsystems system_ss.add(when: 'CONFIG_QCOM_QDSP6SS_CLK', if_true: files('qcom-qdsp6ss-clk.c')) + +system_ss.add(when: 'CONFIG_RISCV_RPMI', if_true: [files( + 'riscv_rpmi.c', +), librpmi], if_false: files('riscv_rpmi-stub.c'))
hw/misc/riscv_rpmi-stub.c new file +16 -0
@@ -0,0 +1,16 @@ +/* +* RISC-V RPMI stubs. +* +* SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/misc/riscv_rpmi.h" + +DeviceState *riscv_rpmi_create(const RiscvRpmiConfig *cfg G_GNUC_UNUSED, +Error **errp) +{ +error_setg (errp,"RISC-V RPMI support is not compiled in" ); +return NULL ; +}
hw/misc/riscv_rpmi.c new file +514 -0
514 lines not on this page · raw message
hw/misc/riscv_rpmi_internal.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* RISC-V RPMI internal service helpers. +* +* Copyright (c) 2026 Qualcomm Technologies, Inc. +* Author: +* Subrahmanya Lingappa <[email protected]> +*/ + +#ifndef HW_MISC_RISCV_RPMI_INTERNAL_H +#define HW_MISC_RISCV_RPMI_INTERNAL_H + +#include "qapi/error.h" +#include "hw/misc/riscv_rpmi.h" +#include "librpmi.h" + +#define RPMI_PLAT_INFO "QEMU RISC-V RPMI" + +extern const struct rpmi_shmem_platform_ops rpmi_shmem_qemu_ops; +bool riscv_rpmi_service_enabled (RiscvRpmiState *s, +enum rpmi_servicegroup_id service_group); +void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s); + +#endif
include/hw/misc/riscv_rpmi.h new file +92 -0
92 lines not on this page · raw message
PATCH v15 3/10 hw/riscv: add RPMI FDT helpers
In reply to Subrahmanya LingappaAdd helper routines for describing RPMI shared-memory mailbox transports and sibling service nodes in the RISC-V virt device tree.
The helpers keep RPMI node construction in one place so the virt machine can add service groups without open-coding compatible strings, channel IDs, interrupts, and shared-memory references at each call site.
--- hw/riscv/meson.build | 3 ++ hw/riscv/rpmi-fdt-stub.c | 24 ++++++++++ hw/riscv/rpmi-fdt.c | 92 +++++++++++++++++++++++++++++++++++++ include/hw/riscv/rpmi-fdt.h | 34 ++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 hw/riscv/rpmi-fdt-stub.c create mode 100644 hw/riscv/rpmi-fdt.c create mode 100644 include/hw/riscv/rpmi-fdt.h
hw/riscv/meson.build +3 -0
@@ -5,6 +5,9 @@ riscv_ss.add(files('device-common.c')) riscv_ss.add(files('fdt-common.c')) riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c')) riscv_ss.add(files('riscv_hart.c')) +riscv_ss.add(when: 'CONFIG_RISCV_RPMI', + if_true: files('rpmi-fdt.c'), + if_false: files('rpmi-fdt-stub.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) riscv_ss.add(when: 'CONFIG_RISCV_SERVER_PLATFORM_REF', if_true: files('server_platform_ref.c'))
hw/riscv/rpmi-fdt-stub.c new file +24 -0
@@ -0,0 +1,24 @@ +/* +* RISC-V RPMI device-tree helper stubs. +* +* SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "qemu/osdep.h" +#include "hw/riscv/rpmi-fdt.h" + +void riscv_rpmi_fdt_add_mbox(void *fdt G_GNUC_UNUSED, + const RiscvRpmiFdtMboxConfig *cfg G_GNUC_UNUSED, + uint32_t *phandle G_GNUC_UNUSED, + uint32_t *mbox_handle G_GNUC_UNUSED) +{ +g_assert_not_reached (); +} + +void riscv_rpmi_fdt_add_service_node(void *fdt G_GNUC_UNUSED, + const RiscvRpmiServiceConfig *service +G_GNUC_UNUSED , + uint32_t mbox_handle G_GNUC_UNUSED) +{ +g_assert_not_reached (); +}
hw/riscv/rpmi-fdt.c new file +92 -0
92 lines not on this page · raw message
include/hw/riscv/rpmi-fdt.h new file +34 -0
@@ -0,0 +1,34 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* RISC-V RPMI device-tree helpers +* +* Copyright (c) 2026 Qualcomm Technologies, Inc. +* Author: +* Subrahmanya Lingappa <[email protected]> +*/ + +#ifndef HW_RISCV_RPMI_FDT_H +#define HW_RISCV_RPMI_FDT_H + +#include "exec/hwaddr.h" + +typedef struct RiscvRpmiServiceConfig RiscvRpmiServiceConfig ; + +typedef struct RiscvRpmiFdtMboxConfig { +hwaddr shmem_base; +hwaddr doorbell_base; +uint32_t a2p_req_size; +uint32_t p2a_req_size; +uint32_t doorbell_size; +}RiscvRpmiFdtMboxConfig ; + +void riscv_rpmi_fdt_add_mbox (void *fdt, +const RiscvRpmiFdtMboxConfig *cfg, +uint32_t *phandle, +uint32_t *mbox_handle); +void riscv_rpmi_fdt_add_service_node (void *fdt, +const RiscvRpmiServiceConfig *service, +uint32_t mbox_handle); + +#endif
PATCH v15 4/10 hw/riscv/virt: add opt-in RPMI base support
In reply to Subrahmanya LingappaAdd the virt machine rpmi=on/off option and wire the initial RPMI Base transport into machine realization for firmware clients that use RPMI platform management.
The option remains disabled by default. Enabling it requires a librpmi-enabled TCG build; KVM and builds without librpmi reject the configuration. The RPMI mailbox node is emitted when enabled, while the legacy reset and poweroff nodes remain available until the later service patches select the RPMI reset path.
Size each A2P queue from one quarter of shared memory after reserving 8 KiB: 30 KiB per queue on virt.
--- hw/riscv/Kconfig | 1 + hw/riscv/virt.c | 90 +++++++++++++++++++++++++++++++++++++++++ include/hw/riscv/virt.h | 3 ++ 3 files changed, 94 insertions(+)
hw/riscv/Kconfig +1 -0
@@ -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
hw/riscv/virt.c +90 -0
144 lines not on this page · raw message
include/hw/riscv/virt.h +3 -0
@@ -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,
PATCH v15 5/10 riscv: add RPMI system reset service
In reply to Subrahmanya LingappaAdd a QEMU implementation of the RPMI System Reset service group.
The service advertises shutdown and cold reboot reset types, validates guest requests, and dispatches accepted requests through machine reset and shutdown callbacks. This lets firmware use RPMI reset commands while keeping board-specific reset policy in the RISC-V machine.
--- hw/misc/meson.build | 1 + hw/misc/riscv_rpmi.c | 68 +++++++++++- hw/misc/riscv_rpmi_internal.h | 9 ++ hw/misc/riscv_rpmi_sysreset.c | 185 +++++++++++++++++++++++++++++++++ hw/riscv/fdt-common.c | 8 +- hw/riscv/server_platform_ref.c | 2 +- hw/riscv/virt.c | 46 +++++++- include/hw/misc/riscv_rpmi.h | 10 +- include/hw/riscv/fdt-common.h | 3 +- 9 files changed, 322 insertions(+), 10 deletions(-) create mode 100644 hw/misc/riscv_rpmi_sysreset.c
hw/misc/meson.build +1 -0
@@ -185,4 +185,5 @@ system_ss.add(when: 'CONFIG_QCOM_QDSP6SS_CLK', if_true: files('qcom-qdsp6ss-clk. system_ss.add(when: 'CONFIG_RISCV_RPMI', if_true: [files( 'riscv_rpmi.c', + 'riscv_rpmi_sysreset.c', ), librpmi], if_false: files('riscv_rpmi-stub.c'))
hw/misc/riscv_rpmi.c +65 -3
96 lines not on this page · raw message
hw/misc/riscv_rpmi_internal.h +9 -0
@@ -21,5 +21,14 @@ extern const struct rpmi_shmem_platform_ops rpmi_shmem_qemu_ops;bool riscv_rpmi_service_enabled (RiscvRpmiState *s,enum rpmi_servicegroup_id service_group);void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s); +bool riscv_rpmi_context_add_group (RiscvRpmiState *s, +struct rpmi_service_group *group, +const char *name, +Error **errp); +void riscv_rpmi_context_remove_group (RiscvRpmiState *s, +struct rpmi_service_group *group); + +bool riscv_rpmi_sysreset_add (RiscvRpmiState *s,Error **errp); +void riscv_rpmi_sysreset_remove (RiscvRpmiState *s);#endif
hw/misc/riscv_rpmi_sysreset.c new file +185 -0
185 lines not on this page · raw message
hw/riscv/fdt-common.c +7 -1
@@ -315,7 +315,8 @@ void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize)void riscv_create_fdt_syscon (void *fdt,uint32_t *next_phandle,hwaddr addr,hwaddr size,uint32_t reboot,uint32_t poweroff, -bool sifive_test_compat) +bool sifive_test_compat, +bool create_reset_nodes) {uint32_t syscon_phandle;char *name;
@@ -343,6 +344,11 @@ void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,g_free (name); +/* Some machines route reset and shutdown through another interface. */ +if (!create_reset_nodes) { +return ; + } + name =g_strdup_printf ("/reboot" );qemu_fdt_add_subnode (fdt, name);qemu_fdt_setprop_string (fdt, name,"compatible" ,"syscon-reboot" );
hw/riscv/server_platform_ref.c +1 -1
@@ -310,7 +310,7 @@ static void finalize_fdt(RISCVServerRefMachineState *s)riscv_create_fdt_syscon (ms->fdt, &phandle, rvserver_ref_memmap[RVSERVER_RESET_SYSCON ].base, rvserver_ref_memmap[RVSERVER_RESET_SYSCON ].size, -SYSCON_RESET ,SYSCON_POWEROFF , false); +SYSCON_RESET ,SYSCON_POWEROFF , false, true); riscv_create_fdt_uart(ms->fdt, &rvserver_ref_memmap[RVSERVER_UART0], RVSERVER_UART0_IRQ, AIA_TYPE_APLIC_IMSIC,
hw/riscv/virt.c +44 -2
83 lines not on this page · raw message
include/hw/misc/riscv_rpmi.h +8 -2
@@ -43,6 +43,11 @@ struct rpmi_service_group;struct rpmi_shmem ;struct rpmi_transport ; +typedef struct RiscvRpmiMachineOps { +void (*system_reset)(void ); +void (*system_shutdown)(void ); +}RiscvRpmiMachineOps ; + typedef struct RiscvRpmiServiceConfig { const char *node_name; const char *compatible;
@@ -58,7 +63,7 @@ typedef struct RiscvRpmiConfig {uint32_t a2p_req_size;uint32_t p2a_req_size;const char *platform_info; - +const RiscvRpmiMachineOps *machine_ops;const uint32_t *hart_ids;uint32_t hart_count;const RiscvRpmiServiceConfig *services;
@@ -75,7 +80,8 @@ struct RiscvRpmiState {uint32_t a2p_req_size;uint32_t p2a_req_size;char *platform_info; - +const RiscvRpmiMachineOps *machine_ops; +struct rpmi_service_group *sysreset_group;uint32_t *hart_ids;uint32_t hart_count;const RiscvRpmiServiceConfig *services;
include/hw/riscv/fdt-common.h +2 -1
@@ -103,7 +103,8 @@ void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize);void riscv_create_fdt_syscon (void *fdt,uint32_t *next_phandle,hwaddr addr,hwaddr size,uint32_t reboot,uint32_t poweroff, -bool sifive_test_compat); +bool sifive_test_compat, +bool create_reset_nodes); uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size, uint32_t *next_phandle, uint32_t irq_chip,
PATCH v15 6/10 riscv: add RPMI HSM service
In reply to Subrahmanya LingappaAdd the RPMI Hart State Management service group for RISC-V virt.
The service exposes configured hart IDs to librpmi and keeps stable per-hart state in the RPMI device. A persistent observer on each target CPU makes actual WFI entry authoritative for stop and suspend completion, while CPU work handles starts and requests received after a hart has already entered WFI.
Keep RPMI-stopped harts off despite pending interrupts, timer events, kicks, or generic resume attempts. HART_START is the normal path that restores the hart power state and execution address.
Serialize librpmi state publication under the BQL, drain target-CPU work during teardown, and reconstruct the external librpmi HSM object during machine reset so pending operations return to the STARTED baseline.
--- hw/misc/meson.build | 1 + hw/misc/riscv_rpmi.c | 7 + hw/misc/riscv_rpmi_hsm.c | 344 ++++++++++++++++++++++++++++++++++ hw/misc/riscv_rpmi_internal.h | 5 +- hw/riscv/virt.c | 5 + include/hw/misc/riscv_rpmi.h | 5 + target/riscv/cpu-qom.h | 16 ++ target/riscv/cpu.c | 61 ++++++ target/riscv/cpu.h | 7 + target/riscv/tcg/op_helper.c | 4 + target/riscv/tcg/tcg-cpu.c | 1 + 11 files changed, 455 insertions(+), 1 deletion(-) create mode 100644 hw/misc/riscv_rpmi_hsm.c
hw/misc/meson.build +1 -0
@@ -186,4 +186,5 @@ system_ss.add(when: 'CONFIG_QCOM_QDSP6SS_CLK', if_true: files('qcom-qdsp6ss-clk. system_ss.add(when: 'CONFIG_RISCV_RPMI', if_true: [files( 'riscv_rpmi.c', 'riscv_rpmi_sysreset.c', + 'riscv_rpmi_hsm.c', ), librpmi], if_false: files('riscv_rpmi-stub.c'))
hw/misc/riscv_rpmi.c +7 -0
@@ -210,6 +210,10 @@ static const RiscvRpmiServiceOps riscv_rpmi_service_ops[] = { .service_group = RPMI_SRVGRP_SYSTEM_RESET, .add = riscv_rpmi_sysreset_add, .remove = riscv_rpmi_sysreset_remove, + }, { + .service_group = RPMI_SRVGRP_HSM, + .add = riscv_rpmi_hsm_add, + .remove = riscv_rpmi_hsm_remove, }, };
@@ -259,6 +263,9 @@ static void riscv_rpmi_reset_hold(Object *obj, ResetType type)memset (memory_region_get_ram_ptr (&s->shmem),0 , s->shmem_size);memory_region_set_dirty (&s->shmem,0 , s->shmem_size); } +if (!riscv_rpmi_hsm_reset (s, &error_abort)) { +return ; + } }static void riscv_rpmi_cleanup (RiscvRpmiState *s)
hw/misc/riscv_rpmi_hsm.c new file +344 -0
344 lines not on this page · raw message
hw/misc/riscv_rpmi_internal.h +4 -1
@@ -27,8 +27,11 @@ bool riscv_rpmi_context_add_group(RiscvRpmiState *s, Error **errp);void riscv_rpmi_context_remove_group (RiscvRpmiState *s,struct rpmi_service_group *group); -bool riscv_rpmi_sysreset_add (RiscvRpmiState *s,Error **errp);void riscv_rpmi_sysreset_remove (RiscvRpmiState *s); +bool riscv_rpmi_hsm_add (RiscvRpmiState *s,Error **errp); +void riscv_rpmi_hsm_remove (RiscvRpmiState *s); +bool riscv_rpmi_hsm_reset (RiscvRpmiState *s,Error **errp); +#endif
hw/riscv/virt.c +5 -0
@@ -485,6 +485,11 @@ static const RiscvRpmiServiceConfig virt_rpmi_services[] = { .compatible = "riscv,rpmi-system-reset", .service_group = RPMI_SRVGRP_SYSTEM_RESET, }, + { + .node_name = "hsm", + .compatible = "riscv,rpmi-hsm", + .service_group = RPMI_SRVGRP_HSM, + }, };static uint32_t virt_rpmi_service_count (void )
include/hw/misc/riscv_rpmi.h +5 -0
@@ -42,6 +42,8 @@ struct rpmi_context;struct rpmi_service_group ;struct rpmi_shmem ;struct rpmi_transport ; +struct rpmi_hsm ; +typedef struct RiscvRpmiHsmHart RiscvRpmiHsmHart ; typedef struct RiscvRpmiMachineOps { void (*system_reset)(void);
@@ -82,6 +84,9 @@ struct RiscvRpmiState {char *platform_info;const RiscvRpmiMachineOps *machine_ops;struct rpmi_service_group *sysreset_group; +struct rpmi_hsm *hsm; +struct rpmi_service_group *hsm_group; +RiscvRpmiHsmHart *hsm_harts;uint32_t *hart_ids;uint32_t hart_count;const RiscvRpmiServiceConfig *services;
target/riscv/cpu-qom.h +16 -0
@@ -64,4 +64,20 @@ OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) +#ifndef CONFIG_USER_ONLY +/* +* WFI observers persist across entries and exits. Access observers and WFI +* state only on the target CPU thread; use run_on_cpu() to register or remove +* an observer and drain earlier CPU work before freeing its opaque state. +*/ +void riscv_cpu_set_wfi_observer ( +CPUState *cpu, +void (*observer)(CPUState *cpu,bool entering,void *opaque), +void *opaque); +void riscv_cpu_handle_wfi (CPUState *cpu); +void riscv_cpu_handle_wfi_resume (CPUState *cpu); +void riscv_cpu_replay_wfi_observer (CPUState *cpu); +void riscv_cpu_set_powered_off (CPUState *cpu,bool powered_off); +#endif +#endif /* RISCV_CPU_QOM_H */
target/riscv/cpu.c +61 -0
79 lines not on this page · raw message
target/riscv/cpu.h +7 -0
@@ -577,6 +577,13 @@ struct ArchCPU {CPURISCVState env; +#ifndef CONFIG_USER_ONLY +void (*wfi_observer)(CPUState *,bool ,void *); +void *wfi_observer_opaque; +bool wfi_active; +bool powered_off; +#endif +GDBFeature dyn_csr_feature;GDBFeature dyn_vreg_feature;
target/riscv/tcg/op_helper.c +4 -0
@@ -644,6 +644,10 @@ void HELPER(wfi)(CPURISCVState *env)return ; } cs->halted =1 ; +#ifndef CONFIG_USER_ONLY +/* Publish WFI only after QEMU has entered the halted state. */ +riscv_cpu_handle_wfi (cs); +#endif cs->exception_index =EXCP_HLT ;cpu_loop_exit (cs); }
target/riscv/tcg/tcg-cpu.c +1 -0
@@ -305,6 +305,7 @@ const TCGCPUOps riscv_tcg_ops = { .tlb_fill = riscv_cpu_tlb_fill, .pointer_wrap = riscv_pointer_wrap, .cpu_exec_enter = riscv_cpu_exec_enter, + .leaving_halt = riscv_cpu_handle_wfi_resume, .cpu_exec_interrupt = riscv_cpu_exec_interrupt, .cpu_exec_reset = cpu_reset, .do_interrupt = riscv_cpu_do_interrupt,
PATCH v15 7/10 riscv: add RPMI system suspend service
In reply to Subrahmanya LingappaAdd the RPMI System Suspend service group for RISC-V virt.
The service advertises suspend-to-RAM support through librpmi, registers QEMU wakeup support, and routes the finalize callback to the generic system suspend path. Process only the accepted System Suspend event instead of polling every RPMI service group from an unrelated doorbell request.
On wakeup, publish the suspend event under the BQL and defer the HSM hart resume until vCPUs are ready to run. Cancel stale wakeup work during teardown. Machine reset removes and recreates System Suspend around HSM reconstruction so the service always references the current HSM object.
Reject malformed resume addresses before accepting suspend. Require the target hart's configured instruction alignment and address width, and verify that the resume PC is backed by RAM in the active system-memory map.
Validate the librpmi hart index and target CPU before accessing hart state.
--- hw/misc/meson.build | 2 + hw/misc/riscv_rpmi.c | 30 +++-- hw/misc/riscv_rpmi_hsm.c | 15 +++ hw/misc/riscv_rpmi_internal.h | 8 +- hw/misc/riscv_rpmi_syssusp.c | 210 ++++++++++++++++++++++++++++++++++ hw/riscv/virt.c | 5 + include/hw/misc/riscv_rpmi.h | 9 ++ 7 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 hw/misc/riscv_rpmi_syssusp.c
hw/misc/meson.build +2 -0
@@ -188,3 +188,5 @@ system_ss.add(when: 'CONFIG_RISCV_RPMI', if_true: [files( 'riscv_rpmi_sysreset.c', 'riscv_rpmi_hsm.c', ), librpmi], if_false: files('riscv_rpmi-stub.c')) +specific_ss.add(when: 'CONFIG_RISCV_RPMI', + if_true: [files('riscv_rpmi_syssusp.c'), librpmi])
hw/misc/riscv_rpmi.c +23 -7
@@ -214,6 +214,10 @@ static const RiscvRpmiServiceOps riscv_rpmi_service_ops[] = { .service_group = RPMI_SRVGRP_HSM, .add = riscv_rpmi_hsm_add, .remove = riscv_rpmi_hsm_remove, + }, { + .service_group = RPMI_SRVGRP_SYSTEM_SUSPEND, + .add = riscv_rpmi_syssusp_add, + .remove = riscv_rpmi_syssusp_remove, }, };
@@ -256,6 +260,7 @@ static void riscv_rpmi_init(Object *obj)static void riscv_rpmi_reset_hold (Object *obj,ResetType type) {RiscvRpmiState *s =RISCV_RPMI (obj); +bool reset_syssusp = s->syssusp_group !=NULL ; s->doorbell =0 ;
@@ -263,9 +268,15 @@ static void riscv_rpmi_reset_hold(Object *obj, ResetType type)memset (memory_region_get_ram_ptr (&s->shmem),0 , s->shmem_size);memory_region_set_dirty (&s->shmem,0 , s->shmem_size); } +if (reset_syssusp) { +riscv_rpmi_syssusp_remove (s); + }if (!riscv_rpmi_hsm_reset (s, &error_abort)) {return ; } +if (reset_syssusp && !riscv_rpmi_syssusp_add (s, &error_abort)) { +return ; + } }static void riscv_rpmi_cleanup (RiscvRpmiState *s)
@@ -309,13 +320,6 @@ bool riscv_rpmi_service_enabled(RiscvRpmiState *s,return false; } -void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s) -{ -if (s->context) { -rpmi_context_process_a2p_request (s->context); - } -} - bool riscv_rpmi_context_add_group(RiscvRpmiState *s, struct rpmi_service_group *group, const char *name,
@@ -340,6 +344,18 @@ void riscv_rpmi_context_remove_group(RiscvRpmiState *s, } } +void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s) +{ +if (s->context) { +rpmi_context_process_a2p_request (s->context); +if (s->syssusp_event_pending && s->syssusp_group) { + s->syssusp_event_pending = false; +rpmi_context_process_group_events (s->context, +RPMI_SRVGRP_SYSTEM_SUSPEND ); + } + } +} +static bool riscv_rpmi_validate_config (RiscvRpmiState *s,Error **errp) {uint64_t queue_bytes;
hw/misc/riscv_rpmi_hsm.c +15 -0
@@ -42,6 +42,7 @@ static RiscvRpmiHsmHart *riscv_rpmi_hsm_hart(RiscvRpmiState *s,return &s->hsm_harts[hart_index]; } +static void riscv_rpmi_hsm_wfi (CPUState *cpu,bool entering,void *opaque) {RiscvRpmiHsmHart *hart = opaque;
@@ -342,3 +343,17 @@ bool riscv_rpmi_hsm_reset(RiscvRpmiState *s, Error **errp) s->hsm_group = group;return true; } + +void riscv_rpmi_hsm_resume (RiscvRpmiState *s,uint32_t hart_index, +uint64_t resume_addr) +{ +RiscvRpmiHsmHart *hart =riscv_rpmi_hsm_hart (s, hart_index); + +if (!hart) { +return ; + } + + hart->start_addr = resume_addr; +run_on_cpu (hart->cpu, riscv_rpmi_hsm_start_cpu, +RUN_ON_CPU_HOST_PTR (hart)); +}
hw/misc/riscv_rpmi_internal.h +7 -1
@@ -20,18 +20,24 @@extern const struct rpmi_shmem_platform_ops rpmi_shmem_qemu_ops;bool riscv_rpmi_service_enabled (RiscvRpmiState *s,enum rpmi_servicegroup_id service_group); -void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s);bool riscv_rpmi_context_add_group (RiscvRpmiState *s,struct rpmi_service_group *group,const char *name,Error **errp);void riscv_rpmi_context_remove_group (RiscvRpmiState *s,struct rpmi_service_group *group); +void riscv_rpmi_context_process_a2p_request (RiscvRpmiState *s); +bool riscv_rpmi_sysreset_add (RiscvRpmiState *s,Error **errp);void riscv_rpmi_sysreset_remove (RiscvRpmiState *s);bool riscv_rpmi_hsm_add (RiscvRpmiState *s,Error **errp);void riscv_rpmi_hsm_remove (RiscvRpmiState *s);bool riscv_rpmi_hsm_reset (RiscvRpmiState *s,Error **errp); +void riscv_rpmi_hsm_resume (RiscvRpmiState *s,uint32_t hart_index, +uint64_t resume_addr); + +bool riscv_rpmi_syssusp_add (RiscvRpmiState *s,Error **errp); +void riscv_rpmi_syssusp_remove (RiscvRpmiState *s);#endif
hw/misc/riscv_rpmi_syssusp.c new file +210 -0
210 lines not on this page · raw message
hw/riscv/virt.c +5 -0
@@ -490,6 +490,11 @@ static const RiscvRpmiServiceConfig virt_rpmi_services[] = { .compatible = "riscv,rpmi-hsm", .service_group = RPMI_SRVGRP_HSM, }, + { + .node_name = "suspend", + .compatible = "riscv,rpmi-system-suspend", + .service_group = RPMI_SRVGRP_SYSTEM_SUSPEND, + }, };static uint32_t virt_rpmi_service_count (void )
include/hw/misc/riscv_rpmi.h +9 -0
@@ -13,6 +13,8 @@#include "exec/hwaddr.h" #include "hw/core/sysbus.h" +#include "qemu/notify.h" +#include "qemu/timer.h" #include "qom/object.h" #ifdef CONFIG_LIBRPMI
@@ -84,9 +86,16 @@ struct RiscvRpmiState {char *platform_info;const RiscvRpmiMachineOps *machine_ops;struct rpmi_service_group *sysreset_group; +struct rpmi_service_group *syssusp_group;struct rpmi_hsm *hsm;struct rpmi_service_group *hsm_group;RiscvRpmiHsmHart *hsm_harts; +bool syssusp_event_pending; +Notifier wakeup_notifier; +QEMUTimer *wakeup_timer; +bool syssusp_resume_pending; +uint32_t syssusp_resume_hart_index; +uint64_t syssusp_resume_addr;uint32_t *hart_ids;uint32_t hart_count;const RiscvRpmiServiceConfig *services;
PATCH v15 8/10 docs/system/riscv: document initial virt RPMI support
In reply to Subrahmanya LingappaDocument the opt-in virt RPMI transport and the initial HSM, system reset, and system suspend service groups.
--- docs/system/riscv/virt.rst | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
docs/system/riscv/virt.rst +79 -0
@@ -149,6 +149,85 @@ The following machine-specific options are supported: Enables the riscv-iommu-sys platform device. Defaults to 'off'. +- rpmi=[on|off] + + Enables the RISC-V RPMI shared-memory transport. This option defaults to + "off", is TCG-only, and is available only when QEMU is built with librpmi + support. This support targets the RISC-V Platform Management Interface + (RPMI) Specification v1.0 Ratified (`RPMI v1.0 specification`_). The initial + ``virt`` implementation exposes RPMI system reset, system suspend, and HSM + service groups. System reset can request shutdown or cold reboot through + RPMI. HSM uses the ``virt`` hart IDs and supports hart discovery, status, + start, stop, and suspend commands. System suspend uses QEMU's suspend and + wakeup path. Migration is currently blocked while RPMI transport and service + VMState support is being designed. + + The build dependency is provided by `librpmi`_. QEMU requires librpmi 1.0.0 + or newer. If the host distribution does not provide a librpmi development + package, build and install it from the upstream source tree so that + ``pkg-config`` can find ``librpmi.pc``: + + .. code-block:: bash + + $ git clone https://github.com/riscv-software-src/librpmi.git + $ cd librpmi + $ make + $ make install I=/usr/local + $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH + $ pkg-config --modversion librpmi + + The librpmi repository can also generate installable ``librpmi-dev`` Debian + packages with ``make deb-pkg`` and ``librpmi-devel`` RPM packages with + ``make rpm-pkg``. After installing librpmi, configure QEMU with + ``--enable-librpmi`` or ``-Dlibrpmi=enabled``. + +.. _RPMI v1.0 specification: https://github.com/riscv-non-isa/riscv-rpmi/releases/download/v1.0/riscv-rpmi.pdf +.. _librpmi: https://github.com/riscv-software-src/librpmi + +RPMI qtest coverage +------------------- + +QEMU includes qtest coverage for the RPMI transport and the initial service +groups in ``tests/qtest/riscv-rpmi-test.c``. To run the qtest from a build +configured with librpmi support and the ``riscv64-softmmu`` target: + +.. code-block:: bash + + $ meson test -C build qemu:qtest-riscv64/riscv-rpmi-test + +The qtest covers Base service discovery, System Reset, HSM, System Suspend, +negative transport cases, reset behavior, and migration blocking while RPMI +VMState support is being designed. + +RPMI firmware and guest smoke +----------------------------- + +A firmware-level RPMI smoke test can be run with OpenSBI, a Linux kernel, and a +RISC-V disk image: + +.. code-block:: bash + + $ qemu-system-riscv64 \ + -machine virt,rpmi=on \ + -cpu rv64 -smp 4 -m 4G -nographic \ + -bios /path/to/fw_jump.bin \ + -kernel /path/to/Image \ + -append "root=/dev/vda rw console=ttyS0 earlycon=sbi" \ + -drive file=/path/to/rootfs.img,format=raw,if=virtio,snapshot=on + +The OpenSBI banner should report RPMI-backed HSM and system suspend support. +After the guest reaches a shell, normal guest reboot/poweroff commands exercise +the RPMI system reset path. + +RPMI device tree policy +----------------------- + +RPMI is currently described through FDT only; no ACPI representation is emitted +for the RPMI transport or service groups. The ``virt`` machine uses the +``riscv,rpmi-shmem-mbox`` shared-memory mailbox node plus sibling service nodes +with ``riscv,rpmi-*`` compatible strings. Each service node references the +mailbox with an ``mboxes`` property containing the RPMI service-group ID. + Running Linux kernel --------------------
PATCH v15 9/10 tests/qtest: cover initial RISC-V RPMI services
In reply to Subrahmanya LingappaAdd qtests for the RPMI transport plus Base, system reset, HSM, and system suspend service groups.
The qtest accelerator does not execute a target hart to WFI, so check that stop and suspend remain pending rather than treating the request as immediately complete. Verify that HART_START is denied while stop is pending and that machine reset returns pending HSM state to STARTED before accepting fresh stop and suspend requests.
Check System Suspend resume-address rejection without a suspend event or runstate change. Cover instruction alignment with and without compressed instructions, MMIO and unmapped addresses, RAM-backed addresses, RV32 width rejection for mapped RAM above 4 GiB, and recovery after rejection/reset. Check that an invalid System Suspend hart ID is rejected without a suspend event.
Check the enlarged virt queue ranges in the DT and exercise queue-boundary rejection and wraparound at the last data slot.
--- MAINTAINERS | 1 + tests/qtest/meson.build | 3 + tests/qtest/riscv-rpmi-test.c | 762 ++++++++++++++++++++++++++++++++++ 3 files changed, 766 insertions(+) create mode 100644 tests/qtest/riscv-rpmi-test.c
MAINTAINERS +1 -0
@@ -381,6 +381,7 @@ F: hw/riscv/ F: hw/intc/riscv* F: hw/misc/riscv_rpmi* F: include/hw/misc/riscv_rpmi.h +F: tests/qtest/riscv-rpmi-test.c F: include/hw/char/riscv_htif.h F: include/hw/riscv/ F: common-user/host/riscv*
tests/qtest/meson.build +3 -0
@@ -317,6 +317,8 @@ qtests_riscv32 = \ qtests_riscv64 = ['riscv-csr-test'] + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ + (config_all_devices.has_key('CONFIG_RISCV_RPMI') ? + ['riscv-rpmi-test'] : []) + \ (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \
@@ -442,6 +444,7 @@ qtests = { 'pnv-xive2-test': files('pnv-xive2-common.c', 'pnv-xive2-flush-sync.c', 'pnv-xive2-nvpg_bar.c'), 'qos-test': [chardev, io, qos_test_ss.apply({}).sources()], + 'riscv-rpmi-test': [files('riscv-rpmi-test.c'), fdt], 'tpm-crb-swtpm-test': [io, tpmemu_files], 'tpm-crb-test': [io, tpmemu_files], 'tpm-tis-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
tests/qtest/riscv-rpmi-test.c new file +762 -0
762 lines not on this page · raw message
PATCH v15 10/10 tests/functional: add initial RPMI virt guest smoke
In reply to Subrahmanya LingappaBoot an RPMI-enabled RISC-V virt guest and exercise the initial HSM, system suspend, and system reset paths.
Require completed CPU offline and online transitions for HSM stop/start, repeat the cycle, and stop a hart running a busy workload. Reboot while a secondary hart remains stopped, verify the next boot restores both harts, and repeat HSM control afterward. Also cover HSM stop/start immediately after suspend/wakeup and a fresh suspend cycle after reboot.
Reject definitive OpenSBI HSM failure diagnostics instead of accepting a shell marker that only appeared in the echoed command.
Linux can report CPU death before firmware reaches STOPPED. Bound retries of the subsequent online request, retain transient errors in the console, and require a completed online transition rather than assuming that an offline sysfs mask proves immediate firmware stop completion.
Allow the outer Meson timeout to exceed the test's 360-second timeout. Fail immediately on the suspend failure marker, and split that marker in the shell command so echoed input cannot trigger it.
--- tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_rpmi_virt.py | 269 +++++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 tests/functional/riscv64/test_rpmi_virt.py
tests/functional/riscv64/meson.build +2 -0
@@ -5,6 +5,7 @@ test_riscv64_timeouts = { 'k230' : 120, 'server_ref' : 120, 'tuxrun' : 120, + 'rpmi_virt' : 420, } tests_riscv64_system_quick = [
@@ -21,4 +22,5 @@ tests_riscv64_system_thorough = [ 'tt_atlantis', 'tuxrun', 'milkv_duo', + 'rpmi_virt', ]
tests/functional/riscv64/test_rpmi_virt.py new file +269 -0
269 lines not on this page · raw message