The seL4 AArch64 QEMU Substrate Target
TopicFrom the PointSav Documentation
The unikernel images in this platform run on the seL4 microkernel targeting the AArch64
instruction set architecture, with QEMU's virt machine model as the primary
emulation environment for development, testing, and CI. This target was selected
through a set of architecture decisions (Group 3A and Group 3D) made in May 2026
and is the hardware foundation for all Phase 1C and Phase 2 work.
[edit]1. seL4 as the Microkernel Foundation
seL4 is a formally verified L4-family microkernel developed by CSIRO's Data61 and maintained by the seL4 Foundation. Its defining property is a machine-checked proof of functional correctness: the kernel implementation is proven to match a formal specification at the Isabelle/HOL level. This proof covers the AArch64 target.
seL4 uses a capability-based access control model. Every kernel resource β memory, threads, IPC endpoints, interrupt handlers β is accessible only through a capability, a typed unforgeable token held in a kernel-managed capability space. Sharing a resource means delegating a capability; revocation removes it. This model is the foundation on which the Capability Ledger Substrate is built: the ledger extends seL4's kernel-enforced access control with a cryptographically auditable record of every capability decision.
The substrate does not modify the seL4 kernel. It builds on the kernel's published API (libsel4) and the Microkit framework's protection-domain model.
[edit]2. AArch64 First
The AArch64 (ARMv8-A 64-bit) architecture was selected as the primary target for two reasons.
First, the proof portfolio. The seL4 formal proof covers AArch64 as a first-class target, alongside x86-64 and RISC-V 64. AArch64 has the longest track record of continuous proof maintenance in the seL4 project and is used in the seL4 foundation's own continuous-integration pipelines.
Second, the hardware trajectory. AArch64 server processors (Ampere Altra, AWS
Graviton, Neoverse N1/V1) are available in the cloud providers relevant to the
deployment targets. The QEMU virt machine model provides a faithful AArch64
emulation environment that maps directly to these physical targets.
x86-64 is not excluded β seL4 supports it β but AArch64-first means that the toolchain investment, build infrastructure, and test matrix are calibrated to AArch64 from the outset. x86-64 support, if needed, inherits from the same build pipeline.
[edit]3. The QEMU virt Machine Model
QEMU's virt machine model for AArch64 (-machine virt) is a synthetic platform
with no fixed hardware correspondence. It is designed specifically for software
development and emulation. Key characteristics relevant to seL4:
CPU: The default target is Cortex-A53 (-cpu cortex-a53), an ARMv8-A
implementation with hardware virtualisation extensions. seL4 on AArch64 runs at
Exception Level 1 (EL1) in non-virtualisation mode for the kernel, with user
processes at EL0.
Interrupt controller: GIC version 2 by default (QEMU_GIC_VERSION=2).
seL4's AArch64 port uses the ARM Generic Interrupt Controller; the QEMU virt
platform provides a software GIC compatible with the seL4 driver.
UART: PL011 serial controller at physical address 0x09000000. seL4's
KernelPrinting and KernelDebugBuild options route kernel debug output to this
UART, which QEMU maps to the emulator's standard output when -nographic is used.
Device tree: The seL4 CMake build system extracts the machine's device tree
binary from QEMU at configure time, then converts it to DTS and compiles it into
the kernel. This is why qemu-system-aarch64 must be present before the seL4 kernel
can be configured.
Physical memory: The QEMU virt device tree describes physical RAM from
0x40000000 to 0x80000000 β a 1 GiB window. QEMU must be launched with at least
-m 1G; booting with less allocates physical memory that does not cover the full
window described to the kernel, causing the elfloader to fail when placing images
within the expected range.
[edit]4. Kernel Build Configuration
The seL4 kernel is built from source at vendor-sel4-kernel/src/ using CMake with
a GCC cross-compile toolchain. The critical configuration options for the QEMU
AArch64 target are:
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc
-DCMAKE_ASM_COMPILER=aarch64-linux-gnu-gcc
-DCROSS_COMPILER_PREFIX=aarch64-linux-gnu-
-DKernelPlatform=qemu-arm-virt
-DKernelArch=arm
-DKernelSel4Arch=aarch64
-DKernelVerificationBuild=OFF
-DKernelPrinting=ON
-DKernelDebugBuild=ON
KernelVerificationBuild=OFF is required for KernelPrinting=ON to take effect.
When KernelVerificationBuild=ON, the CMake configuration silently disables
CONFIG_PRINTING β the CMake cache records KernelPrinting_DISABLED:INTERNAL=TRUE
without warning, and the kernel produces no serial output.
KernelPrinting=ON enables the kernel's serial output via the PL011 UART.
KernelDebugBuild=ON enables debug assertions and additional diagnostic output.
Both are appropriate for development and testing; a production image would use
CMAKE_BUILD_TYPE=Release without these options.
The build produces kernel.elf, a statically linked AArch64 ELF executable with
entry point 0xffffff8040000000 β the kernel's intended virtual address once the
AArch64 MMU is configured. As of Phase 1C.b (2026-05-27), this build succeeds from
the seL4 v15.0.0-dev source tree with aarch64-linux-gnu-gcc v13.3.0 on Ubuntu 24.04.
[edit]5. The Elfloader and the Boot Chain
The seL4 kernel ELF for AArch64 has a link-time entry point at virtual address
0xffffff8040000000. This is the kernel's intended virtual address once the AArch64
MMU is configured and the kernel's own page tables are in place. QEMU cannot load the
kernel ELF directly β it would attempt to place it at that virtual address in physical
memory, which does not exist on the virt machine.
The standard seL4 boot flow uses the elfloader, a small bootstrap program from
the seL4_tools repository (vendored at vendor-sel4-tools/elfloader-tool/). The
elfloader:
- Runs from physical address
0x40400000, where QEMU can load it directly. - Unpacks the seL4 kernel ELF from a CPIO archive embedded in the loader image.
- Configures the AArch64 MMU page tables to map the kernel's virtual address space.
- Unpacks the initial user-level thread (rootserver) from the same CPIO archive.
- Jumps to the kernel entry point, now reachable through the MMU mapping.
The combined image β elfloader binary with the kernel, device tree, and rootserver embedded as a CPIO archive β is what QEMU actually boots.
As of Phase 1C.d (moonshot-toolkit v0.3.0), this image is assembled automatically
by the moonshot-toolkit build command. The AssembleImage step compiles the elfloader
sources, generates the CPIO archive using a pure Rust writer, and links the combined
binary. No Python, CMake, or shell scripts are involved in the image assembly path.
[edit]6. Phase 1C Boot Chain β Verified
Phase 1C is complete. The full AArch64 boot chain from source to QEMU output has been demonstrated on the workspace VM.
Phase 1C.b (completed 2026-05-27): the seL4 kernel for QEMU AArch64 was built
from source. vendor-sel4-kernel/build/aarch64-qemu/kernel.elf is a valid AArch64
static ELF, entry point 0xffffff8040000000.
Phase 1C.c (completed 2026-05-28): full QEMU boot confirmed. A manually assembled elfloader image was loaded by QEMU, producing kernel output through the PL011 UART and handing off to a minimal rootserver.
Phase 1C.d (completed 2026-05-29): moonshot-toolkit v0.3.0 automates the full pipeline. The command:
cargo run -p moonshot-toolkit -- build moonshot-toolkit/examples/hello-world.toml
produces build/system-image.bin with entry point 0x40400000. Booting with:
qemu-system-aarch64 -machine virt,secure=off -cpu cortex-a53 \
-m 1G -nographic -kernel build/system-image.bin
produces:
ELF-loader started on CPU: ARM Ltd. Cortex-A53 r0p4
paddr=[40400000..40423fff]
Bootstrapping kernel
β¦
Booting all finished, dropped to user space
[edit]See Also
- moonshot-toolkit-build-orchestrator β the Rust build orchestrator that cross-compiles protection domains and assembles this target's boot image
- capability-ledger-substrate β what the unikernel images enforce at runtime