[PATCH 6/7] platform: virt: add QEMU virt WorldGuard hwiso tests
Raymond Mao <[email protected]>
| Newsgroups | org.infradead.lists.opensbi |
|---|---|
| Message-ID | <[email protected]> |
From: Raymond Mao <[email protected]> Add QEMU virt WorldGuard mechanism-specific tests for boot-time checker programming and runtime CSR state, and verify the expected root / domain@0 / domain@1 behavior through the HWISO test callback API. Signed-off-by: Raymond Mao <[email protected]> --- platform/generic/objects.mk | 1 + .../generic/virt/qemu_virt_wgchecker_test.c | 321 ++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 platform/generic/virt/qemu_virt_wgchecker_test.c diff --git a/platform/generic/objects.mk b/platform/generic/objects.mk index 80bd65ea..be58873a 100644 --- a/platform/generic/objects.mk +++ b/platform/generic/objects.mk @@ -23,6 +23,7 @@ platform-objs-y += platform_override_modules.o platform-objs-y += worldguard.o platform-objs-y += wgchecker2.o platform-objs-y += virt/qemu_virt_worldguard.o +platform-objs-$(CONFIG_SBIUNIT) += virt/qemu_virt_wgchecker_test.o # Blobs to build FW_TEXT_START=0x80000000 diff --git a/platform/generic/virt/qemu_virt_wgchecker_test.c b/platform/generic/virt/qemu_virt_wgchecker_test.c new file mode 100644 index 00000000..0eeaa3a0 --- /dev/null +++ b/platform/generic/virt/qemu_virt_wgchecker_test.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026 RISCstar Solutions Corporation. + * + * Author: Raymond Mao <[email protected]> + */ +#include <libfdt.h> +#include <sbi/riscv_encoding.h> +#include <sbi/riscv_io.h> +#include <sbi/sbi_domain.h> +#include <sbi/sbi_error.h> +#include <sbi/sbi_hart.h> +#include <sbi/sbi_hwiso.h> +#include <sbi/sbi_hwiso_test.h> +#include <sbi/sbi_scratch.h> +#include <sbi/sbi_string.h> +#include <sbi/sbi_unit_test.h> +#include <sbi_utils/fdt/fdt_helper.h> +#include <wgchecker2.h> +#include <worldguard.h> + +struct qemu_virt_wg_slot_expect { + bool check_addr; + u64 addr; + u64 perm; + u32 cfg; +}; + +struct qemu_virt_wg_checker_expect { + const char *path; + u32 slot_count; + struct qemu_virt_wg_slot_expect *slots; + struct qemu_virt_wg_slot_expect last_slot; +}; + +struct qemu_virt_wg_expect { + u32 wid; + u32 widlist_mask; + bool check_slwid; + u32 slwid; +}; + +static u64 qemu_virt_wg_mmio_read64(unsigned long addr) +{ +#if __riscv_xlen != 32 + return readq((void *)addr); +#else + return readl((void *)addr) | ((u64)readl((void *)(addr + 4)) << 32); +#endif +} + +static struct qemu_virt_wg_slot_expect qemu_virt_wg_dram_slots[] = { + { + .check_addr = true, + .addr = 0x20000000ULL, + .perm = 0, + .cfg = WGCHECKER2_SLOT_CFG_A_OFF, + }, + { + .check_addr = true, + .addr = 0x30000000ULL, + .perm = 0xcf, + .cfg = WGCHECKER2_SLOT_CFG_A_TOR, + }, + { + .check_addr = true, + .addr = 0x30400000ULL, + .perm = 0xcc, + .cfg = WGCHECKER2_SLOT_CFG_A_TOR, + }, + { + .check_addr = true, + .addr = 0x40000000ULL, + .perm = 0xcf, + .cfg = WGCHECKER2_SLOT_CFG_A_TOR, + }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, +}; + +static struct qemu_virt_wg_slot_expect qemu_virt_wg_zero_slots[] = { + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, + { .check_addr = true, .addr = 0, .perm = 0, .cfg = 0 }, +}; + +static const struct qemu_virt_wg_checker_expect qemu_virt_wg_checker_expects[] = { + { + .path = "/soc/wgchecker@6000000", + .slot_count = 16, + .slots = qemu_virt_wg_dram_slots, + .last_slot = { .perm = 0, .cfg = 0 }, + }, + { + .path = "/soc/wgchecker@6001000", + .slot_count = 16, + .slots = qemu_virt_wg_zero_slots, + .last_slot = { .perm = 0xc3, .cfg = WGCHECKER2_SLOT_CFG_A_TOR }, + }, + { + .path = "/soc/wgchecker@6002000", + .slot_count = 1, + .slots = NULL, + .last_slot = { .perm = 0xc0, .cfg = WGCHECKER2_SLOT_CFG_A_TOR }, + }, +}; + +static const struct qemu_virt_wg_expect qemu_virt_wg_root_expect = { + .wid = 3, + .widlist_mask = 0, + .check_slwid = false, +}; + +static const struct qemu_virt_wg_expect qemu_virt_wg_domain0_expect = { + .wid = 0, + .widlist_mask = 0xb, + .check_slwid = true, + .slwid = 0, +}; + +static const struct qemu_virt_wg_expect qemu_virt_wg_domain1_expect = { + .wid = 1, + .widlist_mask = 0xa, + .check_slwid = true, + .slwid = 1, +}; + +static struct sbi_domain *qemu_virt_wg_find_domain(const char *name) +{ + u32 i; + struct sbi_domain *dom; + + sbi_domain_for_each(i, dom) { + if (!sbi_strcmp(dom->name, name)) + return dom; + } + + return NULL; +} + +static const struct qemu_virt_wg_expect * +qemu_virt_wg_domain_expect(const struct sbi_domain *dom) +{ + if (dom == &root) + return &qemu_virt_wg_root_expect; + if (dom && !sbi_strcmp(dom->name, "root")) + return &qemu_virt_wg_root_expect; + if (!dom) + return NULL; + if (!sbi_strcmp(dom->name, "domain@0")) + return &qemu_virt_wg_domain0_expect; + if (!sbi_strcmp(dom->name, "domain@1")) + return &qemu_virt_wg_domain1_expect; + + return NULL; +} + +static void qemu_virt_wg_assert_checker(struct sbiunit_test_case *test, + const struct qemu_virt_wg_checker_expect *expect) +{ + void *fdt = fdt_get_address(); + u64 base, size, addr, perm; + u32 cfg, slot; + int node, rc; + + node = fdt_path_offset(fdt, expect->path); + SBIUNIT_ASSERT(test, node >= 0); + + rc = fdt_get_node_addr_size(fdt, node, 0, &base, &size); + SBIUNIT_ASSERT_EQ(test, rc, 0); + (void)size; + + SBIUNIT_ASSERT_EQ(test, + readl((void *)(unsigned long) + (base + WGCHECKER2_MMIO_NSLOTS)), + expect->slot_count); + SBIUNIT_ASSERT_EQ(test, + qemu_virt_wg_mmio_read64(base + WGCHECKER2_MMIO_ERRCAUSE), + 0UL); + SBIUNIT_ASSERT_EQ(test, + qemu_virt_wg_mmio_read64(base + WGCHECKER2_MMIO_ERRADDR), + 0UL); + + for (slot = 1; slot < expect->slot_count; slot++) { + addr = qemu_virt_wg_mmio_read64( + base + WGCHECKER2_MMIO_SLOT_BASE + + slot * WGCHECKER2_MMIO_SLOT_STRIDE + + WGCHECKER2_MMIO_SLOT_ADDR); + perm = qemu_virt_wg_mmio_read64( + base + WGCHECKER2_MMIO_SLOT_BASE + + slot * WGCHECKER2_MMIO_SLOT_STRIDE + + WGCHECKER2_MMIO_SLOT_PERM); + cfg = readl((void *)(unsigned long) + (base + WGCHECKER2_MMIO_SLOT_BASE + + slot * WGCHECKER2_MMIO_SLOT_STRIDE + + WGCHECKER2_MMIO_SLOT_CFG)) & + WGCHECKER2_SLOT_CFG_A_MASK; + + if (expect->slots[slot - 1].check_addr) + SBIUNIT_ASSERT_EQ(test, addr, expect->slots[slot - 1].addr); + SBIUNIT_ASSERT_EQ(test, perm, expect->slots[slot - 1].perm); + SBIUNIT_ASSERT_EQ(test, cfg, expect->slots[slot - 1].cfg); + } + + perm = qemu_virt_wg_mmio_read64( + base + WGCHECKER2_MMIO_SLOT_BASE + + expect->slot_count * WGCHECKER2_MMIO_SLOT_STRIDE + + WGCHECKER2_MMIO_SLOT_PERM); + cfg = readl((void *)(unsigned long) + (base + WGCHECKER2_MMIO_SLOT_BASE + + expect->slot_count * WGCHECKER2_MMIO_SLOT_STRIDE + + WGCHECKER2_MMIO_SLOT_CFG)) & + WGCHECKER2_SLOT_CFG_A_MASK; + SBIUNIT_ASSERT_EQ(test, perm, expect->last_slot.perm); + SBIUNIT_ASSERT_EQ(test, cfg, expect->last_slot.cfg); +} + +static void qemu_virt_wg_assert_state(struct sbiunit_test_case *test, + const struct sbi_domain *dom, void *ctx) +{ + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + const struct qemu_virt_wg_expect *expect; + + (void)ctx; + + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMWG)) + return; + expect = qemu_virt_wg_domain_expect(dom); + if (!expect) + return; + + SBIUNIT_ASSERT_EQ(test, csr_read(CSR_MLWID), expect->wid); + + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSWG)) + return; + + SBIUNIT_ASSERT_EQ(test, csr_read(CSR_MWIDDELEG), expect->widlist_mask); + if (!expect->check_slwid) + return; + + SBIUNIT_ASSERT_EQ(test, csr_read(CSR_SLWID), expect->slwid); +} + +static void qemu_virt_wg_assert_quiesced(struct sbiunit_test_case *test, + const struct sbi_domain *dom, void *ctx) +{ + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + + (void)dom; + (void)ctx; + + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMWG)) + return; + + SBIUNIT_ASSERT_EQ(test, csr_read(CSR_MLWID), qemu_virt_wg_root_expect.wid); + + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSWG)) + return; + + SBIUNIT_ASSERT_EQ(test, csr_read(CSR_MWIDDELEG), 0UL); +} + +static void qemu_virt_wg_boot_test(struct sbiunit_test_case *test) +{ + struct sbi_domain *dom0, *dom1; + u32 i; + + for (i = 0; + i < (sizeof(qemu_virt_wg_checker_expects) / + sizeof(qemu_virt_wg_checker_expects[0])); + i++) + qemu_virt_wg_assert_checker(test, &qemu_virt_wg_checker_expects[i]); + + SBIUNIT_ASSERT_EQ(test, worldguard_test_check_runtime_state(true), 0); + SBIUNIT_ASSERT_EQ(test, wgchecker2_checker_count(), 3); + + dom0 = qemu_virt_wg_find_domain("domain@0"); + dom1 = qemu_virt_wg_find_domain("domain@1"); + SBIUNIT_ASSERT_NE(test, dom0, NULL); + SBIUNIT_ASSERT_NE(test, dom1, NULL); + SBIUNIT_ASSERT_EQ(test, + worldguard_test_check_domain_state( + dom0, true, qemu_virt_wg_domain0_expect.wid, + qemu_virt_wg_domain0_expect.widlist_mask), + 0); + SBIUNIT_ASSERT_EQ(test, + worldguard_test_check_domain_state( + dom1, true, qemu_virt_wg_domain1_expect.wid, + qemu_virt_wg_domain1_expect.widlist_mask), + 0); + SBIUNIT_ASSERT_EQ(test, + worldguard_test_check_domain_state(&root, false, 0, 0), + 0); +} + +const struct sbi_hwiso_test_ops qemu_virt_worldguard_test_ops = { + .boot_test = qemu_virt_wg_boot_test, + .domain_state_test = qemu_virt_wg_assert_state, + .domain_quiesce_test = qemu_virt_wg_assert_quiesced, +}; -- 2.25.1 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi