[PATCH 5/7] test: add generic hwiso SBI unit coverage

Raymond Mao raymondmaoca at gmail.com
Tue May 19 13:33:29 PDT 2026


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

Add a generic HWISO SBI unit suite that exercises boot-time
initialization and domain-switch hook sequencing without embedding one
platform mechanism's policy directly into the core test driver.

Provide a small test registration layer so each HWISO mechanism can
supply its own state and quiesce assertions.

Signed-off-by: Raymond Mao <raymond.mao at riscstar.com>
---
 include/sbi/sbi_hwiso_test.h |  33 +++++++
 lib/sbi/objects.mk           |   3 +
 lib/sbi/sbi_hwiso_test.c     | 167 +++++++++++++++++++++++++++++++++++
 lib/sbi/sbi_hwiso_testlib.c  | 108 ++++++++++++++++++++++
 4 files changed, 311 insertions(+)
 create mode 100644 include/sbi/sbi_hwiso_test.h
 create mode 100644 lib/sbi/sbi_hwiso_test.c
 create mode 100644 lib/sbi/sbi_hwiso_testlib.c

diff --git a/include/sbi/sbi_hwiso_test.h b/include/sbi/sbi_hwiso_test.h
new file mode 100644
index 00000000..3970df5a
--- /dev/null
+++ b/include/sbi/sbi_hwiso_test.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2026 RISCstar Solutions Corporation.
+ *
+ * Author: Raymond Mao <raymond.mao at riscstar.com>
+ */
+
+#ifndef __SBI_HWISO_TEST_H__
+#define __SBI_HWISO_TEST_H__
+
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_hwiso.h>
+#include <sbi/sbi_unit_test.h>
+
+#ifdef CONFIG_SBIUNIT
+struct sbi_hwiso_test_ops {
+	void (*boot_test)(struct sbiunit_test_case *test);
+	void (*domain_state_test)(struct sbiunit_test_case *test,
+				 const struct sbi_domain *dom, void *ctx);
+	void (*domain_quiesce_test)(struct sbiunit_test_case *test,
+				    const struct sbi_domain *dom, void *ctx);
+};
+
+int sbi_hwiso_test_register(const struct sbi_hwiso_ops *ops,
+			    const struct sbi_hwiso_test_ops *test_ops);
+void sbi_hwiso_test_boot(struct sbiunit_test_case *test);
+void sbi_hwiso_test_domain_state(struct sbiunit_test_case *test,
+				 const struct sbi_domain *dom);
+void sbi_hwiso_test_domain_quiesced(struct sbiunit_test_case *test,
+				    const struct sbi_domain *dom);
+#endif
+
+#endif
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index 6091499a..8839d13c 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -13,9 +13,12 @@ libsbi-objs-y += riscv_hardfp.o
 libsbi-objs-y += riscv_locks.o
 libsbi-objs-$(CONFIG_SBIUNIT) += sbi_unit_test.o
 libsbi-objs-$(CONFIG_SBIUNIT) += sbi_unit_tests.o
+libsbi-objs-$(CONFIG_SBIUNIT) += sbi_hwiso_testlib.o
 
 libsbi-objs-$(CONFIG_SBIUNIT) += sbi_bitmap_test.o
+libsbi-objs-$(CONFIG_SBIUNIT) += sbi_hwiso_test.o
 carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += bitmap_test_suite
+carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += hwiso_test_suite
 carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += console_test_suite
 
 libsbi-objs-y += sbi_ecall.o
diff --git a/lib/sbi/sbi_hwiso_test.c b/lib/sbi/sbi_hwiso_test.c
new file mode 100644
index 00000000..716596e2
--- /dev/null
+++ b/lib/sbi/sbi_hwiso_test.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2026 RISCstar Solutions Corporation.
+ *
+ * Author: Raymond Mao <raymond.mao at riscstar.com>
+ */
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_domain_context.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_hwiso.h>
+#include <sbi/sbi_hwiso_test.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unit_test.h>
+
+static u32 hwiso_collect_switch_domains(struct sbi_domain *current,
+					struct sbi_domain **targets,
+					u32 max_targets)
+{
+	u32 i;
+	u32 count = 0;
+	struct sbi_domain *dom;
+
+	if (!targets || !max_targets)
+		return 0;
+
+	sbi_domain_for_each(i, dom) {
+		if (dom == current || dom == &root)
+			continue;
+
+		targets[count++] = dom;
+		if (count == max_targets)
+			return count;
+	}
+
+	if (current != &root && count < max_targets)
+		targets[count++] = &root;
+
+	return count;
+}
+
+static void hwiso_snapshot_context(struct sbi_context *ctx)
+{
+	struct sbi_trap_regs *trap_regs;
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+
+	trap_regs = (struct sbi_trap_regs *)(csr_read(CSR_MSCRATCH) -
+					     SBI_TRAP_REGS_SIZE);
+	ctx->regs = *trap_regs;
+	ctx->sstatus = csr_read(CSR_SSTATUS);
+	ctx->sie = csr_read(CSR_SIE);
+	ctx->stvec = csr_read(CSR_STVEC);
+	ctx->sscratch = csr_read(CSR_SSCRATCH);
+	ctx->sepc = csr_read(CSR_SEPC);
+	ctx->scause = csr_read(CSR_SCAUSE);
+	ctx->stval = csr_read(CSR_STVAL);
+	ctx->sip = csr_read(CSR_SIP);
+	ctx->satp = csr_read(CSR_SATP);
+	ctx->scounteren = 0;
+	ctx->senvcfg = 0;
+	if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
+		ctx->scounteren = csr_read(CSR_SCOUNTEREN);
+	if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
+		ctx->senvcfg = csr_read(CSR_SENVCFG);
+	ctx->initialized = true;
+}
+
+static struct sbi_context *hwiso_ensure_context(struct sbiunit_test_case *test,
+						struct sbi_domain *dom,
+						struct sbi_context *tmpl,
+						u32 hartindex)
+{
+	struct sbi_context *dom_ctx;
+
+	dom_ctx = sbi_hartindex_to_domain_context(hartindex, dom);
+	if (!dom_ctx) {
+		dom_ctx = sbi_zalloc(sizeof(*dom_ctx));
+		SBIUNIT_ASSERT_NE(test, dom_ctx, NULL);
+		dom_ctx->dom = dom;
+		dom->hartindex_to_context_table[hartindex] = dom_ctx;
+	}
+
+	if (tmpl) {
+		*dom_ctx = *tmpl;
+		dom_ctx->dom = dom;
+		dom->hartindex_to_context_table[hartindex] = dom_ctx;
+	}
+
+	return dom_ctx;
+}
+
+static void hwiso_boot_test(struct sbiunit_test_case *test)
+{
+	sbi_hwiso_test_boot(test);
+}
+
+static void hwiso_domain_switch_test(struct sbiunit_test_case *test)
+{
+	struct sbi_domain *cur_dom = sbi_domain_thishart_ptr();
+	struct sbi_context *ctx = sbi_domain_context_thishart_ptr();
+	struct sbi_domain *switch_doms[2];
+	struct sbi_context *cur_ctx;
+	struct sbi_context tmpl_ctx;
+	u32 switch_count;
+	u32 i;
+	u32 hartindex = sbi_hartid_to_hartindex(current_hartid());
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	bool debug_on = false;
+
+	SBIUNIT_ASSERT_NE(test, cur_dom, NULL);
+
+	if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
+		debug_on = true;
+	else
+		scratch->options |= SBI_SCRATCH_DEBUG_PRINTS;
+
+	if (!ctx) {
+		cur_ctx = sbi_zalloc(sizeof(*cur_ctx));
+		SBIUNIT_ASSERT_NE(test, cur_ctx, NULL);
+		cur_ctx->dom = cur_dom;
+		cur_dom->hartindex_to_context_table[hartindex] = cur_ctx;
+		ctx = cur_ctx;
+	}
+
+	hwiso_snapshot_context(ctx);
+	tmpl_ctx = *ctx;
+	switch_count = hwiso_collect_switch_domains(cur_dom, switch_doms, 2);
+
+	(void)hwiso_ensure_context(test, cur_dom, NULL, hartindex);
+	for (i = 0; i < switch_count; i++)
+		(void)hwiso_ensure_context(test, switch_doms[i], &tmpl_ctx,
+					   hartindex);
+
+	if (!switch_count)
+		goto out;
+
+	sbi_hwiso_domain_exit(cur_dom, switch_doms[0]);
+	sbi_hwiso_test_domain_quiesced(test, cur_dom);
+	sbi_hwiso_domain_enter(switch_doms[0], cur_dom);
+	sbi_hwiso_test_domain_state(test, switch_doms[0]);
+	sbi_hwiso_domain_exit(switch_doms[0], cur_dom);
+	sbi_hwiso_test_domain_quiesced(test, switch_doms[0]);
+	sbi_hwiso_domain_enter(cur_dom, switch_doms[0]);
+	sbi_hwiso_test_domain_state(test, cur_dom);
+
+	for (i = 0; i < switch_count; i++) {
+		SBIUNIT_ASSERT_EQ(test, sbi_domain_context_enter(switch_doms[i]), 0);
+		sbi_hwiso_test_domain_state(test, switch_doms[i]);
+	}
+
+	SBIUNIT_ASSERT_EQ(test, sbi_domain_context_enter(cur_dom), 0);
+	sbi_hwiso_test_domain_state(test, cur_dom);
+
+out:
+	if (!debug_on)
+		scratch->options &= ~SBI_SCRATCH_DEBUG_PRINTS;
+}
+
+static struct sbiunit_test_case hwiso_test_cases[] = {
+	SBIUNIT_TEST_CASE(hwiso_boot_test),
+	SBIUNIT_TEST_CASE(hwiso_domain_switch_test),
+	SBIUNIT_END_CASE,
+};
+
+SBIUNIT_TEST_SUITE(hwiso_test_suite, hwiso_test_cases);
diff --git a/lib/sbi/sbi_hwiso_testlib.c b/lib/sbi/sbi_hwiso_testlib.c
new file mode 100644
index 00000000..2a988088
--- /dev/null
+++ b/lib/sbi/sbi_hwiso_testlib.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2026 RISCstar Solutions Corporation.
+ *
+ * Author: Raymond Mao <raymond.mao at riscstar.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_hwiso_test.h>
+#include <sbi/sbi_list.h>
+
+struct sbi_hwiso_test_node {
+	const struct sbi_hwiso_ops *ops;
+	const struct sbi_hwiso_test_ops *test_ops;
+	struct sbi_dlist node;
+};
+
+static SBI_LIST_HEAD(hwiso_test_ops_list);
+
+static const struct sbi_hwiso_test_ops *
+sbi_hwiso_find_test_ops(const struct sbi_hwiso_ops *ops)
+{
+	struct sbi_hwiso_test_node *entry;
+
+	sbi_list_for_each_entry(entry, &hwiso_test_ops_list, node) {
+		if (entry->ops == ops)
+			return entry->test_ops;
+	}
+
+	return NULL;
+}
+
+int sbi_hwiso_test_register(const struct sbi_hwiso_ops *ops,
+			    const struct sbi_hwiso_test_ops *test_ops)
+{
+	struct sbi_hwiso_test_node *node;
+
+	if (!ops || !test_ops)
+		return SBI_EINVAL;
+	if (sbi_hwiso_find_test_ops(ops))
+		return SBI_EALREADY;
+
+	node = sbi_zalloc(sizeof(*node));
+	if (!node)
+		return SBI_ENOMEM;
+
+	node->ops = ops;
+	node->test_ops = test_ops;
+	SBI_INIT_LIST_HEAD(&node->node);
+	sbi_list_add_tail(&node->node, &hwiso_test_ops_list);
+
+	return 0;
+}
+
+void sbi_hwiso_test_boot(struct sbiunit_test_case *test)
+{
+	struct sbi_hwiso_test_node *entry;
+
+	sbi_list_for_each_entry(entry, &hwiso_test_ops_list, node) {
+		if (!entry->test_ops->boot_test)
+			continue;
+		entry->test_ops->boot_test(test);
+	}
+}
+
+void sbi_hwiso_test_domain_state(struct sbiunit_test_case *test,
+				 const struct sbi_domain *dom)
+{
+	const struct sbi_hwiso_test_ops *test_ops;
+	u32 i;
+
+	if (!dom || !dom->hwiso_ctxs)
+		return;
+
+	for (i = 0; i < dom->hwiso_ctx_count; i++) {
+		if (!dom->hwiso_ctxs[i].ops)
+			continue;
+
+		test_ops = sbi_hwiso_find_test_ops(dom->hwiso_ctxs[i].ops);
+		if (!test_ops || !test_ops->domain_state_test)
+			continue;
+
+		test_ops->domain_state_test(test, dom, dom->hwiso_ctxs[i].ctx);
+	}
+}
+
+void sbi_hwiso_test_domain_quiesced(struct sbiunit_test_case *test,
+				    const struct sbi_domain *dom)
+{
+	const struct sbi_hwiso_test_ops *test_ops;
+	u32 i;
+
+	if (!dom || !dom->hwiso_ctxs)
+		return;
+
+	for (i = 0; i < dom->hwiso_ctx_count; i++) {
+		if (!dom->hwiso_ctxs[i].ops)
+			continue;
+
+		test_ops = sbi_hwiso_find_test_ops(dom->hwiso_ctxs[i].ops);
+		if (!test_ops || !test_ops->domain_quiesce_test)
+			continue;
+
+		test_ops->domain_quiesce_test(test, dom,
+					      dom->hwiso_ctxs[i].ctx);
+	}
+}
-- 
2.25.1




More information about the opensbi mailing list