OpenSBI Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Raymond Mao <raymondmaoca@gmail.com>
To: opensbi@lists.infradead.org
Cc: scott@riscstar.com, dave.patel@riscstar.com,
	raymond.mao@riscstar.com, robin.randhawa@sifive.com,
	samuel.holland@sifive.com, anup.patel@qti.qualcomm.com,
	anuppate@qti.qualcomm.com, anup@brainfault.org,
	dhaval@rivosinc.com, peter.lin@sifive.com
Subject: [PATCH 6/7] platform: virt: add QEMU virt WorldGuard hwiso tests
Date: Tue, 19 May 2026 16:33:30 -0400	[thread overview]
Message-ID: <20260519203331.2773185-7-raymondmaoca@gmail.com> (raw)
In-Reply-To: <20260519203331.2773185-1-raymondmaoca@gmail.com>

From: Raymond Mao <raymond.mao@riscstar.com>

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 <raymond.mao@riscstar.com>
---
 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 <raymond.mao@riscstar.com>
+ */
+#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
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

  parent reply	other threads:[~2026-05-19 20:34 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-19 20:33 [PATCH 0/7] Add WorldGuard hwiso support Raymond Mao
2026-05-19 20:33 ` [PATCH 1/7] hart: add WorldGuard CSR IDs and hart extension flags Raymond Mao
2026-05-19 20:33 ` [PATCH 2/7] docs: document hwiso WorldGuard DT bindings Raymond Mao
2026-05-19 20:33 ` [PATCH 3/7] [NOT-FOR-UPSTREAM] platform: virt: add QEMU WorldGuard hwiso overlay Raymond Mao
2026-05-19 20:33 ` [PATCH 4/7] platform: generic: add WorldGuard hwiso support with wgchecker2 Raymond Mao
2026-05-19 20:33 ` [PATCH 5/7] test: add generic hwiso SBI unit coverage Raymond Mao
2026-05-19 20:33 ` Raymond Mao [this message]
2026-05-19 20:33 ` [PATCH 7/7] platform: virt: add WorldGuard HWISO failure-mode SBIUNIT test Raymond Mao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260519203331.2773185-7-raymondmaoca@gmail.com \
    --to=raymondmaoca@gmail.com \
    --cc=anup.patel@qti.qualcomm.com \
    --cc=anup@brainfault.org \
    --cc=anuppate@qti.qualcomm.com \
    --cc=dave.patel@riscstar.com \
    --cc=dhaval@rivosinc.com \
    --cc=opensbi@lists.infradead.org \
    --cc=peter.lin@sifive.com \
    --cc=raymond.mao@riscstar.com \
    --cc=robin.randhawa@sifive.com \
    --cc=samuel.holland@sifive.com \
    --cc=scott@riscstar.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox