[RFC PATCH] sbi: add hardware isolation abstraction framework

Raymond Mao
2026-03-17T20:19:16Z

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

Introduce a system-level hardware isolation framework with a
registration API and per-domain context tracking.
This establishes an abstraction that allows multiple mechanisms to
be composed while keeping core domain data structures independent
of any single platform implementation.

Signed-off-by: Raymond Mao <raymond.mao@riscstar.com>
---
include/sbi/sbi_domain.h | 4 +
include/sbi/sbi_hwiso.h | 57 +++++++++++
lib/sbi/objects.mk | 1 +
lib/sbi/sbi_hwiso.c | 215 +++++++++++++++++++++++++++++++++++++++
4 files changed, 277 insertions(+)
create mode 100644 include/sbi/sbi_hwiso.h
create mode 100644 lib/sbi/sbi_hwiso.c

diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 02765777..fc7330a6 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -14,6 +14,7 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_domain_context.h>
+#include <sbi/sbi_hwiso.h>
#include <sbi/sbi_rpxy.h>

struct sbi_scratch;
@@ -199,6 +200,9 @@ struct sbi_domain {
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
+ /** Hardware isolation contexts for registered mechanisms */
+ struct sbi_hwiso_domain_ctx *hwiso_ctxs;
+ u32 hwiso_ctx_count;
/** Identifies whether to include the firmware region */
bool fw_region_inited;
};
diff --git a/include/sbi/sbi_hwiso.h b/include/sbi/sbi_hwiso.h
new file mode 100644
index 00000000..adbeb715
--- /dev/null
+++ b/include/sbi/sbi_hwiso.h
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * System-level hardware isolation framework
+ *
+ * Copyright (c) 2026 RISCstar Solutions Corporation.
+ *
+ * Author: Raymond Mao <raymond.mao@riscstar.com>
+ */
+
+#ifndef __SBI_HWISO_H__
+#define __SBI_HWISO_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_domain;
+
+struct sbi_hwiso_ops {
+ const char *name;
+
+ /* Boot-time init */
+ int (*init)(void *fdt);
+
+ /* Per-domain init (domain_offset refers to domain instance node) */
+ int (*domain_init)(void *fdt, int domain_offset,
+ struct sbi_domain *dom, void **ctx);
+
+ /* Before switching away from a domain */
+ void (*domain_exit)(const struct sbi_domain *src,
+ const struct sbi_domain *dst, void *ctx);
+
+ /* After switching into a domain */
+ void (*domain_enter)(const struct sbi_domain *dst,
+ const struct sbi_domain *src, void *ctx);
+
+ /* Optional cleanup */
+ void (*domain_cleanup)(struct sbi_domain *dom, void *ctx);
+};
+
+struct sbi_hwiso_domain_ctx {
+ const struct sbi_hwiso_ops *ops;
+ void *ctx;
+};
+
+int sbi_hwiso_register(const struct sbi_hwiso_ops *ops);
+
+int sbi_hwiso_init(void *fdt);
+int sbi_hwiso_domain_init(void *fdt, int domain_offset,
+ struct sbi_domain *dom);
+
+void sbi_hwiso_domain_exit(const struct sbi_domain *src,
+ const struct sbi_domain *dst);
+void sbi_hwiso_domain_enter(const struct sbi_domain *dst,
+ const struct sbi_domain *src);
+void sbi_hwiso_domain_cleanup(struct sbi_domain *dom);
+
+#endif /* __SBI_HWISO_H__ */
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index ca312ee2..6091499a 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -72,6 +72,7 @@ libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
+libsbi-objs-y += sbi_hwiso.o
libsbi-objs-y += sbi_heap.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o
diff --git a/lib/sbi/sbi_hwiso.c b/lib/sbi/sbi_hwiso.c
new file mode 100644
index 00000000..5f876b33
--- /dev/null
+++ b/lib/sbi/sbi_hwiso.c
@@ -0,0 +1,215 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * System-level hardware isolation framework
+ *
+ * Copyright (c) 2026 RISCstar Solutions Corporation.
+ *
+ * Author: Raymond Mao <raymond.mao@riscstar.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_hwiso.h>
+#include <sbi/sbi_list.h>
+
+struct sbi_hwiso_node {
+ const struct sbi_hwiso_ops *ops;
+ struct sbi_dlist node;
+};
+
+static SBI_LIST_HEAD(hwiso_ops_list);
+static u32 hwiso_ops_count;
+
+static bool hwiso_ops_registered(const struct sbi_hwiso_ops *ops)
+{
+ struct sbi_hwiso_node *entry;
+
+ sbi_list_for_each_entry(entry, &hwiso_ops_list, node) {
+ if (entry->ops == ops)
+ return true;
+ }
+
+ return false;
+}
+
+int sbi_hwiso_register(const struct sbi_hwiso_ops *ops)
+{
+ struct sbi_hwiso_node *node;
+
+ if (!ops || !ops->name)
+ return SBI_EINVAL;
+
+ if (hwiso_ops_registered(ops))
+ return SBI_EALREADY;
+
+ node = sbi_zalloc(sizeof(*node));
+ if (!node)
+ return SBI_ENOMEM;
+
+ node->ops = ops;
+ SBI_INIT_LIST_HEAD(&node->node);
+ sbi_list_add_tail(&node->node, &hwiso_ops_list);
+ hwiso_ops_count++;
+
+ return 0;
+}
+
+int sbi_hwiso_init(void *fdt)
+{
+ struct sbi_hwiso_node *entry;
+ int rc;
+
+ sbi_list_for_each_entry(entry, &hwiso_ops_list, node) {
+ if (!entry->ops->init)
+ continue;
+
+ rc = entry->ops->init(fdt);
+ if (rc == SBI_ENOMEM)
+ return rc;
+ if (rc)
+ sbi_printf("hwiso: %s init failed (error %d)\n",
+ entry->ops->name, rc);
+ }
+
+ return 0;
+}
+
+static void hwiso_warn_unknown_nodes(void *fdt, int domain_offset)
+{
+ int hoff, child;
+ struct sbi_hwiso_node *entry;
+ bool known;
+
+ if (!fdt || (domain_offset < 0))
+ return;
+
+ hoff = fdt_subnode_offset(fdt, domain_offset, "hw-isolation");
+ if (hoff < 0)
+ return;
+
+ fdt_for_each_subnode(child, fdt, hoff) {
+ known = false;
+ sbi_list_for_each_entry(entry, &hwiso_ops_list, node) {
+ if (!fdt_node_check_compatible(
+ fdt, child, entry->ops->name)) {
+ known = true;
+ break;
+ }
+ }
+
+ if (!known)
+ sbi_printf("hwiso: unknown mechanism at %s\n",
+ fdt_get_name(fdt, child, NULL));
+ }
+}
+
+int sbi_hwiso_domain_init(void *fdt, int domain_offset,
+ struct sbi_domain *dom)
+{
+ struct sbi_hwiso_node *entry;
+ struct sbi_hwiso_domain_ctx *ctxs;
+ void *ctx;
+ u32 idx = 0;
+ int rc;
+
+ if (!dom)
+ return 0;
+
+ if (!hwiso_ops_count) {
+ hwiso_warn_unknown_nodes(fdt, domain_offset);
+ return 0;
+ }
+
+ ctxs = sbi_calloc(sizeof(*ctxs), hwiso_ops_count);
+ if (!ctxs)
+ return SBI_ENOMEM;
+
+ dom->hwiso_ctxs = ctxs;
+ dom->hwiso_ctx_count = hwiso_ops_count;
+
+ sbi_list_for_each_entry(entry, &hwiso_ops_list, node) {
+ ctxs[idx].ops = entry->ops;
+ ctxs[idx].ctx = NULL;
+ ctx = NULL;
+
+ if (entry->ops->domain_init) {
+ rc = entry->ops->domain_init(fdt, domain_offset,
+ dom, &ctx);
+ if (rc == SBI_ENOMEM) {
+ sbi_hwiso_domain_cleanup(dom);
+ return rc;
+ }
+ if (rc) {
+ sbi_printf("hwiso: %s domain init failed"
+ " (error %d)\n",
+ entry->ops->name, rc);
+ ctx = NULL;
+ }
+ }
+
+ ctxs[idx].ctx = ctx;
+ idx++;
+ }
+
+ hwiso_warn_unknown_nodes(fdt, domain_offset);
+
+ return 0;
+}
+
+void sbi_hwiso_domain_exit(const struct sbi_domain *src,
+ const struct sbi_domain *dst)
+{
+ u32 i;
+
+ if (!src || !src->hwiso_ctxs)
+ return;
+
+ for (i = 0; i < src->hwiso_ctx_count; i++) {
+ if (!src->hwiso_ctxs[i].ops ||
+ !src->hwiso_ctxs[i].ops->domain_exit)
+ continue;
+ src->hwiso_ctxs[i].ops->domain_exit(
+ src, dst, src->hwiso_ctxs[i].ctx);
+ }
+}
+
+void sbi_hwiso_domain_enter(const struct sbi_domain *dst,
+ const struct sbi_domain *src)
+{
+ u32 i;
+
+ if (!dst || !dst->hwiso_ctxs)
+ return;
+
+ for (i = 0; i < dst->hwiso_ctx_count; i++) {
+ if (!dst->hwiso_ctxs[i].ops ||
+ !dst->hwiso_ctxs[i].ops->domain_enter)
+ continue;
+ dst->hwiso_ctxs[i].ops->domain_enter(
+ dst, src, dst->hwiso_ctxs[i].ctx);
+ }
+}
+
+void sbi_hwiso_domain_cleanup(struct sbi_domain *dom)
+{
+ u32 i;
+
+ if (!dom || !dom->hwiso_ctxs)
+ return;
+
+ for (i = 0; i < dom->hwiso_ctx_count; i++) {
+ if (!dom->hwiso_ctxs[i].ops ||
+ !dom->hwiso_ctxs[i].ops->domain_cleanup)
+ continue;
+ dom->hwiso_ctxs[i].ops->domain_cleanup(
+ dom, dom->hwiso_ctxs[i].ctx);
+ }
+
+ sbi_free(dom->hwiso_ctxs);
+ dom->hwiso_ctxs = NULL;
+ dom->hwiso_ctx_count = 0;
+}
--
2.25.1