hw/riscv: add RPMI support for server reference platform
Subsystems (2)
v5 cover hw/riscv: add RPMI support for server reference platform
Add RPMI transport and service-group support to the RISC-V Server Platform Reference Board. The series applies on top of the initial RPMI virt support series and wires the board's reset, HSM, and system-suspend operations to the same librpmi-backed implementation used by ``virt``.
The RPMI FDT service nodes are emitted as ``/soc/<service>`` siblings of the shared-memory mailbox. Each node keeps its ``mboxes`` phandle and service-group ID, and the server-reference qtest checks this hierarchy as a regression.
Dependencies:
- [PATCH v15 00/10] riscv: add initial RPMI virt support.
- The server-reference board is already present in QEMU master at 74f7bf4c59e6b6d50dbc6e124d93440be8be4386.
Changes since v4:
- Rebase onto the updated initial RPMI v15 prerequisite; server-reference code is unchanged. Wrap one long assertion in the qtest.
Changes since v3:
- Rebase onto QEMU master and the initial RPMI v14 prerequisite.
- Keep the board integration and its queue sizes unchanged.
- [2/2] tests/qtest: cover server reference platform RPMI:
- Use per-machine queue sizes in the shared harness: virt uses 30 KiB queues while server-reference retains 1 KiB queues. Derive acknowledgement offsets and ring moduli accordingly.
- Inherit resume-address coverage for RAM-backed PCs, MMIO and unmapped rejection, and RV32 width checks on mapped high RAM.
Changes since v2:
- Rebase the server-reference integration onto QEMU master and the v13 RPMI virt prerequisite.
- [1/2] hw/riscv: add RPMI support for server reference platform:
- Add an explicit ``rpmi=on|off`` property, defaulting to off so the existing board remains migratable and retains its legacy reset/poweroff device-tree nodes.
- Gate RPMI realization, reset/shutdown callbacks, and service nodes on the property; reject explicit enablement for KVM and no-librpmi builds.
- Document the property, migration restriction, build requirements, and both device-tree layouts.
- [2/2] tests/qtest: cover server reference platform RPMI:
- Reuse the common RPMI protocol tests and register the server-reference machine-specific subset.
- Add checks for default/off and explicit-on machine policy, service-node sibling placement, mailbox phandles and service IDs, legacy syscon nodes, and migration behavior.
- Name the RPMI-off migration test as a policy-command acceptance check; it does not restore a destination VM.
Testing:
- Combined RPMI-enabled RISC-V build: passed.
- RPMI/server-reference qtests: 30/30 subtests passed.
- Server-reference guest boots were not rerun on the updated v15 base.
Subrahmanya Lingappa (2):
hw/riscv: add RPMI support for server reference platform tests/qtest: cover server reference platform RPMI
docs/system/riscv/riscv-server-ref.rst | 43 ++++ hw/riscv/Kconfig | 1 + hw/riscv/server_platform_ref.c | 149 ++++++++++- meson.build | 4 + tests/qtest/riscv-rpmi-test.c | 435 +++++++++++++++++++++++++-------- 5 files changed, 532 insertions(+), 100 deletions(-)
base-commit: 1833f648bc88dc8905ee8adce5e1363639594a68
PATCH v5 1/2 hw/riscv: add RPMI support for server reference platform
Add opt-in RPMI platform management to the riscv-server-ref machine for firmware clients that use the RPMI transport.
RPMI is disabled by default so the existing board remains migratable and retains its legacy reset and poweroff device-tree nodes. The rpmi=on option realizes the unmigratable RPMI device, advertises the Base, System Reset, HSM, and System Suspend services, and omits those legacy nodes.
Explicit RPMI enablement rejects KVM and builds without librpmi. Document the property, migration restriction, build requirements, and both device-tree layouts.
--- docs/system/riscv/riscv-server-ref.rst | 43 +++++++ hw/riscv/Kconfig | 1 + hw/riscv/server_platform_ref.c | 149 ++++++++++++++++++++++++- meson.build | 4 + 4 files changed, 195 insertions(+), 2 deletions(-)
docs/system/riscv/riscv-server-ref.rst +43 -0
@@ -28,6 +28,7 @@ The main features included in the riscv-server-ref board are: * No fw_cfg device * No ACPI table * Minimal device tree nodes +* RISC-V RPMI platform management There are multiple ways of using this reference board. The spec compliant way is using an EDK2 image and a TPM device. The board was tested with the TPM
@@ -60,6 +61,48 @@ And then start QEMU with: -netdev user,id=net0 -device e1000e,netdev=net0 \ -nographic +RPMI support +------------ + +The ``riscv-server-ref`` machine exposes RISC-V RPMI platform management when +the ``rpmi=on`` machine option is selected and QEMU is built with librpmi +support. RPMI is disabled by default. ``rpmi=off`` preserves the legacy +device tree and keeps the board migratable. An RPMI-enabled machine contains +an unmigratable RPMI device, so live migration is unavailable while +``rpmi=on`` is selected. RPMI is unavailable with KVM and requires a build +with librpmi. + +The initial ``riscv-server-ref`` RPMI implementation exposes Base, System +Reset, HSM, and System Suspend service groups. System Reset handles guest +shutdown and cold reboot requests through RPMI. +HSM uses the machine hart IDs for hart discovery, status, start, stop, and +suspend commands. System Suspend uses QEMU's suspend and wakeup path. + +When ``rpmi=on`` is selected, the generated device tree advertises reset, +shutdown, HSM, and suspend through RPMI service nodes and omits the legacy +syscon reboot and poweroff nodes. With the default ``rpmi=off`` setting, the +generated device tree retains the legacy syscon reboot and poweroff nodes. +RPMI is currently described through FDT only; this machine does not emit ACPI +tables for the RPMI transport or service groups. + +RPMI support targets the RISC-V Platform Management Interface (RPMI) +Specification v1.0 Ratified (`server-ref RPMI v1.0 specification`_). The +build dependency is provided by `server-ref librpmi`_. After installing +librpmi, configure QEMU with ``--enable-librpmi`` or ``-Dlibrpmi=enabled`` to +make the build fail if librpmi is unavailable. + +.. code-block:: bash + + qemu-system-riscv64 -M riscv-server-ref,rpmi=on \ + -bios fw_dynamic.bin \ + -kernel EDK2.fd \ + -drive file=nvme_disk.ext2,format=raw,id=hd0,if=none \ + -device ahci,id=ahci \ + -device ide-hd,drive=hd0,bus=ahci.0 \ + -nographic + .. _spec: https://github.com/riscv-non-isa/riscv-server-platform .. _tpm: https://qemu-project.gitlab.io/qemu/specs/tpm.html +.. _server-ref RPMI v1.0 specification: https://github.com/riscv-non-isa/riscv-rpmi/releases/download/v1.0/riscv-rpmi.pdf +.. _server-ref librpmi: https://github.com/riscv-software-src/librpmi
hw/riscv/Kconfig +1 -0
@@ -86,6 +86,7 @@ config RISCV_SERVER_PLATFORM_REF select RISCV_IOMMU select RISCV_NUMA select SERIAL_MM + select RISCV_RPMI if LIBRPMI config SHAKTI_C bool
hw/riscv/server_platform_ref.c +147 -2
235 lines not on this page · raw message
meson.build +4 -0
@@ -3444,6 +3444,10 @@ foreach target : target_dirs foreach k, v: config_devices config_devices_data.set(k, 1) endforeach + if target == 'riscv64-softmmu' and get_option('default_devices') and \ + not librpmi.found() + warning('riscv-server-ref machine will be built without RPMI support; install librpmi and configure with --enable-librpmi to enable RPMI') + endif config_devices_mak_list += config_devices_mak config_devices_h += {target: configure_file(output: target + '-config-devices.h', configuration: config_devices_data)}
PATCH v5 2/2 tests/qtest: cover server reference platform RPMI
In reply to Subrahmanya LingappaExercise the server-reference RPMI policy alongside the shared protocol tests. Cover explicit and default RPMI-off realization, RPMI-on service discovery, FDT layouts, and migration behavior for both property states.
The FDT checks verify mailbox phandles, service IDs, sibling placement, and preservation of the legacy syscon nodes when RPMI is disabled.
The RPMI-off migration check is a policy smoke test that verifies command acceptance only; it does not restore a destination VM.
Use per-machine queue sizes in the shared protocol harness so the enlarged virt queues and existing server queues both retain correct acknowledgement offsets and ring wraparound.
--- tests/qtest/riscv-rpmi-test.c | 435 ++++++++++++++++++++++++++-------- 1 file changed, 337 insertions(+), 98 deletions(-)
tests/qtest/riscv-rpmi-test.c +337 -98
@@ -16,13 +16,16 @@#define RPMI_SHMEM_BASE 0x10200000ULL#define RPMI_DOORBELL_BASE 0x10230000ULL +#define RVSERVER_RPMI_SHMEM_BASE 0x110000ULL +#define RVSERVER_RPMI_DOORBELL_BASE 0x140000ULL#define RPMI_SLOT_SIZE 64 -#define RPMI_QUEUE_SIZE 0x7800 -#define RPMI_QUEUE_DATA_SLOTS (RPMI_QUEUE_SIZE / RPMI_SLOT_SIZE - 2) +#define RPMI_VIRT_QUEUE_SIZE 0x7800 +#define RPMI_RVSERVER_QUEUE_SIZE 0x400 +#define RPMI_QUEUE_DATA_SLOTS (rpmi_queue_size / RPMI_SLOT_SIZE - 2) -#define RPMI_A2P_HEAD RPMI_SHMEM_BASE -#define RPMI_A2P_TAIL (RPMI_SHMEM_BASE + RPMI_SLOT_SIZE) -#define RPMI_A2P_SLOT0 (RPMI_SHMEM_BASE + 2 * RPMI_SLOT_SIZE) +#define RPMI_A2P_HEAD rpmi_shmem_base +#define RPMI_A2P_TAIL (rpmi_shmem_base + RPMI_SLOT_SIZE) +#define RPMI_A2P_SLOT0 (rpmi_shmem_base + 2 * RPMI_SLOT_SIZE)#define RPMI_SRVGRP_BASE 0x0001#define RPMI_SRVGRP_SYSTEM_RESET 0x0003
@@ -61,53 +64,65 @@#define RPMI_HSM_TEST_START_ADDR 0x80000000ULL#define RPMI_HSM_TEST_RESUME_ADDR 0x80001000ULL -#define RPMI_P2A_ACK_BASE (RPMI_SHMEM_BASE + RPMI_QUEUE_SIZE) +#define RPMI_P2A_ACK_BASE (rpmi_shmem_base + rpmi_queue_size)#define RPMI_P2A_ACK_HEAD RPMI_P2A_ACK_BASE#define RPMI_P2A_ACK_TAIL (RPMI_P2A_ACK_BASE + RPMI_SLOT_SIZE) -static uint64_t rpmi_response_base; - -static uint64_t rpmi_queue_slot (uint64_t queue_base,uint32_t index) -{ -return queue_base + (index +2 ) *RPMI_SLOT_SIZE ; -} - -static void rpmi_send_request (QTestState *qts,uint16_t service_group, -uint8_t service_id,uint8_t request_type, -const uint32_t *data,size_t data_words) -{ -uint32_t tail =qtest_readl (qts,RPMI_A2P_TAIL ); -uint64_t slot =rpmi_queue_slot (RPMI_SHMEM_BASE , tail); -size_t i; - -qtest_writew (qts, slot, service_group); -qtest_writeb (qts, slot +2 , service_id); -qtest_writeb (qts, slot +3 , request_type); -qtest_writew (qts, slot +4 , data_words *sizeof (*data)); -qtest_writew (qts, slot +6 ,RPMI_TOKEN ); - -for (i =0 ; i < data_words; i++) { -qtest_writel (qts, slot +8 + i *sizeof (*data), data[i]); - } - -g_test_message ( -"RPMI_A2P_REQ shmem=0x%016" PRIx64" doorbell=0x%016" PRIx64 -" group=0x%04x service=0x%02x type=0x%02x data_len=%zu" -" token=0x%04x a2p_tail=%u slot=0x%016" PRIx64, - (uint64_t )RPMI_SHMEM_BASE , (uint64_t )RPMI_DOORBELL_BASE , - service_group, service_id, request_type, data_words *sizeof (*data), -RPMI_TOKEN , tail, slot); - -qtest_writel (qts,RPMI_A2P_TAIL , (tail +1 ) %RPMI_QUEUE_DATA_SLOTS ); -qtest_writel (qts,RPMI_DOORBELL_BASE ,1 ); -} - -static uint32_t rpmi_response_word (QTestState *qts,unsigned int word) -{ -return qtest_readl (qts, rpmi_response_base +8 + word *sizeof (uint32_t )); -} - -static void test_rpmi_virt_fdt_service_nodes (void ) +typedef struct RiscvRpmiQTestMachine { +const char *machine_opts; +uint64_t shmem_base; +uint64_t doorbell_base; +uint32_t queue_size; +const char *platform_info; +const char *reset_node; +const char *poweroff_node; +}RiscvRpmiQTestMachine ; + +static const RiscvRpmiQTestMachine virt_rpmi_machine = { + .machine_opts ="virt,rpmi=on" , + .shmem_base =RPMI_SHMEM_BASE , + .doorbell_base =RPMI_DOORBELL_BASE , + .queue_size =RPMI_VIRT_QUEUE_SIZE , + .platform_info ="QEMU RISC-V virt RPMI" , + .reset_node ="/reboot" , + .poweroff_node ="/poweroff" , +}; + +static const RiscvRpmiQTestMachine rvserver_ref_rpmi_machine = { + .machine_opts ="riscv-server-ref,rpmi=on" , + .shmem_base =RVSERVER_RPMI_SHMEM_BASE , + .doorbell_base =RVSERVER_RPMI_DOORBELL_BASE , + .queue_size =RPMI_RVSERVER_QUEUE_SIZE , + .platform_info ="QEMU RISC-V server-ref RPMI" , + .reset_node ="/reboot" , + .poweroff_node ="/poweroff" , +}; + +static const RiscvRpmiQTestMachine rvserver_ref_legacy_machine = { + .machine_opts ="riscv-server-ref,rpmi=off" , + .shmem_base =RVSERVER_RPMI_SHMEM_BASE , + .doorbell_base =RVSERVER_RPMI_DOORBELL_BASE , + .queue_size =RPMI_RVSERVER_QUEUE_SIZE , + .platform_info ="QEMU RISC-V server-ref RPMI" , + .reset_node ="/reboot" , + .poweroff_node ="/poweroff" , +}; + +static const RiscvRpmiQTestMachine rvserver_ref_default_machine = { + .machine_opts ="riscv-server-ref" , + .shmem_base =RVSERVER_RPMI_SHMEM_BASE , + .doorbell_base =RVSERVER_RPMI_DOORBELL_BASE , + .queue_size =RPMI_RVSERVER_QUEUE_SIZE , + .platform_info ="QEMU RISC-V server-ref RPMI" , + .reset_node ="/reboot" , + .poweroff_node ="/poweroff" , +}; + +static QTestState *rpmi_qtest_init (const RiscvRpmiQTestMachine *machine, +const char *extra_args); + +static void rpmi_test_fdt_service_nodes ( +const RiscvRpmiQTestMachine *machine) { static const struct { const char *name;
@@ -118,6 +133,7 @@ static void test_rpmi_virt_fdt_service_nodes(void) { "suspend", RPMI_SRVGRP_SYSTEM_SUSPEND }, }; g_autofree char *dtb_path = NULL; + g_autofree char *mailbox_path = NULL; g_autofree char *dtb = NULL;gsize dtb_size;const fdt32_t *prop;
@@ -128,7 +144,7 @@ static void test_rpmi_virt_fdt_service_nodes(void) dtb_path =g_strdup_printf ("%s/riscv-rpmi-fdt-%u.dtb" ,g_get_tmp_dir (), (unsigned )getpid ()); - qts =qtest_init ("-machine virt,rpmi=on -display none -S" ); + qts =rpmi_qtest_init (machine," -display none -S" );qtest_qmp_assert_success (qts,"{ 'execute': 'dumpdtb', 'arguments': " "{ 'filename': %s } }" , dtb_path);
@@ -137,15 +153,18 @@ static void test_rpmi_virt_fdt_service_nodes(void)g_assert_true (g_file_get_contents (dtb_path, &dtb, &dtb_size,NULL )); g_assert_cmpint(fdt_check_header(dtb), ==, 0); - mailbox_offset =fdt_path_offset (dtb,"/soc/mailbox@10200000" ); + mailbox_path =g_strdup_printf ("/soc/mailbox@%" PRIx64, + machine->shmem_base); + mailbox_offset =fdt_path_offset (dtb, mailbox_path); g_assert_cmpint(mailbox_offset, >=, 0); prop =fdt_getprop (dtb, mailbox_offset,"reg" , &phandle_len);g_assert_nonnull (prop); g_assert_cmpint(phandle_len, >=, 8 * sizeof(*prop));for (unsigned int queue =0 ; queue <2 ; queue++) { g_assert_cmphex(fdt32_to_cpu(prop[4 * queue + 1]), ==, -RPMI_SHMEM_BASE + queue *RPMI_QUEUE_SIZE ); - g_assert_cmphex(fdt32_to_cpu(prop[4 * queue + 3]), ==, RPMI_QUEUE_SIZE); + machine->shmem_base + queue * machine->queue_size); + g_assert_cmphex(fdt32_to_cpu(prop[4 * queue + 3]), ==, + machine->queue_size); } prop =fdt_getprop (dtb, mailbox_offset,"phandle" , &phandle_len);g_assert_nonnull (prop);
@@ -170,9 +189,111 @@ static void test_rpmi_virt_fdt_service_nodes(void) services[i].service_group); } + g_assert_cmpint(fdt_path_offset(dtb, machine->reset_node), ==, + -FDT_ERR_NOTFOUND ); + g_assert_cmpint(fdt_path_offset(dtb, machine->poweroff_node), ==, + -FDT_ERR_NOTFOUND ); + g_assert_cmpint(g_remove(dtb_path), ==, 0); } +static void test_rpmi_virt_fdt_service_nodes (void ) +{ +rpmi_test_fdt_service_nodes (&virt_rpmi_machine); +} + +static void test_rpmi_rvserver_ref_fdt_service_nodes (void ) +{ +rpmi_test_fdt_service_nodes (&rvserver_ref_rpmi_machine); +} + +static void rpmi_test_fdt_legacy_nodes ( +const RiscvRpmiQTestMachine *machine) +{ + g_autofree char *dtb_path = NULL; + g_autofree char *dtb = NULL; +gsize dtb_size; +QTestState *qts; + + dtb_path =g_strdup_printf ("%s/riscv-rpmi-fdt-legacy-%u.dtb" , +g_get_tmp_dir (), (unsigned )getpid ()); + qts =rpmi_qtest_init (machine," -display none -S" ); +qtest_qmp_assert_success (qts, +"{ 'execute': 'dumpdtb', 'arguments': " +"{ 'filename': %s } }" , dtb_path); +qtest_quit (qts); + +g_assert_true (g_file_get_contents (dtb_path, &dtb, &dtb_size,NULL )); + g_assert_cmpint(fdt_check_header(dtb), ==, 0); + g_assert_cmpint(fdt_path_offset(dtb, machine->reset_node), >=, 0); + g_assert_cmpint(fdt_path_offset(dtb, machine->poweroff_node), >=, 0); + g_assert_cmpint(fdt_path_offset(dtb, "/soc/mailbox@110000"), ==, + -FDT_ERR_NOTFOUND ); + g_assert_cmpint(fdt_path_offset(dtb, "/soc/sysreset"), ==, + -FDT_ERR_NOTFOUND ); + g_assert_cmpint(g_remove(dtb_path), ==, 0); +} + +static void test_rpmi_rvserver_ref_fdt_legacy_nodes (void ) +{ +rpmi_test_fdt_legacy_nodes (&rvserver_ref_legacy_machine); +} + +static uint64_t rpmi_shmem_base =RPMI_SHMEM_BASE ; +static uint64_t rpmi_doorbell_base =RPMI_DOORBELL_BASE ; +static uint32_t rpmi_queue_size =RPMI_VIRT_QUEUE_SIZE ; +static uint64_t rpmi_response_base; + +static QTestState *rpmi_qtest_init (const RiscvRpmiQTestMachine *machine, +const char *extra_args) +{ + rpmi_shmem_base = machine->shmem_base; + rpmi_doorbell_base = machine->doorbell_base; + rpmi_queue_size = machine->queue_size; + +return qtest_initf ("-machine %s%s" , machine->machine_opts, extra_args); +} + +static uint64_t rpmi_queue_slot (uint64_t queue_base,uint32_t index) +{ +return queue_base + (index +2 ) *RPMI_SLOT_SIZE ; +} + +static void rpmi_send_request (QTestState *qts,uint16_t service_group, +uint8_t service_id,uint8_t request_type, +const uint32_t *data,size_t data_words) +{ +uint32_t tail =qtest_readl (qts,RPMI_A2P_TAIL ); +uint64_t slot =rpmi_queue_slot (rpmi_shmem_base, tail); +size_t i; + +qtest_writew (qts, slot, service_group); +qtest_writeb (qts, slot +2 , service_id); +qtest_writeb (qts, slot +3 , request_type); +qtest_writew (qts, slot +4 , data_words *sizeof (*data)); +qtest_writew (qts, slot +6 ,RPMI_TOKEN ); + +for (i =0 ; i < data_words; i++) { +qtest_writel (qts, slot +8 + i *sizeof (*data), data[i]); + } + +g_test_message ( +"RPMI_A2P_REQ shmem=0x%016" PRIx64" doorbell=0x%016" PRIx64 +" group=0x%04x service=0x%02x type=0x%02x data_len=%zu" +" token=0x%04x a2p_tail=%u slot=0x%016" PRIx64, + (uint64_t )rpmi_shmem_base, (uint64_t )rpmi_doorbell_base, + service_group, service_id, request_type, data_words *sizeof (*data), +RPMI_TOKEN , tail, slot); + +qtest_writel (qts,RPMI_A2P_TAIL , (tail +1 ) %RPMI_QUEUE_DATA_SLOTS ); +qtest_writel (qts, rpmi_doorbell_base,1 ); +} + +static uint32_t rpmi_response_word (QTestState *qts,unsigned int word) +{ +return qtest_readl (qts, rpmi_response_base +8 + word *sizeof (uint32_t )); +} +static void rpmi_expect_ack (QTestState *qts,uint16_t service_group,uint8_t service_id,uint16_t data_len) {
@@ -194,7 +315,7 @@ static void rpmi_expect_ack(QTestState *qts, uint16_t service_group," group=0x%04x service=0x%02x type=0x%02x data_len=%u" " token=0x%04x p2a_head=%u slot=0x%016" PRIx64" status=0x%08x" , - (uint64_t )RPMI_SHMEM_BASE , service_group, service_id, + (uint64_t )rpmi_shmem_base, service_group, service_id,RPMI_MSG_ACKNOWLEDGEMENT , data_len,RPMI_TOKEN , head, rpmi_response_base, data_len >= sizeof(uint32_t) ? rpmi_response_word(qts, 0) : 0);
@@ -255,30 +376,41 @@ static void test_rpmi_machine_rejects_too_many_harts(void) "max CPUs supported by machine 'virt' is 512"); } -static void test_rpmi_base_platform_info (void ) +static void rpmi_check_platform_info (QTestState *qts,const char *expected) { -static const char expected[] ="QEMU RISC-V virt RPMI" ; -QTestState *qts; +size_t expected_len =strlen (expected) +1 ;size_t i; - qts =qtest_init ("-machine virt,rpmi=on" );rpmi_send_request (qts,RPMI_SRVGRP_BASE ,RPMI_BASE_SRV_GET_PLATFORM_INFO ,RPMI_MSG_NORMAL_REQUEST ,NULL ,0 );rpmi_expect_ack (qts,RPMI_SRVGRP_BASE ,RPMI_BASE_SRV_GET_PLATFORM_INFO , -2 *sizeof (uint32_t ) +sizeof (expected)); +2 *sizeof (uint32_t ) + expected_len); g_assert_cmphex(rpmi_response_word(qts, 0), ==, 0); - g_assert_cmphex(rpmi_response_word(qts, 1), ==, sizeof(expected)); -for (i =0 ; i <sizeof (expected); i++) { + g_assert_cmphex(rpmi_response_word(qts, 1), ==, expected_len); +for (i =0 ; i < expected_len; i++) { g_assert_cmphex(qtest_readb(qts, rpmi_response_base + 16 + i), ==, expected[i]); } +} + +static void rpmi_test_platform_info (const RiscvRpmiQTestMachine *machine) +{ +QTestState *qts; + + qts =rpmi_qtest_init (machine,"" ); +rpmi_check_platform_info (qts, machine->platform_info);qtest_quit (qts); } +static void test_rpmi_base_platform_info (void ) +{ +rpmi_test_platform_info (&virt_rpmi_machine); +} +static void rpmi_probe_group (QTestState *qts,uint32_t service_group,bool present) {
@@ -297,11 +429,8 @@ static void rpmi_probe_group(QTestState *qts, uint32_t service_group, } } -static void test_rpmi_base_probe_service_groups (void ) +static void rpmi_check_service_groups (QTestState *qts) { -QTestState *qts; - - qts =qtest_init ("-machine virt,rpmi=on,aia=aplic-imsic" );rpmi_probe_group (qts,RPMI_SRVGRP_BASE , true);qtest_system_reset (qts);rpmi_probe_group (qts,RPMI_SRVGRP_SYSTEM_RESET , true);
@@ -309,10 +438,88 @@ static void test_rpmi_base_probe_service_groups(void)rpmi_probe_group (qts,RPMI_SRVGRP_HSM , true);qtest_system_reset (qts);rpmi_probe_group (qts,RPMI_SRVGRP_SYSTEM_SUSPEND , true); +} + +static void rpmi_test_service_groups (const RiscvRpmiQTestMachine *machine, +const char *extra_args) +{ +QTestState *qts; + + qts =rpmi_qtest_init (machine, extra_args); +rpmi_check_service_groups (qts); + +qtest_quit (qts); +} + +static void test_rpmi_base_probe_service_groups (void ) +{ +rpmi_test_service_groups (&virt_rpmi_machine,",aia=aplic-imsic" ); +} + +static void test_rpmi_rvserver_ref_machine_realize_off (void ) +{ +QTestState *qts; + + qts =rpmi_qtest_init (&rvserver_ref_legacy_machine,"" ); +qtest_quit (qts); +} + +static void test_rpmi_rvserver_ref_machine_realize_default (void ) +{ +QTestState *qts; + + qts =rpmi_qtest_init (&rvserver_ref_default_machine,"" ); +qtest_quit (qts); +} + +static void test_rpmi_rvserver_ref_fdt_default_nodes (void ) +{ +rpmi_test_fdt_legacy_nodes (&rvserver_ref_default_machine); +} + +static void test_rpmi_rvserver_ref_platform_info (void ) +{ +rpmi_test_platform_info (&rvserver_ref_rpmi_machine); +} + +static void test_rpmi_rvserver_ref_probe_service_groups (void ) +{ +rpmi_test_service_groups (&rvserver_ref_rpmi_machine,"" ); +} + +static void rpmi_check_hsm_hart_list (QTestState *qts,uint32_t hart_count) +{ +uint32_t start_index =0 ; + +rpmi_send_request (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_HART_LIST , +RPMI_MSG_NORMAL_REQUEST , &start_index,1 ); + +rpmi_expect_ack (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_HART_LIST , + (3 + hart_count) *sizeof (uint32_t )); + g_assert_cmphex(rpmi_response_word(qts, 0), ==, 0); + g_assert_cmphex(rpmi_response_word(qts, 1), ==, 0); + g_assert_cmphex(rpmi_response_word(qts, 2), ==, hart_count); +for (uint32_t i =0 ; i < hart_count; i++) { + g_assert_cmphex(rpmi_response_word(qts, i + 3), ==, i); + } +} + +static void rpmi_test_hsm_hart_list (const RiscvRpmiQTestMachine *machine, +const char *extra_args) +{ +QTestState *qts; + + qts =rpmi_qtest_init (machine, extra_args); +rpmi_check_hsm_hart_list (qts,4 );qtest_quit (qts); } +static void test_rpmi_rvserver_ref_hsm_hart_list (void ) +{ +rpmi_test_hsm_hart_list (&rvserver_ref_rpmi_machine," -smp 4" ); +} +static void test_rpmi_sysreset_attrs (void ) { static const struct {
@@ -325,7 +532,7 @@ static void test_rpmi_sysreset_attrs(void) };QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );for (size_t i =0 ; i <ARRAY_SIZE (cases); i++) {if (i) {qtest_system_reset (qts);
@@ -348,7 +555,7 @@ static void test_rpmi_sysreset_shutdown(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );rpmi_send_sysreset (qts,RPMI_SYSRST_TYPE_SHUTDOWN ,RPMI_MSG_POSTED_REQUEST );qtest_qmp_eventwait (qts,"SHUTDOWN" );
@@ -359,7 +566,7 @@ static void test_rpmi_sysreset_cold_reboot(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on -no-reboot" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -no-reboot" );rpmi_send_sysreset (qts,RPMI_SYSRST_TYPE_COLD_REBOOT ,RPMI_MSG_POSTED_REQUEST );qtest_qmp_eventwait (qts,"SHUTDOWN" );
@@ -370,7 +577,7 @@ static void test_rpmi_sysreset_invalid_type(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );rpmi_send_sysreset (qts,RPMI_SYSRST_TYPE_INVALID ,RPMI_MSG_NORMAL_REQUEST );
@@ -387,7 +594,7 @@ static void test_rpmi_repeated_reset_after_traffic(void)QTestState *qts;uint32_t reset_type =RPMI_SYSRST_TYPE_SHUTDOWN ; - qts =qtest_init ("-machine virt,rpmi=on,aia=aplic-imsic" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,",aia=aplic-imsic" );for (uint32_t i =0 ; i <5 ; i++) { rpmi_send_request(qts, RPMI_SRVGRP_SYSTEM_RESET, RPMI_SYSRST_SRV_GET_ATTRIBUTES,
@@ -406,7 +613,7 @@ static void test_rpmi_reset_clears_transport(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );rpmi_send_sysreset (qts,RPMI_SYSRST_TYPE_INVALID ,RPMI_MSG_NORMAL_REQUEST ); rpmi_expect_ack(qts, RPMI_SRVGRP_SYSTEM_RESET,
@@ -425,7 +632,7 @@ static void test_rpmi_doorbell_invalid_access(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );qtest_writeb (qts,RPMI_DOORBELL_BASE ,1 );qtest_writel (qts,RPMI_DOORBELL_BASE +4 ,1 ); g_assert_cmphex(qtest_readl(qts, RPMI_DOORBELL_BASE), ==, 0);
@@ -437,7 +644,7 @@ static void test_rpmi_queue_bounds(void) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on" ); + qts =rpmi_qtest_init (&virt_rpmi_machine,"" );qtest_writel (qts,RPMI_A2P_TAIL ,RPMI_QUEUE_DATA_SLOTS );qtest_writel (qts,RPMI_DOORBELL_BASE ,1 ); g_assert_cmphex(qtest_readl(qts, RPMI_A2P_HEAD), ==, 0);
@@ -463,7 +670,7 @@ static void test_rpmi_migration_blocked(void)QDict *error;const char *desc; - qts =qtest_init ("-machine virt,rpmi=on -S" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -S" ); error =qtest_qmp_assert_failure_ref (qts,"{ 'execute': 'migrate'," " 'arguments': { 'uri': 'exec:cat > /dev/null' } }" );
@@ -477,41 +684,50 @@ static void test_rpmi_migration_blocked(void)qtest_quit (qts); } -static void rpmi_expect_hsm_hart_list (QTestState *qts) +static void test_rpmi_rvserver_ref_migration_blocked (void ) { -uint32_t start_index =0 ; +QTestState *qts; +QDict *error; +const char *desc; -rpmi_send_request (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_HART_LIST , -RPMI_MSG_NORMAL_REQUEST , &start_index,1 ); + qts =rpmi_qtest_init (&rvserver_ref_rpmi_machine," -S" ); + error =qtest_qmp_assert_failure_ref (qts, +"{ 'execute': 'migrate'," +" 'arguments': { 'uri': 'exec:cat > /dev/null' } }" ); + desc =qdict_get_try_str (error,"desc" ); -rpmi_expect_ack (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_HART_LIST , -7 *sizeof (uint32_t )); - g_assert_cmphex(rpmi_response_word(qts, 0), ==, 0); - g_assert_cmphex(rpmi_response_word(qts, 1), ==, 0); - g_assert_cmphex(rpmi_response_word(qts, 2), ==, 4); - g_assert_cmphex(rpmi_response_word(qts, 3), ==, 0); - g_assert_cmphex(rpmi_response_word(qts, 4), ==, 1); - g_assert_cmphex(rpmi_response_word(qts, 5), ==, 2); - g_assert_cmphex(rpmi_response_word(qts, 6), ==, 3); +g_assert_nonnull (desc); +g_assert_nonnull (strstr (desc,"non-migratable device" )); +g_assert_nonnull (strstr (desc,"riscv-rpmi" )); + +qobject_unref (error); +qtest_quit (qts); } -static void test_rpmi_hsm_hart_list (void ) +static void test_rpmi_rvserver_ref_migration_command_accepted (void ) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on -smp 4" ); -rpmi_expect_hsm_hart_list (qts); - + qts =rpmi_qtest_init (&rvserver_ref_legacy_machine," -S" ); +/* This is a policy smoke test; no migration destination is restored. */ +qtest_qmp_assert_success (qts, +"{ 'execute': 'migrate'," +" 'arguments': { 'uri': 'exec:cat > /dev/null' } }" );qtest_quit (qts); } +static void test_rpmi_hsm_hart_list (void ) +{ +rpmi_test_hsm_hart_list (&virt_rpmi_machine," -smp 4" ); +} +static void test_rpmi_hsm_multi_socket_hart_list (void ) {QTestState *qts; - qts =qtest_init ("-machine virt,rpmi=on " -"-smp 4,sockets=2,cores=2,threads=1" ); -rpmi_expect_hsm_hart_list (qts); + qts =rpmi_qtest_init (&virt_rpmi_machine, +" -smp 4,sockets=2,cores=2,threads=1" ); +rpmi_check_hsm_hart_list (qts,4 );qtest_quit (qts); }
@@ -521,7 +737,7 @@ static void test_rpmi_hsm_hart_status(void)QTestState *qts;uint32_t hart_id =3 ; - qts =qtest_init ("-machine virt,rpmi=on -smp 4" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -smp 4" );rpmi_send_request (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_HART_STATUS ,RPMI_MSG_NORMAL_REQUEST , &hart_id,1 );
@@ -555,7 +771,7 @@ static void test_rpmi_hsm_hart_control(void)uint32_t start_index =0 ;uint32_t suspend_type =0 ; - qts =qtest_init ("-machine virt,rpmi=on -smp 2" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -smp 2" );rpmi_send_request (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_GET_SUSPEND_TYPES ,RPMI_MSG_NORMAL_REQUEST , &start_index,1 ); rpmi_expect_ack(qts, RPMI_SRVGRP_HSM, RPMI_HSM_SRV_GET_SUSPEND_TYPES,
@@ -601,7 +817,7 @@ static void test_rpmi_hsm_hart_control(void)qtest_quit (qts); - qts =qtest_init ("-machine virt,rpmi=on -smp 2" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -smp 2" );rpmi_send_request (qts,RPMI_SRVGRP_HSM ,RPMI_HSM_SRV_HART_SUSPEND ,RPMI_MSG_NORMAL_REQUEST , suspend_request,ARRAY_SIZE (suspend_request));
@@ -632,7 +848,7 @@ static void test_rpmi_syssusp_attrs_and_suspend(void)uint32_t suspend_type =0 ;uint32_t suspend_request[] = {0 ,0 ,0x80000000 ,0 }; - qts =qtest_init ("-machine virt,rpmi=on -smp 1" ); + qts =rpmi_qtest_init (&virt_rpmi_machine," -smp 1" );rpmi_send_request (qts,RPMI_SRVGRP_SYSTEM_SUSPEND ,RPMI_SYSSUSP_SRV_GET_ATTRIBUTES ,RPMI_MSG_NORMAL_REQUEST , &suspend_type,1 );
@@ -758,5 +974,28 @@ int main(int argc, char **argv) test_rpmi_syssusp_attrs_and_suspend); } +if (qtest_has_machine ("riscv-server-ref" )) { +qtest_add_func ("/riscv/rpmi/rvserver-ref/machine/realize-off" , + test_rpmi_rvserver_ref_machine_realize_off); +qtest_add_func ("/riscv/rpmi/rvserver-ref/machine/realize-default" , + test_rpmi_rvserver_ref_machine_realize_default); +qtest_add_func ("/riscv/rpmi/rvserver-ref/fdt/service-nodes" , + test_rpmi_rvserver_ref_fdt_service_nodes); +qtest_add_func ("/riscv/rpmi/rvserver-ref/fdt/legacy-nodes" , + test_rpmi_rvserver_ref_fdt_legacy_nodes); +qtest_add_func ("/riscv/rpmi/rvserver-ref/fdt/default-nodes" , + test_rpmi_rvserver_ref_fdt_default_nodes); +qtest_add_func ("/riscv/rpmi/rvserver-ref/rpmi/platform-info" , + test_rpmi_rvserver_ref_platform_info); +qtest_add_func ("/riscv/rpmi/rvserver-ref/base/probe-service-groups" , + test_rpmi_rvserver_ref_probe_service_groups); +qtest_add_func ("/riscv/rpmi/rvserver-ref/hsm/hart-list" , + test_rpmi_rvserver_ref_hsm_hart_list); +qtest_add_func ("/riscv/rpmi/rvserver-ref/migration/blocked" , + test_rpmi_rvserver_ref_migration_blocked); +qtest_add_func ("/riscv/rpmi/rvserver-ref/migration/command-accepted" , + test_rpmi_rvserver_ref_migration_command_accepted); + } +return g_test_run (); }