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

Raymond Mao <[email protected]>
Newsgroups org.infradead.lists.opensbi
Message-ID <[email protected]>
From: Raymond Mao <[email protected]>

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 <[email protected]>
---
 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+#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 <[email protected]>
+ */
+
+#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


-- 
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.