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_jump entry point – still in M-mode, no mret
  • 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_EXTENSION and return SBI_ERR_NOT_SUPPORTED when 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_base operand 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, so HART_START/HART_GET_STATUS operate on real harts

Boot Setup Performed by the Firmware

  • Trap delegation: medeleg/mideleg set 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
  • menvcfg and mcounteren enabled so Sstc/Svpbmt/Zicbom/Zicboz and rdtime work from S-mode without trapping – the kernel’s early entropy initialization reads rdtime before any driver is up, so a missing mcounteren.TM breaks 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=0 builds; OpenSBI programs its own RX/RW split from the detected PMP count with trap-safe probing
  • mseccfg’s Zkr sseed/useed bits enabled once at boot
  • Entropy-source FUSE bank programmed once at boot via shared code linked into both firmware paths (alongside the mseccfg setup)
  • 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 writes stimecmp directly and the TIME extension’s SET_TIMER is 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 with earlycon=sbi/hvc0
  • HSM/IPI/RFENCE: exercised by the kernel’s own SMP boot and TLB-shootdown code paths (see Linux)
  • SRST: guest reboot/poweroff issue 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_STOP parks the calling hart permanently rather than supporting a later re-HART_START of 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_mask as 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