Baleen

A static-partitioning separation kernel for AArch64/EL2, built so that its claims can be checked rather than believed.

View the Project on GitHub via-balaena/baleen

Baleen roadmap — from a proven model to a “slim Qubes”

The model is done (docs/TIER-B/C/D): hv-core is proven ∀-N, both directions of non-interference — a domain cannot be affected by (integrity) nor learn from (confidentiality) another except through authorized channels. This doc is the path from that proven model to a real, running system you can use. It is written to the same discipline the proofs were: babystep every layer, diamond it, audit it, never skip ahead, and mark honestly where the word “verified” applies and where it stops.

The target: a greenfield “slim Qubes” — and why not Xen-compat

The capstone is not a Xen-compatible hypervisor and Qubes is not a dependency. The Xen personality (baleen-xenabi) is dropped. Matching Xen’s 20-year organic ABI bug-for-bug would be the single most expensive path, would drag Xen’s unproven semantics onto our clean core (killing the proof’s value at the emulation boundary), and would leave us subordinate to two upstreams forever. Qubes is an architecture — a set of security patterns — not code we must run.

So we build those patterns fresh on the proven core, using hardware virtualization + virtio: unmodified guests (Linux) think they are on generic virtual hardware and use the virtio drivers they already ship. No guest needs to know Baleen exists; no Xen ABI is implemented. The small proven hv-core stays the trusted computing base, and every layer above is designed against our own clean HvCall ABI so the proof’s guarantees flow all the way up.

“Slim Qubes” is scoped to the disposable-and-vault workflow — the part of Qubes that Baleen proves most directly, done better:

The method (non-negotiable — the same discipline as A→D)

The tiers A→D worked because of a rhythm, not heroics. It carries over verbatim to the build:

  1. Babystep. One layer per arc. A layer is not started until the one below is green and audited. Never skip ahead — the temptation to “just get a guest booting” before the metal seam is diamonded is exactly how unproven assumptions get load-bearing.
  2. Spike first, measure, then scale. Prove one thin vertical slice of a layer end-to-end before building it out — the Kani-bridge / enumerator-bridge move. Surface the cost before committing.
  3. Diamond each layer. Each layer states its own invariants and gets held to them: a property to preserve, a check that it holds, and — where the layer touches isolation — a model + proof in hv-core before the code that relies on it. (Phases that extend isolation, e.g. DMA and GPU-memory, loop back to hv-core + Verus, not just implementation.)
  4. Architecture audit between every layer. The design-lesson #17 move — try to break the new layer’s isolation on paper, against every layer below, before moving on. A clean audit is a valid result and the confidence artifact; a found gap is cheaper here than three layers later.
  5. Mark the verified scope, per layer, honestly. Every layer is one of: extends the proof (new hv-core invariant + Verus proof), refines the proof (implementation shown to realize the model, validated functionally — see docs/QEMU-AND-METAL.md), or unverified plumbing (no isolation content; say so plainly). The word “verified” applies to the first two only, and the ledger at the bottom of this doc tracks which is which.

The phases

Each phase lists its see-it moment (the working demo), the new work, the diamond + audit checkpoint, and honest flags (does it extend or only refine the proof; does it need real hardware; platform tension).

M3 — Metal bring-up: “it’s alive”

M4 — First native guest: the proof touches reality

M5 — Disposables + vault: the isolation thesis, live

M6 — Trusted input/GUI domain: a usable desktop

M7 — Data-device attach + IOMMU: the DMA story

M8 — GPU acceleration: near-bare-metal disposables (the big pillar)

Capstone — “slim Qubes”

The assembled system: GPU-accelerated near-bare-metal disposables, an offline vault, direct data-device attach, and a trusted input/GUI domain — greenfield, virtio, no Xen, on the proven hv-core. The parts of Qubes you actually use, on a provable core, with the GPU story Qubes lacks.

Near-term execution — the first arcs (M3 → M4)

The phases above are the shape; this is the concrete arc-by-arc sequence to start, each an arc in the same commit → diamond → audit → CI-green rhythm the model was built with. Each arc is one PR.

Arc 0 — the metal dev + test loop (the enabling move — do this first)

Stand up the loop before any hypervisor logic, so every later metal arc lands with the same discipline: a hv-metal crate (a standalone crate, excluded from the workspace like hv-fuzz, and the only crate that overrides the unsafe_code = "forbid" fence — in its own manifest), an aarch64-unknown-none-softfloat bare-metal target with a minimal linker script and an assembly entry, a cargo xtask qemu launcher (qemu-system-aarch64 -M virt,virtualization=on -cpu max -nographic), and a headless QEMU boot-test in CI (boot, assert a serial marker, kill on timeout) so “diamond → CI-green → merge” stays alive on the metal side. See-it: the binary boots on the emulated CPU and prints a marker, testable in CI. Why first: without the green-CI ratchet, metal work loses the rhythm that made the model work.

M3 — metal bring-up

M4 — first guest + the bridge (the proof touches reality)

After Arc 5, M5 (control domain + virtio-blk/console + disposable-from-template + a no-net vault) is where it stops being a demo and becomes a system — and it mostly cashes in the lifecycle and non-interference proofs, so it should move fast.

Two honest notes on the phase change: (1) iteration slows — QEMU boot cycles are seconds, not the instant enumerator; the Arc-0 CI boot-test is what keeps that from eroding discipline. (2) This is the first unsafe (MMIO, page-table writes, system-register pokes); the fence audit (#1) exists precisely to keep that surface minimal and justified — the same “name exactly what’s trusted” move as the proofs.

The two hard pillars (called out, because they carry the risk)

Platform reality (name the fork)

The Apple-Silicon dev machine is ideal for M3–M6 (isolation, disposables, vault, input/GUI, near-metal CPU/RAM) — same-architecture, no cross-emulation, fast loop. M7’s SMMU substrate turned out to develop here too (QEMU emulates a stage-2 SMMUv3; see the M7 section). But M8 (accelerated GPU), and M7’s controller passthrough on silicon, pull toward x86 hardware with a standard open GPU, the same territory Qubes lives in — because Apple gates EL2 and Apple’s GPU has no passthrough/virtualization path a hypervisor can use. So: build and demo the thesis on ARM through M6; expect a real-hardware, likely x86, phase for the two hard pillars. hv-core doesn’t change across the fork (that is the whole point of the hv-hal fence); only the metal layer does.

The honesty ledger — what “verified” covers, per layer

layer relation to the proof needs real HW?
hv-core (M0) proven ∀-N, both non-interference directions — (it’s the model)
M3 HAL / metal refines — TimeSource realized+honored (ARM); GuestMemory/VcpuOps deferred, assumptions named (Audit #1, docs/AUDIT-1-HAL-FENCE.md) no (QEMU-sound)
M4 Stage-2 gen refines — real p2m→Stage-2 emitted + negative-isolation test PASSED; GuestMemory realized+honored (ARM); Audit #2 SOUND (docs/AUDIT-2-P2M-STAGE2.md) no (QEMU-sound)
M5 disposables + vault refines (lifecycle + non-interference cashed in) no (QEMU-sound)
M6 input/GUI domain extends (focus-integrity) + plumbing no
M7 DMA / IOMMU extends; rungs 1–3 = SMMU default-deny then translation — a device bound to a domain’s own Stage-2 tables, boot-witnessed, with ∀-StreamID Kani over the stream-table builder and ∀-binding Kani over the stream→domain binding (docs/SMMU-STREAM-TABLE.md, docs/SMMU-TRANSLATION.md). A hv-core DMA-isolation model is still absent no for the configuration logic; yes for silicon
M8 GPU memory extends (GPU-memory non-interference) + big trusted driver yes

Two standing caveats carry through every layer: the proofs cover the model, and the metal enforces it only insofar as each layer refines or extends it as marked (docs/QEMU-AND-METAL.md draws the emulation-vs-metal line); and the timing/side-channel surface (caches, contention) is outside both the model and QEMU — an M7/M8-and-beyond concern that needs new design (constant-time discipline, SMMU config), not just testing.

✅ EL2 MMU bring-up — the named real-hardware prerequisite, now BUILT (ledger 5, rungs A1 + A2). Through M4 the hypervisor ran with its own stage-1 MMU off (SCTLR_EL2.M=0), so on real silicon its data accesses were Device-nGnRnE — which made its atomics UNPREDICTABLE (livelock) and left its caches unmanaged. Invisible under QEMU/TCG, so it was named-and-deferred rather than fixed inline, on the grounds that its payoff could only be validated on real EL2 silicon.

A1 (#156) gave EL2 an identity mapping with SCTLR_EL2.M, W^X on its own image, and MMU-off attributes deliberately preserved. A2 maps EL2’s DRAM Normal Write-Back Inner Shareable and sets SCTLR_EL2.C, which closes both consequences at once: the atomics hazard is gone by construction (exclusives are UNPREDICTABLE because the memory is Device, and it no longer is), and the cache hazard is gone by explicit maintenance plus one repair — VTCR_EL2 = 0x8002_3559 had the stage-2 walker fetching Write-Back Inner-Shareable from EL2’s own .bss while EL2’s stores were Device, a live mismatch A2 removes.

⚠ Two terms of the original plan were not built, both deliberately. SCTLR_EL2.I stays 0 (EL2 copies no guest code, so an I-cache buys nothing and the binary keeps zero ic instructions), and boot-time cache invalidation is a loader contract rather than this rung’s, since the right instruction differs by region. ⚠ And the deferral’s own premise survives: hv-metal has never run on the FVP or on silicon, so A2’s call sites are witnessed by nothing this repository owns — the mechanisms are graded by fvp-probe (m3/m4, m6). See docs/ARC-4-TRAP-AND-SERVICE.md, “Real-hardware readiness”, for the per-consequence accounting.

One-line summary

Build a greenfield, virtio-based slim Qubes — GPU-accelerated near-metal disposables, a vault, direct device attach, a trusted input/GUI domain — on the proven hv-core, one diamonded and audited layer at a time, never skipping ahead, marking honestly at each layer whether “verified” still applies. Xen is not a dependency; the proof is the foundation.