30K lines of no_std Rust: a bare-metal ARM64 hypervisor that replaces Google's Hafnium SPMC
⚓ Rust 📅 2026-04-09 👤 surdeus 👁️ 6I built a bare-metal Type-1 hypervisor at ARM's S-EL2 (Secure EL2) in no_std Rust. It replaces Hafnium — Google's 200K+ line C reference implementation — as the Secure Partition Manager Core, and runs alongside Android pKVM on the same chip.
What it does
- Boots Linux 6.12 to a BusyBox shell (4 vCPUs, virtio-blk)
- Manages 3 Secure Partitions at S-EL1
- Full FF-A v1.1: messaging, memory sharing, ownership transfer, notifications
- Coexists with pKVM (NS-EL2) on 4 physical CPUs
- 35/35 E2E tests through real TF-A firmware + pKVM
- 230KB release binary
Rust-specific things I learned
no_std is surprisingly viable at EL2. One dependency (fdt for DTB parsing). alloc crate with a bump allocator gives you Box/Vec. Enum dispatch replaces trait objects for zero-cost MMIO routing — no vtables, the compiler monomorphizes everything.
SP lifecycle as an enum is a game-changer. The state machine (Reset→Idle→Running→Blocked→Preempted) has ~15 valid transitions. Adding Blocked→Preempted for chain preemption, match forced me to handle every case. Caught two bugs at compile time. In C this would have been an int and asserts scattered across files.
Debug-mode codegen will bite you below the OS. read_volatile compiles to NEON SIMD (cnt v0.8b) in debug mode for alignment checks. ARM's EL3 firmware traps all FP/SIMD by default. Silent hang, no fault, no output. Hours of GDB. Fix: one TF-A build flag. Lesson: start with opt-level = 1 from day one for bare-metal.
No unwrap() in the entire codebase. Everything is ? or pattern matching. When you're running at EL2 there's no panic handler that helps — you just hang. Rust's error propagation makes this natural rather than painful.
Quick start
git clone https://github.com/willamhou/hypervisor
cd hypervisor
make run # 34 test suites, ~5 seconds on QEMU
make run-linux # boots Linux to shell
For pKVM integration, you need TF-A + AOSP kernel (both build via Docker, ~30min first time).
Links
- Blog post with war stories: Two Hypervisors, One SoC: Replacing Hafnium with 30K Lines of Rust | Hypervisor — ARM64 Type-1 in Rust
- GitHub: GitHub - willamhou/hypervisor: ARM64 Type-1 bare-metal hypervisor in Rust (no_std) — boots Linux at EL1, FF-A v1.1 SPMC at S-EL2, pKVM integration · GitHub
- dev.to: Two Hypervisors, One SoC: Replacing Hafnium with 30K Lines of Rust - DEV Community
Happy to answer questions about no_std bare-metal, ARM security architecture, or the FF-A protocol.
1 post - 1 participant
🏷️ Rust_feed