Skip to main content

Milestone 4

Milestone 4 Status

Milestone 4 introduced a generic framework for supporting platform specific system level hardware isolation features. The deliverables include a documentation of the design for the framework, an implementation of the generic parts of the design, and unit tests for validating the framework implementation.

The documentation and a patch series was sent to the OpenSBI mailing list on May 4, 2026 and is currently under active upstream review. Acceptance and merging of the M4 patch set should be soon, subject to maintainer review timelines and feedback.

Milestone 5 features an implementation of the hardware isolation framework using WorldGuard.


Milestone Description

This milestone develops generic hardware isolation features. OpenSBI needs extensions to allow optional, platform specific, system level hardware isolation features to be specified, configured and used on a per OpenSBI domain specific basis.

Overview

The system-level hardware isolation framework for OpenSBI providing abstraction on operations with: -Multi-mechanism registration / initialization / domain lifecycle callbacks -Global mechanism resources and per-domain isolation policies parsing from DeviceTree during initialization -WorldGuard DeviceTree binding model and test mechanism for demo and bring-up purpose -UT test suite to exercise isolation policies cleared / applied during domain switches

The implementation is complete and validated on QEMU (-M virt,aia=aplic), version: 10.1.93.

Background and Motivation

The existing OpenSBI domain lifecycle management was missing for system-level isolation handling. The new framework aligns with the system-level abstraction model by allowing multiple hardware isolation mechanisms to register, be initialized at boot, and receive domain lifecycle callbacks.

Design Goals

  1. Provide a registration-based system-level isolation framework.
  2. Allow multiple isolation mechanisms to coexist and be called in order.
  3. Keep default behavior unchanged when no mechanisms are registered.
  4. Maintain DeviceTree-driven per-domain isolation policies.
  5. Provide a WorldGuard DeviceTree binding for demo and bring-up.
  6. Ensure domain lifecycle events call all mechanisms.

Non-goals

  • Real hardware device support (i.e. WorldGuard, IOPMP) - will be delivered in M5.

High-Level Architecture

Design Overview

The hardware isolation framework provides:

  • A registration API for multiple mechanisms per domain (sbi_hwiso_register).
  • Boot-time initialization for mechanism-global resources (sbi_hwiso_init).
  • Per-domain initialization for domain isolation policies and context allocation (sbi_hwiso_domain_init).
  • Domain lifecycle callbacks (sbi_hwiso_domain_exit, sbi_hwiso_domain_enter).
  • Optional cleanup if a specific mechanism requires (sbi_hwiso_domain_cleanup).

Domains hold a list of mechanism contexts in struct sbi_domain, so each registered mechanism can store its own per-domain state.

Hardware Isolation Framework Core

Registration

The hardware isolation framework provides a registration list for multiple hardware isolation mechanisms during system initialization - each node of the list represents one registered mechanism.

Each mechanism registers its own operations via sbi_hwiso_register during the early boot stage, including all operations a mechanism requires through the domain lifcycle: init(), domain_init(), domain_exit(), domain_enter() and domain_cleanup().`

Below is the hardware isolation operations structure.

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);

/* Cleanup */
void (*domain_cleanup)(struct sbi_domain *dom, void *ctx);
};
Initialization

During domain boot-time, each registered mechanism will be initialized by sbi_hwiso_init as a system-level initialization, calling the registered init operation hook (ops->init()) for parsing the resources belong to each mechanism (i.e. devices and/or memory regions) from the DeviceTree, and save them as mechanism-global context.

Then, in the per-domain initialization stage, the hardware isolation domain initialization will be executed by sbi_hwiso_domain_init as a domain-level initialization, calling the registered mechanism-specific domain init hook (ops->domain_init()) for parsing all per-mechanism hardware isolation policies from each domain’s configuration node (please refer to the section DeviceTree-Binding Model for more details), and save them into the per-domain hardware isolation context structure below:

struct sbi_hwiso_domain_ctx {
const struct sbi_hwiso_ops *ops;
void *ctx;
};

So, both init() and domain_init() are mechanism implementation-specific and DeviceTree based.

Domain Switch

During domain switch, sbi_hwiso_domain_exit will be invoked to exit from the current domain, followed by sbi_hwiso_domain_enter to enter to the next domain. They will call ops->domain_exit() and ops->domain_enter() respectively. Optionally sbi_hwiso_domain_cleanup is intended for additional cleanup if the mechanism requires for (i.e. for error handling).

These operation functions are mechanism implementation-specific, managing the isolation devices / memory regions / configurations based on the mechanism-global context and per-domain hardware isolation context saved during the initialization stage.

DeviceTree-binding Model

The hardware isolation policies of each mechanism are represented by the hw-isolation subnodes under each domain configuration node, which are fully implementation-specific per mechanism. Below is an example of two mechanisms coexisting in one domain.

domain@1 {
compatible = "opensbi,domain,instance";
...
hw-isolation {
foo-mechanism {
compatible = "foo-vendor,foo-mechanism";
foo-policy = <...>;
};
bar-mechanism {
compatible = "bar-vendor,bar-mechanism";
bar-policy = <...>;
};
};
};

For testing purposes, the WorldGuard DeviceTree bindings are adopted to validate the hardware isolation framework.

Below the DeviceTree segment depicts the wg-demo has been assigned to domain@0 and domain@1 with different policies settings on (wid, widlist).

opensbi-domains {
compatible = "opensbi,domain,config";
#address-cells = <1>;
#size-cells = <0>;
...
root: domain@0 {
compatible = "opensbi,domain,instance";

...
hw-isolation {
wg-demo {
compatible = "sifive,wgchecker2";
worldguard,wid = <0>;
worldguard,widlist = <0 1 3>;
};
};
};

guest0: domain@1 {
compatible = "opensbi,domain,instance";
...
hw-isolation {
wg-demo {
compatible = "sifive,wgchecker2";
worldguard,wid = <1>;
worldguard,widlist = <1 3>;
};
};
};
};

WorldGuard wg-checker Test Mechanism for Demo

Together with the wg-demo node, a test driver based on the WorldGuard wg-checker was introduced to provide a minimal mechanism to exercise the hardware isolation framework (registration, DeviceTree parsing, enter/exit callbacks).

Below is the operation list implemented for registration under the hardware isolation framework.

static const struct sbi_hwiso_ops wgchecker_demo_ops = {
.name = "sifive,wgchecker2",
.init = wg_demo_init,
.domain_init = wg_demo_domain_init,
.domain_exit = wg_demo_domain_exit,
.domain_enter = wg_demo_domain_enter,
.domain_cleanup = wg_demo_domain_cleanup,
};

Test Suite for Unit Tests

The domain lifecycle test for hardware isolation leverages the existing OpenSBI Unit Test framework. A new test suite was introduced to demonstrate a domain context switch flow when hardware isolation is in use.

static struct sbiunit_test_case hwiso_test_cases[] = {
SBIUNIT_TEST_CASE(hwiso_domain_switch_test),
SBIUNIT_END_CASE,
};

SBIUNIT_TEST_SUITE(hwiso_test_suite, hwiso_test_cases);

Build Steps and Test Instructions

Build via Buildroot Project

Get Buildroot source code:

$ git clone https://gitlab.com/riseproject/riscv-optee/buildroot.git -b rp016_m4

Configure Buildroot:

$ cd buildroot
$ make qemu_riscv64_virt_optee_defconfig

Build:

$ make -j$(nproc)

To avoid building errors due to outdated Buildroot native CMakeLists.txt files, if you have a CMAKE version > 3.30 on your host, build with:

$ make -j$(nproc) CMAKE_POLICY_VERSION_MINIMUM=3.5

This will build all of the required components. All build artifacts can be found under output/build.

Running OpenSBI with Unit Test

Start QEMU:

./output/images/start-qemu-dto.sh

By running this script, the test DeviceTree overlay ‘qemu-virt-hwiso-overlay.dts’ will be compiled and applied to the dumped QEMU base DeviceTree before re-running QEMU.

Logs appear in the console after QEMU launch.

[HWISO] init sifive,wgchecker2
[WG] wg_demo_init
[WG] checker wgchecker@100000
[WG] reg[0] base=0x100000 size=0x1000
[WG] worldguard_cfg for wg-demo-device@10000000
[WG] reg[0] base=0x10000000 size=0x10000000
[WG] perms: 0x0 0xc0
[WG] worldguard_cfg for wg-demo-device@20000000
[WG] reg[0] base=0x20000000 size=0x10000000
[WG] perms: 0x0 0xc3
[WG] worldguard_cfg for wg-demo-device@30000000
[WG] reg[0] base=0x30000000 size=0x10000000
[WG] perms: 0x0 0xc0
[WG] worldguard_cfg for memory@80000000
[WG] reg[0] base=0x80000000 size=0x100000000
[WG] range[0] base=0x80000000 size=0x40000000
[WG] range[1] base=0xc0000000 size=0x1000000
[WG] range[2] base=0xc1000000 size=0x3f000000
[WG] perms: 0x0 0xcf 0x0 0xcc 0x0 0xcf
[HWISO] ops: sifive,wgchecker2, init domain: domain@1
[WG] wg_demo_domain_init
[WG] domain_init domain@1 wid=1 widlist_count=2
[HWISO] ops: sifive,wgchecker2, init domain: domain@0
[WG] wg_demo_domain_init
[WG] domain_init domain@0 wid=0 widlist_count=3
Domain2 Boot HARTID forced to 1
[HWISO] ops: sifive,wgchecker2, init domain: root
[WG] wg_demo_domain_init
[WG] domain_init root wid=<none> widlist_count=0

Above the system boot logs indicate the WorldGuard wg-checker demo mechanism (wgchecker_demo_ops) was registered and initialized successfully via the hardware isolation framework for domain@0 and domain@1, all related resources and per-domain isolation policies are parsed from DeviceTree and saved into context.

Then the SBI unit tests start automatically.

# Running SBIUNIT tests #
...
## Running test suite: hwiso_test_suite
[HWISO] ops: sifive,wgchecker2, domain exit src=domain@0 dst=domain@1
[WG] wg_demo_domain_exit
[WG] domain_exit src=domain@0 dst=domain@1
[HWISO] ops: sifive,wgchecker2, domain enter dst=domain@1 src=domain@0
[WG] wg_demo_domain_enter
[WG] domain_enter dst=domain@1 wid=1 widlist=1,3
[HWISO] ops: sifive,wgchecker2, domain exit src=domain@1 dst=root
[WG] wg_demo_domain_exit
[WG] domain_exit src=domain@1 dst=root
[HWISO] ops: sifive,wgchecker2, domain enter dst=root src=domain@1
[WG] wg_demo_domain_enter
[WG] domain_enter dst=root
[PASSED] hwiso_domain_switch_test
1 PASSED / 0 FAILED / 1 TOTAL

The hardware isolation test suite switches the domains following the sequence: domain@0 -> domain@1 -> root. During each domain switch, the logs depict the corresponding WorldGuard isolation policies (wid, widlist) being cleared or applied, showing the hardware isolation framework is working properly when domain switches occur.