OpenSBI is the open source reference implementation of the RISC-V Supervisor Binary Interface (SBI). It runs in machine mode (M-mode), the most privileged level on a RISC-V core, and gives an operating system kernel in supervisor mode a small, standard set of services: timers, inter-processor interrupts, remote TLB fences, starting and stopping cores, and reboot. On a typical board it sits between a first stage loader and U-Boot or EDK II, and it stays resident after Linux boots.
If you have booted Linux on a RISC-V development board, a RISC-V laptop or the QEMU virt machine, OpenSBI very likely ran before your bootloader did, and it is still running underneath your kernel now. This guide goes one level deeper than our posts on coreboot, on the difference between secure, trusted and measured boot and on how motherboard firmware evolved from BIOS to UEFI. Every register, extension ID, build flag and command below comes from the RISC-V specifications, the OpenSBI, Linux, U-Boot and QEMU documentation, and the project repositories listed at the end.
Key takeaways
- RISC-V defines three privilege levels: user (U), supervisor (S) and machine (M). Only M-mode is mandatory. The hypervisor extension splits supervisor mode into HS-mode for the host and VS-mode and VU-mode for guests.
- Some jobs can only be done in M-mode on many platforms: programming the machine timer, sending inter-processor interrupts through the core local interruptor, configuring physical memory protection, and resetting the system. The SBI is the contract that lets an S-mode kernel ask M-mode firmware to do those jobs.
- The SBI specification is maintained by RISC-V International in the
riscv-non-isa/riscv-sbi-docrepository. Version 3.0 was tagged as ratified on 16 July 2025. Calls use theECALLinstruction with the extension ID in registera7and the function ID ina6. - OpenSBI ships three firmware types.
fw_dynamicreads the next stage address from a structure the previous stage passes ina2.fw_jumpjumps to an address fixed at build time.fw_payloadbundles the next stage (U-Boot or a kernel) inside the firmware image. - QEMU's documentation calls U-Boot SPL in M-mode, loading OpenSBI
fw_dynamicand U-Boot proper in S-mode, "the recommended RISC-V bootflow". The device tree address travels in registera1through every stage, and the boot hart ID travels ina0. - The RVA23 profile (ratified October 2024), the Boot and Runtime Services specification (ratified August 2025) and the server platform specification (first ratified release May 2026) push RISC-V servers toward UEFI and ACPI rather than board specific boot flows.
- Physical memory protection (PMP) is how M-mode firmware fences off its own memory. Smepmp adds rules that stop M-mode itself from executing or touching lower privilege memory. Smmtt, which would add supervisor domain isolation for confidential computing, was at v0.9.0 in August 2026 and is not ratified.
- RISC-V has no single architectural secure boot: a boot ROM verifies the first stage, then each stage verifies the next, for example U-Boot checking a signed FIT image.
What are RISC-V's privilege modes?
RISC-V calls a hardware thread a hart. At any moment a hart runs at one privilege level, and the privileged architecture defines three of them, each with a two bit encoding.
| Level | Encoding | Name | Abbreviation | What usually runs there |
|---|---|---|---|---|
| 0 | 00 | User/Application | U | Applications |
| 1 | 01 | Supervisor | S | OS kernel, S-mode U-Boot, EDK II firmware |
| 2 | 10 | Reserved | Nothing today | |
| 3 | 11 | Machine | M | Boot ROM, U-Boot SPL, OpenSBI or another SBI firmware |
The privileged specification is explicit that the machine level "has the highest privileges and is the only mandatory privilege level for a RISC-V hardware platform". A small microcontroller may implement only M-mode. A secure embedded design may implement M and U. A core that runs Linux implements M, S and U, because Linux needs supervisor mode for virtual memory.
What does the hypervisor extension add?
The hypervisor (H) extension does not add a fourth privilege level between S and M. Instead it adds a virtualization mode bit. With H implemented, supervisor mode becomes hypervisor extended supervisor mode (HS-mode), where a host kernel such as Linux with KVM runs. Guests run in virtual supervisor mode (VS-mode) and virtual user mode (VU-mode). The SBI specification follows the same split: an SBI implementation can be M-mode firmware serving an HS-mode or S-mode kernel, or a hypervisor in HS-mode serving a VS-mode guest kernel. That is why KVM appears as implementation ID 3 in the SBI specification's list of implementations. RVA23 makes the hypervisor extension mandatory, and RISC-V International's ratification announcement tied that to virtualization for enterprise workloads in on premises servers and the cloud.
Why does the operating system need firmware in M-mode at all?
On x86 and Arm, the firmware that stays resident (SMM handlers, the EL3 secure monitor) rarely sits in the kernel's path for routine work. RISC-V M-mode firmware often does, for three reasons that come from the architecture.
First, some hardware is reachable only from M-mode on many implementations. The classic RISC-V core local interruptor (CLINT) holds the machine timer compare registers and the machine software interrupt registers. The Sstc chapter of the privileged specification states the problem directly: the base privileged architecture defines a hardware mechanism only for machine mode timer interrupts, so timer services for S-mode and HS-mode "have to all be provided by M-mode" through SBI calls. Sstc adds a supervisor timer compare register to remove that round trip, but a kernel cannot assume it on older cores. The same is true for sending an inter-processor interrupt to another hart on a CLINT based system.
Second, physical memory protection is an M-mode feature. PMP entries are machine level control and status registers (CSRs). Only M-mode can program them, so only M-mode can decide which physical memory S-mode is allowed to touch, including the memory that holds the firmware itself.
Third, the RISC-V specifications deliberately leave platform details such as reset, power off and starting secondary harts to the platform. The SBI turns those platform specific operations into a portable call, so the same kernel binary can boot on many SoCs. The SBI specification puts the goal plainly: the SBI lets S-mode or VS-mode software "be portable across all RISC-V implementations".
The privileged specification itself describes this layering. An operating system talks to a supervisor execution environment (SEE) through a supervisor binary interface, and the SEE can be a boot loader and firmware on a simple system or a hypervisor on a large server. OpenSBI is one SEE. A hypervisor is another.
What does M-mode firmware do after boot?
After the kernel starts, M-mode firmware runs only when something traps into it: an SBI call through ECALL, an interrupt or exception left with M-mode rather than delegated to S-mode, or an operation the firmware emulates, such as the misaligned load and store emulation that OpenSBI v1.9 improved for vector accesses. The Linux boot requirements treat that firmware as part of the platform: its resident memory, and any PMP protected memory, must be marked reserved so the kernel never maps it.
What is the Supervisor Binary Interface (SBI)?
The SBI is a specification, not a piece of software. RISC-V International maintains it as a non ISA specification in the riscv-non-isa/riscv-sbi-doc GitHub repository. The OpenSBI README describes the SBI as "the recommended interface" between platform firmware in M-mode and a bootloader, hypervisor or OS in S-mode or HS-mode, and between a hypervisor in HS-mode and a guest in VS-mode.
Which SBI version is current?
The repository's releases show version 3.0 tagged "Release 3.0 (Ratified)" on 16 July 2025, after release candidates that ran from November 2024 to June 2025. The specification's change log records the jump from v0.1 (now the "legacy" extension) through v0.2, which introduced extension probing, v0.3, which added system reset, hart suspend and the performance monitoring extension, v1.0, v2.0, and v3.0.
| Version | Key additions recorded in the SBI change log |
|---|---|
| v0.1 | Original calls (set timer, console, IPI, remote fences, shutdown); now the optional legacy extension |
| v0.2 | Base extension with probing; the v0.1 calls moved to the legacy extension |
| v0.3 | System reset (SRST), HSM hart suspend, performance monitoring unit (PMU) |
| v1.0 | Updated calling convention; RV32 references removed; ratification |
| v2.0 | Debug console, system suspend, CPPC, nested acceleration, steal time accounting, PMU snapshot |
| v3.0 | Supervisor software events (SSE), firmware features (FWFT), debug triggers (DBTR), message proxy (MPXY), new error codes |
The spec version is something the kernel can read at run time. The base extension's first function, sbi_get_spec_version, returns the minor number in the low 24 bits and the major number in the next 7 bits.
How does an SBI call work?
Every SBI function uses the same binary encoding:
- The caller executes
ECALLto trap into the SBI implementation. - Register
a7holds the extension ID (EID). - Register
a6holds the function ID (FID) within that extension, for any extension defined in v0.2 or later. - Registers
a0toa5carry arguments. - The implementation returns an error code in
a0and a value ina1, which the specification describes as a C structure namedsbiretwith anerrorfield and avaluefield. All other registers must be preserved.
Standard error codes run from SBI_SUCCESS (0) through negative values such as SBI_ERR_NOT_SUPPORTED (minus 2), SBI_ERR_INVALID_PARAM (minus 3), SBI_ERR_DENIED (minus 4) and SBI_ERR_INVALID_ADDRESS (minus 5). Extension IDs for the newer extensions are ASCII strings packed into a number, which makes a register dump readable: 0x54494D45 spells "TIME", 0x48534D spells "HSM".
Which calls does the SBI provide?
The extensions a Linux kernel relies on for basic operation are the ones below. The EIDs come straight from the v3.0 specification.
| Extension | EID | What it does for the kernel |
|---|---|---|
| Base | 0x10 | Read the SBI spec version, implementation ID and version; probe whether an extension exists; read machine vendor, architecture and implementation IDs |
| Timer (TIME) | 0x54494D45 | Program the next timer event for the calling hart; replaces legacy EID 0x00 |
| IPI (sPI) | 0x735049 | Send a supervisor software interrupt to a set of harts; replaces legacy EID 0x04 |
| RFENCE (RFNC) | 0x52464E43 | Ask other harts to run FENCE.I, SFENCE.VMA and, with the hypervisor extension, HFENCE.GVMA and HFENCE.VVMA |
| Hart State Management (HSM) | 0x48534D | Start, stop, suspend and query harts; enables ordered boot, CPU hotplug and kexec |
| System Reset (SRST) | 0x53525354 | Shutdown, cold reboot or warm reboot, with an optional reason code |
| Legacy | 0x00 to 0x0F | The original v0.1 calls; optional and deprecated |
The specification also defines extensions for performance monitoring, debug console, system suspend, CPPC, nested acceleration, steal time accounting and the v3.0 additions, and reserves ranges for vendor and firmware specific calls. The interfaces are small: sbi_system_reset takes a 32 bit reset type (0 shutdown, 1 cold reboot, 2 warm reboot) and a 32 bit reason, and does not return on success.
Does the SBI describe the hardware?
No. The specification says it "doesn't specify any method for hardware discovery". S-mode software has to find devices through a device tree or ACPI. That split matters for security reviews: the SBI firmware decides what M-mode does, but the device tree or ACPI tables it passes along decide what the kernel thinks the machine looks like, including which memory is reserved.
Which SBI implementations exist besides OpenSBI?
The base extension's implementation ID table lists twelve, from the Berkeley Boot Loader (ID 0) and OpenSBI (1) to KVM (3), RustSBI (4), Xen Project (7), coreboot (9) and bhyve (11). It mixes M-mode firmware and hypervisors on purpose: anything above a supervisor that offers the SBI is an SBI implementation. Linux logs the ID at boot, so you can tell which one answers your calls.
What is OpenSBI?
OpenSBI is the project that set out to provide "an open-source reference implementation of the RISC-V SBI specifications for platform-specific firmwares executing in M-mode". It lives at github.com/riscv-software-src/opensbi under the BSD 2-Clause license. The copyright notice in the README names Western Digital (2019) and RISC-V International (2023), and the source reuses part of libfdt under its BSD 2-Clause option.
The core is libsbi.a, a platform independent static library that implements the SBI. A platform specific libplatsbi.a joins it to the hardware (console, interrupt controller, timer, reset), and example firmware images built from both can, in the README's words, replace the older riscv-pk Berkeley Boot Loader and hand off to bootloaders such as U-Boot. Most boards now use the generic platform, which reads the device tree at boot to pick drivers; the OpenSBI QEMU document builds the virt machine with PLATFORM=generic.
OpenSBI release timeline
| Date | Release or event | Source |
|---|---|---|
| 24 December 2024 | OpenSBI v1.6 | OpenSBI GitHub releases |
| 30 June 2025 | OpenSBI v1.7 | OpenSBI GitHub releases |
| 16 July 2025 | SBI specification v3.0 tagged ratified | riscv-sbi-doc releases |
| 29 December 2025 | OpenSBI v1.8 | OpenSBI GitHub releases |
| 8 January 2026 | OpenSBI v1.8.1 | OpenSBI GitHub releases |
| 1 July 2026 | OpenSBI v1.9 | OpenSBI GitHub releases |
Releases land roughly every six months. The v1.9 notes list a stack guard initialised from the Zkr entropy extension, NMI support through the Smrnmi extension, vector and floating point context save and restore across domain switches, common PMP encoding helpers and UBSan support, along with new platform and driver ports.
One caution when reading the repository: the README's "Supported SBI version" section still says OpenSBI "fully supports SBI specification v0.2" and describes HSM support from OpenSBI v0.7. That text predates later releases. To learn which SBI version a given build implements, read the banner the firmware prints at boot ("Runtime SBI Version") or ask the kernel, which logs what it detected. The step by step section below shows both.
What are fw_jump, fw_payload and fw_dynamic?
All three firmware types run the same initialisation. They differ in how they learn where the next stage is and whether they carry it. Every type expects the previous stage to pass the hart ID in a0 and the device tree address in a1, aligned to 8 bytes. A stage that cannot set registers can patch the OpenSBI firmware header instead.
| Firmware type | How it finds the next stage | When to use it | Key build options |
|---|---|---|---|
fw_dynamic | Reads a struct fw_dynamic_info whose address the previous stage passes in a2 (8 byte aligned on RV64) | The previous stage loads both OpenSBI and the next stage and can describe them at run time, as U-Boot SPL does | FW_DYNAMIC=y; no platform specific parameters |
fw_jump | Jumps to an address fixed at build time | The previous stage (or QEMU's -kernel) loads the next stage at a known address | FW_JUMP=y, FW_JUMP_ADDR or FW_JUMP_OFFSET, optional FW_JUMP_FDT_ADDR |
fw_payload | Carries the next stage inside its own image | The previous stage can load only one image, or passes no device tree | FW_PAYLOAD=y, FW_PAYLOAD_PATH, optional FW_FDT_PATH to embed a device tree |
Common options apply to all three. FW_TEXT_START sets the link address. FW_FDT_PATH embeds a device tree in the firmware's read only data. FW_OPTIONS is a bit field of run time behaviours; the documentation gives FW_OPTIONS=0x1 as the setting that disables the boot banner. Each build produces an ELF (fw_jump.elf) and a flat binary (fw_jump.bin) under build/platform/<platform>/firmware/ in the build tree.
From a security point of view the choice matters more than it looks. fw_payload produces one image that holds both M-mode firmware and the next stage, so one signature or one hash can cover both. fw_dynamic and fw_jump separate them, which means whatever loads OpenSBI must also verify the next stage, or OpenSBI will jump into whatever sits at that address. In the U-Boot SPL flow, U-Boot SPL loads a FIT image containing OpenSBI and U-Boot proper, so FIT signature verification in SPL can cover both.
What are OpenSBI domains?
OpenSBI's domain support describes "a system-level partition (subset) of underlying hardware". Each domain has a set of harts and a list of memory regions with permissions, and every hart is assigned to exactly one domain. By default every hart belongs to the ROOT domain. Platforms can define more domains, usually in the device tree, so that, for example, one hart runs a small trusted runtime that the main OS cannot read. OpenSBI enforces domain memory regions by programming PMP entries when it enters a domain. The v1.9 release added vector and floating point context save and restore when switching domains, which is the kind of detail that decides whether a domain switch leaks register state.
What does a RISC-V boot flow look like?
There is no single RISC-V boot flow, but most Linux capable boards follow the same shape. Each stage passes the boot hart ID in a0 and the device tree address in a1, as both the U-Boot RISC-V document and the Linux boot requirements describe.
| Stage | Mode | Typical software | Job | Who verifies it |
|---|---|---|---|---|
| 0. Zero stage boot loader (ZSBL) | M | Mask ROM inside the SoC | Pick a boot source (SPI flash, eMMC, SD, UART), load the next stage into on chip SRAM | Immutable; the hardware root of trust if the SoC supports secure boot |
| 1. First stage boot loader | M | U-Boot SPL, or a vendor loader | Train DRAM, load OpenSBI and the next stage from storage | The ROM, if secure boot is fused on |
| 2. SBI firmware | M, stays resident | OpenSBI fw_dynamic (or fw_jump, fw_payload) | Set up PMP, interrupt delegation, timers and HSM; drop to S-mode | The first stage loader (for example SPL verifying a signed FIT) |
| 3. OS loader | S | U-Boot proper, or EDK II (UEFI) | Find and load the kernel, device tree and initramfs; offer a boot menu | The previous stage, or UEFI Secure Boot inside EDK II |
| 4. Kernel | S (HS with KVM) | Linux | Takes the device tree or ACPI tables, starts other harts through SBI HSM | U-Boot FIT signatures, or UEFI Secure Boot through a signed shim or kernel |
QEMU's virt machine documentation names the middle of this chain directly: it supports "the recommended RISC-V bootflow: U-Boot SPL (M-mode) loads OpenSBI fw_dynamic firmware and U-Boot proper (S-mode)". The U-Boot QEMU document fills in the detail: SPL starts in M-mode, U-Boot proper and OpenSBI fw_dynamic are bundled as a FIT image, SPL loads both, passes the location of U-Boot proper to OpenSBI, and OpenSBI starts U-Boot proper in S-mode.
The U-Boot RISC-V architecture document also describes a simpler alternative where U-Boot itself runs in M-mode and loads a fw_payload image holding the SBI firmware and the S-mode OS. That flow is common on development boards and in bring up, less so in products.
What does Linux expect when it gets control?
The Linux kernel documentation, "RISC-V Kernel Boot Requirements and Constraints", is short and specific:
a0holds the hart ID of the current core anda1holds the device tree address.- The
satpCSR is 0, so the MMU is off. - Resident firmware memory and PMP protected memory are marked as reserved, so the kernel never maps them.
- The kernel image sits on a PMD boundary: 2 MB aligned on RV64 and 4 MB on RV32 (the EFI stub relocates it if not).
- Hardware is described by either a device tree (in
a1, or through the EFI configuration table) or ACPI tables (through the EFI configuration table, with the EFI stub creating a tiny device tree).
For SMP systems the document describes two ways to enter the kernel. In the older "spinwait" method, firmware releases every hart into the kernel and one wins a "lottery". In ordered booting, firmware releases one hart and the kernel starts the rest through the SBI HSM extension. The kernel documentation calls ordered booting the preferred method because it supports CPU hotplug and kexec. The OpenSBI README adds the history: HSM support landed in OpenSBI v0.7, and Linux has supported it since v5.7-rc1.
Where do UEFI and EDK II fit?
When the OS loader is UEFI firmware (EDK II is the common open source one), the kernel boots through its EFI stub. The kernel documentation then requires two things of the firmware: it must convert device tree /reserved-memory nodes into the right EFI memory types, and it must implement RISCV_EFI_BOOT_PROTOCOL so the stub can learn the boot hart ID. The older method of reading the boot hart ID from a device tree node is deprecated, and the document says "any new firmware must implement" the protocol. EDK II still runs in S-mode on top of an SBI firmware; UEFI does not replace OpenSBI on RISC-V, it replaces U-Boot proper.
QEMU shows this flow too. Its virt documentation gives an example that boots EDK II from the first emulated flash device (pflash0), read only, with a second flash device for UEFI variables, and notes that images used for pflash must be exactly 32 MiB.
How do RISC-V profiles and platform specs push toward UEFI and ACPI?
A RISC-V core is a base ISA plus a list of optional extensions. That flexibility is great for chip designers and hard for operating system vendors, who need to know what they can assume. RISC-V International answers that with three kinds of documents.
Profiles fix a set of mandatory extensions. RISC-V International announced the ratification of the RVA23 profile on 21 October 2024, describing RVA profiles as aligning 64 bit application processors "that will run rich operating systems (OS) stacks from standard binary OS distributions". RVA23 makes the vector and hypervisor extensions mandatory, and the announcement says it is the baseline requirement for the Android RISC-V ABI. In the riscv/riscv-profiles repository, the combined release titled "RVA23 and RVB23 Profiles, Ratified" is dated 21 January 2025, three months after the announcement, so expect to see both dates quoted.
Boot and Runtime Services (BRS) says how firmware and the OS meet. The riscv-non-isa/riscv-brs repository's v1.0 release notes say the RISC-V Board of Directors ratified BRS on 28 August 2025, and a v1.0.6 release followed in September 2026. BRS defines two "recipes". BRS-I (for "Interoperable") targets servers, desktops and laptops, and aims to let an OS vendor build "a single generic operating system image" that boots on any compliant system. BRS-B (for "Bespoke") targets devices with tailored software, such as mobile, real time and embedded systems. Both recipes require an SBI implementation that conforms to SBI v2.0 or later and implements the HSM extension.
| BRS recipe | Profile | UEFI | ACPI | Device tree | SBI | SMBIOS |
|---|---|---|---|---|---|---|
| BRS-I (Interoperable) | RVA20S64 or later | 2.10 or later | 6.6 or later | Optional, v0.3 or later | 2.0 or later | 3.7.0 or later |
| BRS-B (Bespoke) | RVA20S64 or later | EBBR 2.1.0 or later | Optional, 6.6 or later | Optional, v0.3 or later | 2.0 or later | Optional, 3.7.0 or later |
BRS adds that either ACPI or a device tree may describe the hardware to the OS, "but never both at the same time". In other words, a BRS-I machine boots like a typical x86 or Arm server, with UEFI and ACPI, while a BRS-B board can keep a device tree and a lighter UEFI subset defined by EBBR, the Embedded Base Boot Requirements.
Platform specifications combine a profile with hardware and firmware requirements for a market. The riscv-non-isa/riscv-server-platform repository tagged v1.0, described as the "First ratified release", on 6 May 2026, after release candidates through 2025 and a v0.9 in February 2026.
The practical effect is that a RISC-V server built to these documents looks to the OS much like an Arm or x86 server, with UEFI, ACPI and a standard SBI underneath. The Linux kernel documents ACPI on RISC-V, and QEMU's virt machine generates ACPI tables by default (acpi=on). Boards and embedded systems will keep using device trees and U-Boot, and both paths are supported.
How do PMP, Smepmp and Smmtt isolate memory?
Physical memory protection (PMP)
PMP is the basic RISC-V isolation tool. Each PMP entry is an 8 bit configuration register (read, write, execute permissions, an address matching mode and a lock bit) paired with an address register. The privileged specification allows up to 64 entries and says implementations "may implement zero, 16, or 64 PMP entries". Ordinary PMP rules apply to S-mode and U-mode accesses. M-mode ignores a rule unless its lock bit is set, in which case the rule applies to M-mode too and cannot be changed until reset.
OpenSBI uses PMP to protect itself. Its domain documentation says the ROOT domain always includes "a memory region to protect OpenSBI firmware from S-mode and U-mode", which OpenSBI turns into PMP entries on every hart, and the boot banner reports the protection mechanism in its "Platform HART Protection" line. That is why the Linux boot document insists PMP protected memory is marked reserved: if the kernel tried to map it, every access would fault.
Smepmp
Plain PMP has a gap that the Smepmp chapter of the privileged specification describes in its threat model. Without Smepmp, a PMP rule cannot be enforced on lower modes while also being denied to M-mode. M-mode has unlimited access to any region that is not covered by a locked rule, "including the ability to execute it". So a bug in M-mode firmware that can be tricked into jumping into S-mode or U-mode memory hands the attacker M-mode execution. Smepmp adds three fields in a new mseccfg CSR, named RLB (rule locking bypass), MMWP (machine mode whitelist policy) and MML (machine mode lockdown), which let firmware forbid M-mode from executing, and optionally from accessing, memory that belongs to less privileged modes. It is the RISC-V counterpart of supervisor mode execution and access prevention on other architectures, applied one level up.
Smmtt and supervisor domains
PMP has a limited number of entries and works on physical address ranges, which does not scale to confidential computing, where many virtual machines each need memory the host kernel cannot read. The Smmtt specification (supervisor domain access protection through a memory tracking table) aims to define "the RISC-V privilege ISA extensions required to support Supervisor Domain isolation for multi-tenant security use cases e.g. confidential-computing, trusted platform services, fault isolation". The repository was created in April 2023 and released v0.9.0 on 19 August 2026. It is not ratified, so treat any product claim of Smmtt support as tracking a draft. OpenSBI's domain support is the firmware side that such hardware would plug into.
What do enclave projects such as Keystone do?
Keystone describes itself as "an open-source project for building customizable trusted execution environments (TEEs) based on RISC-V". Its design was published at EuroSys 2020. The documentation's overview lays out the pieces:
- A Security Monitor (SM), "M-mode software with small TCB", which manages enclave lifecycles and "enforces most of Keystone's security guarantees" by managing the isolation boundary between enclaves and the untrusted OS.
- Enclaves, each given "a private physical memory region which is accessible by only the enclave and SM".
- Inside each enclave, a user level enclave application and an S-mode runtime (the reference runtime is called Eyrie) that handles system calls, traps and virtual memory.
The SDK covers attestation and data sealing, and the documentation includes guides for QEMU, the open source CVA6 core, RV32 and a development board. The trick is that M-mode owns PMP, so a small M-mode monitor can carve out memory that even the S-mode kernel cannot read. Keystone is a research and prototyping framework rather than a feature of mainstream boards; it shows what the privilege model allows, not what your hardware already does.
How does secure boot work on RISC-V?
RISC-V International has not defined a single secure boot mechanism that every chip implements. Secure boot on RISC-V is built the same way it is on most systems: an immutable first stage verifies the next, and each stage verifies the one after.
- Root of trust. If the SoC supports it, the mask ROM verifies the first stage loader against a public key or key hash burned into one time programmable fuses. This step is vendor specific. Where it is absent or not enabled, anyone who can write to the boot media can replace every later stage.
- First stage to OpenSBI and U-Boot. U-Boot SPL can verify a signed FIT image that holds OpenSBI and U-Boot proper, using the public key compiled into SPL's control device tree.
- U-Boot to the kernel. U-Boot proper can verify a signed FIT image holding the kernel, device tree and initramfs. Alternatively, UEFI firmware (EDK II or U-Boot's own UEFI implementation) can run UEFI Secure Boot, checking EFI binaries against its signature databases.
- Measured boot. Each stage can also extend measurements into a TPM, if the board has one, so a remote verifier can check what booted. Verified boot stops bad code from running; measured boot lets you prove what ran. Our secure, trusted and measured boot explainer covers the difference.
How does U-Boot verify a signed FIT image?
U-Boot's "FIT Signature Verification" documentation explains the mechanism. A FIT (Flattened Image Tree) is a device tree formatted container described by an image tree source (.its) file. Each image and each configuration can have hash and signature nodes, using algorithm names such as sha256,rsa2048 or sha512,ecdsa256. The public keys live in a /signature node of U-Boot's control device tree. A key marked required = "conf" must verify a configuration before U-Boot will boot it. A configuration signature covers the configuration node and every image it references (kernel, device tree, ramdisk, loadables) with their hash nodes, so an attacker cannot pair a signed kernel with a swapped device tree. The documentation notes a subtle point: mkimage records the signed node list in a hashed-nodes property, but U-Boot does not trust that property during verification and rebuilds the list from the configuration's own image references, because hashed-nodes is not itself covered by the signature. Every referenced image must have at least one hash subnode. mkimage signs the FIT and writes the public key into the control device tree in one command:
tools/mkimage -f fit.its -K control.dtb -k keys -r image.fit
Here -K names the device tree that receives the public key, -k names the key directory, and -r marks the key as required.
Where does OpenSBI sit in that chain?
OpenSBI does not verify anything by default. It trusts whoever loaded it, and it jumps to whatever next stage it was given. That makes the stage before OpenSBI the one that matters: if U-Boot SPL verifies the FIT that contains OpenSBI and U-Boot proper, the M-mode firmware is covered. If SPL is not verified by the ROM, nothing after it is either. When you review a RISC-V product, ask which component verifies fw_dynamic.bin and with which key.
Step by step: build OpenSBI and U-Boot for QEMU, boot Linux and verify a signed FIT
This walkthrough uses QEMU's virt machine, the OpenSBI generic platform, U-Boot and a Linux kernel. It runs on any Linux host. Package names are for Debian and Ubuntu; adjust for your distribution. Nothing here writes to a physical disk, but step 7 creates signing keys: keep test keys and production keys in separate directories and never reuse a lab key on hardware.
Step 1: install a cross toolchain and QEMU
OpenSBI needs a toolchain that can build position independent executables. Its README says bare metal GNU toolchains such as riscv64-unknown-elf-gcc cannot be used, while riscv64-linux-gnu-gcc or Clang work. It also needs the device tree compiler and Python 3.
sudo apt install gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu \
device-tree-compiler python3 qemu-system-misc \
build-essential bison flex bc libssl-dev libgnutls28-dev u-boot-tools git
export CROSS_COMPILE=riscv64-linux-gnu-
qemu-system-riscv64 -version
Step 2: build OpenSBI
Pin a release tag rather than building from the default branch, so you know exactly which firmware you tested.
git clone https://github.com/riscv-software-src/opensbi.git
cd opensbi
git checkout v1.9
make PLATFORM=generic
ls build/platform/generic/firmware/
# fw_dynamic.bin fw_dynamic.elf fw_jump.bin fw_jump.elf fw_payload.bin fw_payload.elf ...
cd ..
The generic platform builds all three firmware types by default. With no FW_PAYLOAD_PATH, fw_payload carries a small test payload that prints a message, which is a quick way to check the toolchain.
qemu-system-riscv64 -M virt -m 256M -nographic \
-bios opensbi/build/platform/generic/firmware/fw_payload.bin
Press Ctrl-a then x to leave QEMU.
Step 3: build a Linux kernel
The OpenSBI QEMU document uses the kernel's RISC-V defconfig and the flat Image, not the ELF vmlinux.
git clone --depth 1 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j"$(nproc)" Image
ls -l arch/riscv/boot/Image
cd ..
You also need a root file system image. Any small RISC-V root file system works; a minimal one built with a build system such as Buildroot is the usual choice for a lab. The commands below call it rootfs.ext2.
Step 4: boot Linux with OpenSBI fw_jump
QEMU places the kernel at the address the generic fw_jump build jumps to (a fixed offset from the firmware base, set in the platform's objects.mk), and passes its generated device tree in a1.
qemu-system-riscv64 -M virt -m 1G -smp 4 -nographic \
-bios opensbi/build/platform/generic/firmware/fw_jump.bin \
-kernel linux/arch/riscv/boot/Image \
-drive file=rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
Before the kernel starts, OpenSBI prints a banner whose fields come from sbi_init.c: the version (OpenSBI v1.9), Platform Name, Platform HART Count, Platform HART Protection, Runtime SBI Version, Standard SBI Extensions and Boot HART ID, among others. The Runtime SBI Version and Standard SBI Extensions lines tell you what the kernel will find. If you leave out -bios, QEMU boots its own bundled OpenSBI instead of the one you built.
Step 5: read the SBI version from the kernel log
Once Linux is up, log in and run:
dmesg | grep -i sbi
The kernel's arch/riscv/kernel/sbi.c prints these lines during boot:
SBI specification v3.0 detected
SBI implementation ID=0x1 Version=0x10009
SBI TIME extension detected
SBI IPI extension detected
SBI RFENCE extension detected
SBI SRST extension detected
Implementation ID 0x1 is OpenSBI in the SBI specification's table. OpenSBI encodes its own version as the major number shifted left by 16 bits, combined with the minor number, according to sbi_version.h, so 0x10009 is OpenSBI 1.9. The exact spec version printed depends on what your OpenSBI build reports; check it against the banner from step 4. If the kernel reports an implementation ID other than 1, something else is answering your SBI calls, for example a hypervisor if you booted the kernel as a KVM guest.
Step 6: boot through U-Boot SPL, OpenSBI fw_dynamic and U-Boot proper
This is the recommended flow from the QEMU and U-Boot documents. U-Boot's build packages OpenSBI's fw_dynamic.bin and U-Boot proper into u-boot.itb; you point it at the OpenSBI binary with the OPENSBI variable.
git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot
git checkout v2026.10
make qemu-riscv64_spl_defconfig
make -j"$(nproc)" OPENSBI=../opensbi/build/platform/generic/firmware/fw_dynamic.bin
cd ..
qemu-system-riscv64 -M virt -m 1G -smp 4 -nographic \
-bios u-boot/spl/u-boot-spl.bin \
-device loader,file=u-boot/u-boot.itb,addr=0x80200000
You should see U-Boot SPL start, then the OpenSBI banner, then U-Boot proper, which is now running in S-mode. That sequence is the whole M-mode to S-mode handoff on one screen.
Step 7: add a verified boot step with a signed FIT image
Now make U-Boot refuse any kernel that is not signed with your key. To keep the lab simple, use S-mode U-Boot on top of OpenSBI fw_jump, and give QEMU a device tree that carries your public key. U-Boot on the virt machine takes its control device tree from the previous stage, which here means the file you pass with -dtb.
First build S-mode U-Boot with FIT signature checking turned on:
cd u-boot
make distclean
make qemu-riscv64_smode_defconfig
cat >> .config <<'CFG'
CONFIG_FIT_SIGNATURE=y
CONFIG_RSA=y
CFG
make olddefconfig
grep -E 'CONFIG_(FIT_SIGNATURE|RSA)=' .config
make -j"$(nproc)"
cd ..
Dump the device tree QEMU generates for your machine shape, so you can add a key to it. Keep the same -m and -smp values as the real boot, because QEMU's documentation requires a supplied device tree to match the CPU count and memory size.
qemu-system-riscv64 -M virt,dumpdtb=virt.dtb -m 1G -smp 4 -nographic
Create a lab signing key. This is a test key; store it outside any repository.
mkdir -p keys
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out keys/dev.key
openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt -subj "/CN=fit-lab-dev/"
Write an image tree source that holds the kernel and the device tree, with a signed configuration:
/dts-v1/;
/ {
description = "Signed RISC-V kernel for the QEMU lab";
#address-cells = <1>;
images {
kernel-1 {
data = /incbin/("linux/arch/riscv/boot/Image");
type = "kernel";
arch = "riscv";
os = "linux";
compression = "none";
load = <0x84000000>;
entry = <0x84000000>;
hash-1 { algo = "sha256"; };
};
fdt-1 {
data = /incbin/("virt.dtb");
type = "flat_dt";
arch = "riscv";
compression = "none";
hash-1 { algo = "sha256"; };
};
};
configurations {
default = "conf-1";
conf-1 {
kernel = "kernel-1";
fdt = "fdt-1";
signature-1 {
algo = "sha256,rsa2048";
key-name-hint = "dev";
};
};
};
};
Sign it, and write the public key into a copy of the QEMU device tree as a required key:
cp virt.dtb virt-with-key.dtb
mkimage -f kernel.its -K virt-with-key.dtb -k keys -r kernel.itb
fit_check_sign -f kernel.itb -k virt-with-key.dtb
fit_check_sign ships with U-Boot's host tools and checks the signature on the host before you boot anything. Now boot S-mode U-Boot with the keyed device tree and load the FIT into RAM:
qemu-system-riscv64 -M virt -m 1G -smp 4 -nographic \
-bios opensbi/build/platform/generic/firmware/fw_jump.bin \
-kernel u-boot/u-boot.bin \
-dtb virt-with-key.dtb \
-device loader,file=kernel.itb,addr=0xa0000000 \
-drive file=rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0
At the U-Boot prompt:
=> setenv bootargs "root=/dev/vda rw console=ttyS0"
=> bootm 0xa0000000
U-Boot reports that it is verifying the configuration signature with sha256,rsa2048 and the key named dev, then boots. To prove the check works, flip one byte of kernel.itb with a hex editor (on a copy) and boot it again: bootm refuses the image.
Be clear about what this lab proves. The public key sits in a device tree on the QEMU command line, and OpenSBI and U-Boot are unverified, so whoever controls the command line controls the key. On real hardware the key must live in a stage the ROM verifies, with the ROM's own key fused into the SoC. The lab teaches FIT mechanics; the root of trust is a hardware decision.
Step 8: record what you built
Write down the versions and hashes of everything in the chain, so a later rebuild can be compared.
sha256sum opensbi/build/platform/generic/firmware/fw_dynamic.bin \
opensbi/build/platform/generic/firmware/fw_jump.bin \
u-boot/spl/u-boot-spl.bin u-boot/u-boot.itb u-boot/u-boot.bin \
linux/arch/riscv/boot/Image kernel.itb > boot-chain.sha256
git -C opensbi describe --tags
git -C u-boot describe --tags
make -s -C linux kernelversion
OpenSBI vs Trusted Firmware-A vs UEFI with SMM
RISC-V, Arm and x86 each keep a small piece of firmware more privileged than the OS kernel. They solve similar problems in different ways.
| OpenSBI on RISC-V | Trusted Firmware-A on Arm | UEFI with SMM on x86 | |
|---|---|---|---|
| Privilege level | M-mode, the highest RISC-V level | EL3, the secure monitor level (BL31) | System Management Mode, entered through a system management interrupt |
| How the OS calls it | ECALL with EID in a7, FID in a6 | SMC under the SMC Calling Convention | Software SMI, usually through a port write; mostly invisible to the OS |
| Standard runtime services | SBI: timer, IPI, remote fences, hart start and stop (HSM), reset, PMU, suspend, debug console | PSCI for CPU on and off, suspend, reset; secure world switching; SDEI | Platform specific: flash writes for UEFI variables, power and thermal handling, legacy emulation |
| Stays resident after boot | Yes | Yes (BL31, plus an optional BL32 trusted OS) | Yes (SMM handlers in protected SMRAM) |
| Boot verification | Not by itself; the stage that loads it must verify it | Trusted Board Boot verifies BL2 to BL33 from a ROM key | Vendor boot guard features and UEFI Secure Boot for later stages |
| Open source reference | Yes, BSD 2-Clause | Yes, BSD 3-Clause | EDK II is open source; most shipped SMM code is vendor specific |
| Hardware description passed on | Device tree in a1, or ACPI via UEFI | Device tree or ACPI via UEFI | ACPI via UEFI |
| Update path | Rebuilt by the board vendor and shipped with SPL or as a FIT; on some boards a user can rebuild and flash it | Silicon vendor fork, device maker build; LTS branches carry fixes | Vendor firmware update, often as UEFI capsules through the OS |
The deeper difference is visibility. OpenSBI and Trusted Firmware-A are open and documented down to the register, so you can rebuild the version your board runs; shipped SMM code is usually closed. Openness only helps if the vendor publishes the version and patches it, which is where the ROM and bootloader supply chain becomes the real question.
Common mistakes
- Assuming QEMU's bundled OpenSBI is the one you built. Without
-bios, QEMU uses its packaged firmware. Always pass-bioswith your own build when you test a change, and check the banner. - Building OpenSBI with a bare metal toolchain. The README says
riscv64-unknown-elf-gcccannot build its position independent images. Useriscv64-linux-gnu-gccor Clang. - Forgetting reserved memory. If the device tree or UEFI memory map does not mark firmware memory and PMP protected regions as reserved, the kernel will fault when it touches them. Custom device trees for new boards often get this wrong.
- Treating a lab key as secure boot, or
fw_jumpas verification. A key on the QEMU command line is not a root of trust, andfw_jumpjumps into whatever sits atFW_JUMP_ADDR. Something ROM verified must check each stage. - Supplying a device tree that does not match QEMU's machine. QEMU requires a supplied device tree to match
-smpand-m, and to have a CLINT node with compatible stringriscv,clint0when used with OpenSBI. A mismatch shows up as harts that never start or memory the kernel cannot see. - Ignoring firmware in the patch plan. OpenSBI, U-Boot SPL and EDK II all receive fixes. If your patch process stops at the kernel and the root file system, your M-mode firmware may be years behind.
FAQ
What is the difference between SBI and OpenSBI?
The SBI is a specification from RISC-V International that defines how S-mode software calls M-mode firmware, or how a guest calls a hypervisor. OpenSBI is one open source implementation of that specification for M-mode firmware. Other implementations include RustSBI, the Berkeley Boot Loader, KVM, Xen and several more listed in the specification.
What is the latest SBI specification version?
Version 3.0, tagged "Release 3.0 (Ratified)" in the riscv-non-isa/riscv-sbi-doc repository on 16 July 2025. It added supervisor software events, firmware features, debug triggers and the message proxy extension. Check the repository's releases for anything newer.
What is the latest OpenSBI release?
OpenSBI v1.9, released on 1 July 2026 according to the project's GitHub releases, after v1.8 (29 December 2025) and v1.8.1 (8 January 2026). The project has released roughly every six months.
Does RISC-V have a secure world like Arm TrustZone?
Not as a single architectural feature. M-mode is the most privileged level, and M-mode firmware can use PMP, Smepmp and OpenSBI domains to isolate memory and harts. Enclave frameworks such as Keystone build trusted execution on top of that. The Smmtt specification for supervisor domain isolation, aimed at confidential computing, was at v0.9.0 in August 2026 and is not yet ratified.
Does RISC-V support UEFI Secure Boot?
Yes, when the OS loader is UEFI firmware such as EDK II or U-Boot's UEFI implementation. UEFI runs in S-mode on top of the SBI firmware, and the Linux kernel's EFI stub boots from it. The Boot and Runtime Services specification, ratified in August 2025, sets out UEFI and ACPI requirements for OS boot on RISC-V.
How do I check which SBI firmware my RISC-V board is running?
Run dmesg | grep -i sbi on Linux. The kernel logs the SBI specification version it detected and the implementation ID and version. Implementation ID 0x1 is OpenSBI, and OpenSBI encodes its version as major shifted left 16 bits plus minor. The OpenSBI banner on the serial console also shows the firmware version and runtime SBI version.
Why does Linux on RISC-V need OpenSBI if U-Boot already loads it?
U-Boot loads the kernel and then gets out of the way. OpenSBI stays resident in M-mode and provides runtime services the S-mode kernel cannot do itself on many platforms: setting the machine timer, sending IPIs, remote TLB shootdowns, starting other harts and rebooting. Without an SBI implementation, an S-mode kernel cannot run on those platforms.
What is RVA23 and why does it matter for boot firmware?
RVA23 is a RISC-V profile, ratified in October 2024, that lists the extensions a 64 bit application processor must implement to run standard binary OS distributions. It makes vector and hypervisor support mandatory. Together with the Boot and Runtime Services and server platform specifications, it gives OS vendors a fixed target, which is what makes generic UEFI and ACPI based installers practical.
Where Safeguard fits
Safeguard does not analyse firmware binaries, sign boot images, manage device fleets or inspect what runs in M-mode on a board. The fit here is indirect. A RISC-V boot chain is built from open source: OpenSBI vendors part of libfdt, U-Boot pulls in its own libraries and host tools that link OpenSSL or GnuTLS, the build host runs a cross compiler, and the Linux kernel and root file system that sit on top carry thousands of packages. The repositories, build containers and signing helpers that produce that chain are ordinary software projects. Safeguard can scan those repositories, Dockerfiles and container images for known vulnerable components, record an SBOM for them, and evaluate policies and gates in CI, so the environment that builds and signs your boot images is held to the same standard as your application code.
Firmware updates move slowly, which makes the parts you control worth keeping current. The build containers, host tools, Python signing scripts and user space that ride along with a RISC-V image are open source dependencies you can patch on your own schedule, even when the SoC vendor's boot ROM and first stage loader can only be fixed by the vendor.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo is a real Safeguard CLI session in a repository: it reads a vulnerability finding and the advisory, asks before each command, edits the dependency, runs the install and tests with your approval and pushes nothing. The same flow fits the tooling repository behind a RISC-V image, for example a Python signing helper or the Dockerfile that hosts your cross compiler and mkimage.
Click through it at your own pace, or open it full screen.
The second demo sets up the Safeguard runner on your own machine, approves it with a device code and scans from the terminal. Firmware build hosts often stay off shared CI on purpose, and a local runner lets you scan the build tree where it already lives.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. A firmware or platform engineer can then ask about the dependencies in a board support repository from the assistant they already use, without granting it more access than they choose.
Click through it at your own pace, or open it full screen.
Download the apps at https://safeguard.sh/download and read the CLI documentation at https://docs.safeguard.sh/docs/cli .
Quick check
Which registers carry the SBI extension ID and function ID, and where does the error code come back?
The extension ID goes in a7 and the function ID in a6. Arguments use a0 to a5. The SBI implementation returns an error code in a0 and a value in a1, and must preserve every other register.
In the recommended QEMU and U-Boot flow, which stage loads OpenSBI, and in which mode does U-Boot proper run?
U-Boot SPL, running in M-mode, loads a FIT image holding OpenSBI fw_dynamic and U-Boot proper. OpenSBI then starts U-Boot proper in S-mode, and stays resident in M-mode to serve SBI calls.
Sources
- RISC-V SBI specification repository and releases (v3.0 ratified)
- SBI v3.0: Introduction
- SBI v3.0: Binary Encoding
- SBI v3.0: Base Extension and implementation IDs
- SBI v3.0: Hart State Management Extension
- SBI v3.0: System Reset Extension
- SBI v3.0: Change Log
- OpenSBI repository README
- OpenSBI releases
- OpenSBI Platform Firmwares
- OpenSBI FW_DYNAMIC
- OpenSBI FW_JUMP
- OpenSBI FW_PAYLOAD
- OpenSBI Domain Support
- OpenSBI QEMU RISC-V Virt Machine Platform
- OpenSBI source: sbi_init.c boot banner
- OpenSBI source: sbi_version.h
- OpenSBI source: generic platform objects.mk
- RISC-V ISA manual repository and releases (privileged architecture)
- Privileged architecture: Introduction and privilege levels
- Privileged architecture: Machine-level ISA and PMP
- Privileged architecture: Hypervisor extension
- Privileged architecture: Smepmp
- Privileged architecture: Sstc
- RISC-V International: ratified specifications
- RISC-V International: RVA23 ratification announcement (21 October 2024)
- RISC-V profiles repository releases
- RISC-V Boot and Runtime Services (BRS) releases
- BRS: Recipes
- BRS: SBI Requirements
- RISC-V server platform specification releases
- RISC-V Smmtt specification repository
- Smmtt releases
- Linux kernel: RISC-V Kernel Boot Requirements and Constraints
- Linux kernel: ACPI on RISC-V
- Linux kernel source: arch/riscv/kernel/sbi.c
- U-Boot: RISC-V architecture documentation
- U-Boot: QEMU RISC-V
- U-Boot: FIT Signature Verification
- QEMU: 'virt' Generic Virtual Platform (RISC-V)
- Keystone Enclave project
- Keystone documentation
- Keystone documentation: Keystone Basics
Last reviewed: 24 October 2026. SBI, OpenSBI and RISC-V platform specifications change with each release; check the linked repositories for the version your firmware is built from.