i-RISCV SBI Firmware
The i-RISCV SoC provides two M-mode boot-firmware paths that reach the exact same kernel image from the same device tree. The default path uses upstream OpenSBI, genuinely unmodified; the alternate path is this project’s own standalone SBI implementation. Which firmware runs is selected purely by the linux_boot Makefile target: check/image (and their 72 variants) use OpenSBI, check-sbi/image-sbi (and their 72 variants) the standalone SBI.
OpenSBI (default)
- A pinned, unmodified upstream OpenSBI release built with
PLATFORM=generic– recognized purely through OpenSBI’s own FDT drivers matching the SoC’s device tree nodes (serial@10000000,clint@2000000,plic0), with zero source customization - A tiny SoC-specific M-mode prestage programs the entropy-source FUSE bank and jumps directly into OpenSBI’s
fw_jumpentry point – still in M-mode, nomret - All standard boot setup (
medeleg/mideleg,menvcfg,mcounteren, PMP) is performed by OpenSBI itself, computed from the hart’s detected extensions – including trap-safe PMP probing on builds where PMP is disabled
Standalone SBI (alternate)
A from-scratch M-mode firmware implementing the modern SBI v2.0 extension set:
- Base (spec v2.0): spec/implementation ID and version,
PROBE_EXTENSION, and vendor/arch/imp IDs read directly from the hart’s own CSRs - TIME, IPI, RFENCE, HSM, SRST, DBCN – each a real handler, not a stub
- The full legacy (v0.1) extension set (
SET_TIMER, console get/putchar, IPIs, remote fences,SHUTDOWN) for pre-v2.0 guests - Unimplemented extensions are correctly reported absent by
PROBE_EXTENSIONand returnSBI_ERR_NOT_SUPPORTEDwhen called, so a probing guest kernel falls back cleanly
Real Cross-Hart Behavior
IPI/RFENCE/HSM genuinely reach harts other than the one servicing the ecall – the same code path serves 2-hart and 16-hart (SMP16) builds:
- IPI: decodes the real
hart_mask/hart_mask_baseoperand pair and raises a real CLINT MSIP against every targeted hart that HSM has genuinely released - RFENCE: every FID (
REMOTE_FENCE_I,REMOTE_SFENCE_VMA[_ASID],REMOTE_HFENCE_VVMA[_ASID],REMOTE_HFENCE_GVMA[_VMID]) is a synchronous cross-hart TLB shootdown – the calling hart fences itself, every other targeted hart is woken via a CLINT-MSIP request/ack handshake that blocks until its fence completes; address/ASID/VMID operands are passed straight through to real selective invalidation (see Tagged TLB) - HSM:
MAX_HARTS-sized per-hart state tables backing a secondary-hart park loop, soHART_START/HART_GET_STATUSoperate on real harts
Boot Setup Performed by the Firmware
- Trap delegation:
medeleg/midelegset for S-mode, including the five H-extension causes (ECALL-from-VS, guest-page-faults 20/21/23, virtual-instruction) so a VS-mode guest under KVM is serviced by its own hypervisor – both paths delegate all five menvcfgandmcounterenenabled so Sstc/Svpbmt/Zicbom/Zicboz andrdtimework from S-mode without trapping – the kernel’s early entropy initialization readsrdtimebefore any driver is up, so a missingmcounteren.TMbreaks every boot- PMP: at least one permissive entry configured before dropping to S-mode (mandatory – a present-but-unconfigured PMP denies all S/U access); the standalone SBI writes one unlocked NAPOT entry covering the whole 56-bit physical address space, runtime-skipped on
PMP_ENABLE=0builds; OpenSBI programs its own RX/RW split from the detected PMP count with trap-safe probing mseccfg’s Zkrsseed/useedbits enabled once at boot- Entropy-source FUSE bank programmed once at boot via shared code linked into both firmware paths (alongside the
mseccfgsetup) - The branch predictor needs no firmware action: transparent always-on hardware that clears its own BTB/PHT/RAS state on every privilege-domain crossing
How Linux Actually Uses It
A guest OS discovers what the firmware offers purely through PROBE_EXTENSION; for the kernels this project boots:
- Timer: the device tree advertises
"sstc", so S-mode writesstimecmpdirectly and the TIME extension’sSET_TIMERis never issued (implemented for spec completeness) - Console: bootargs select
earlycon=uart8250,mmio,.../console=ttyS0, so Linux’s in-tree 8250 driver binds to the real UART node – no SBI involvement in the active console path; DBCN and legacy console stay implemented for guests configured withearlycon=sbi/hvc0 - HSM/IPI/RFENCE: exercised by the kernel’s own SMP boot and TLB-shootdown code paths (see Linux)
- SRST: guest
reboot/poweroffissue SRST exactly as on real hardware
Standalone Firmware Validation
Before ever combining it with a kernel, the standalone firmware is validated in isolation by S-mode smoke tests linked to load where the kernel normally would (linux_boot/tools_scripts/run_sbi_smoke.sh {up,smp,dueling}): every implemented extension exercised via real ecalls on the single-hart build; a second real hart started and IPI/fenced on the 2-hart build; and a two-hart dueling-RFENCE regression test that reproduces (and proves fixed) a cross-hart fence deadlock in the non-reentrant M-mode trap context.
Disclosed Simplifications
Spec-legal, not silent:
HART_STOPparks the calling hart permanently rather than supporting a later re-HART_STARTof the same hart – Linux’s normal SMP boot never calls it (only CPU hotplug-remove does)- SRST reboot re-enters the firmware entry point with RAM untouched; no real board reset exists, so CSRs that only a hardware reset clears keep their values
- Legacy v0.1 remote calls take
hart_maskas a pointer treated as already physical – correct in practice because every Linux version booted here prefers the modern by-value IPI/RFENCE extensions and never reaches this path