Raspberry Pi 5
Relevant source files
- kernel/platform/rpi5/config/config.txt
- kernel/linker-aarch64.ld
- kernel/src/arch/aarch64/platform/rpi5/mod.rs
- kernel/src/arch/aarch64/platform/rpi5/memory_map.rs
- kernel/src/arch/aarch64/platform/rpi5/uart.rs
- kernel/src/arch/aarch64/platform/rpi5/control_link.rs
- kernel/src/bench.rs
- kernel/src/driver/ram.rs
- kernel/Cargo.toml
- scripts/build/rpi5.sh
- scripts/deploy/rpi5.sh
- docs/decisions/0003-supported-targets.md
The Raspberry Pi 5 (BCM2712 SoC plus the RP1 southbridge) is axiomOS’s primary hardware target. ADR-0003 classifies it as Supported after HIL: it is not considered supported until physical boot, GPIO IRQ, control-link, timer, storage and failure-state hardware-in-the-loop evidence exists.
The README describes the project as “a research kernel under active hardware bring-up on Raspberry Pi 5. Not production-ready.” Historical Pi latency and boot-time numbers are archived until they are re-run with retained raw logs and artifact hashes.
Build and deploy
The kernel is built for aarch64-unknown-none with the embedded-rpi5 feature (which enables embedded-profile and rpi5).
cargo xtask build rpi5 -- release embedded-rpi5
cargo xtask deploy rpi5 --dry-run -- /path/to/mounted/pi-boot
cargo xtask deploy rpi5 -- /path/to/mounted/pi-bootThe build embeds a 32-byte Ed25519 public key (AXIOM_BPF_TRUSTED_KEY_PATH) as the BPF trust root and writes rpi5-artifacts.sha256 covering the ELF, kernel8.img, the root filesystem and the key. deploy verifies the hashes before copying kernel8.img and the provenance manifest to the SD card boot partition. The repository does not fetch or pin the Raspberry Pi boot firmware itself; the deploy script says release and HIL evidence must record its exact revision and hashes.
Separate instrumented images exist and are not meant for production: the verifier-cost, bench and bringup-diagnostics features in kernel/Cargo.toml are off by default.
Boot configuration
config.txt is copied to the boot partition:
| Setting | Purpose (from the file’s comments) |
|---|---|
arm_64bit=1 | 64-bit kernel |
kernel=kernel8.img | Pi 5 loads kernel8.img for 64-bit kernels |
pciex4_reset=0 | Keep the RP1 southbridge in its firmware-initialized state; without it RP1 peripherals (UART, GPIO) are not accessible |
enable_rp1_uart=1 | Pre-configure RP1 UART0 at 115200 8N1 |
enable_uart=1, uart_2ndstage=1 | UART output and early boot UART |
dtoverlay=disable-bt | Bluetooth otherwise uses the UART pins |
disable_splash=1 | Skip the rainbow splash |
gpu_mem=16 | Minimum GPU memory; the kernel does not use the GPU |
The file describes pciex4_reset=0 and enable_rp1_uart=1 as “firmware shortcuts” that exist because the kernel has no full PCIe driver. The kernel relies on the firmware having trained the PCIe link to RP1 and mapped RP1 at a fixed physical window.
Boot flow
Firmware to _start_asm
The firmware loads kernel8.img at physical 0x0008_0000 (the link address in linker-aarch64.ld) and jumps to _start_asm with the DTB address in x0. Core 0 continues, other cores are parked, EL2 is dropped to EL1, .bss is cleared, and VBAR_EL1 is set. See AArch64.
Rust _start and platform init
_start stores the DTB address, calls rpi5::init() (which is intentionally side-effect free: the debug UART is lazily initialized on the first log write), then parses the DTB for memory regions (Device Tree).
kernel::init
Architecture init (exception vectors, MMU, GICv2, timer at 100 Hz, syscall), BPF manager, VFS, IIO, scheduler, and then an embedded RAM disk registered as block device 0. The root filesystem is an image compiled into the kernel (include_bytes! of EMBEDDED_DISK_PATH) and copied to the heap, not read from the SD card or NVMe. No Pi 5 storage driver exists in the reviewed code.
Root mount, init, control link
main mounts the ext2 root, starts /bin/init, then calls control_link::spawn() to start the Shrike UART poller task.
Console
The kernel console is the BCM2712 PL011 UART10 at physical 0x10_7D00_1000, the board’s dedicated debug connector, which is what the official Raspberry Pi Debug Probe attaches to. Rp1Uart in uart.rs (despite its name) points at UART10 and deliberately does not reprogram the baud or line control, relying on the firmware’s setup.
Note on the config file: its trailing comments describe a USB-TTL adapter on GPIO14/15 for a serial console. In the current kernel, GPIO14/15 (RP1 UART0) is instead the Shrike control-link UART, so the debug-connector UART10 is the console. The config.txt comment text appears to predate that split.
Early bring-up code also writes single-character markers directly to UART10 (for example {, |, } in boot.S); in Rust these are gated behind the bringup-diagnostics feature.
Memory map used by the kernel
From memory_map.rs:
| Region | Physical address |
|---|---|
| DRAM base / kernel load | 0x0 / 0x8_0000 |
| UART10 (debug console) | 0x10_7D00_1000 |
| GIC-400 distributor / CPU interface | 0x10_7FFF_9000 / 0x10_7FFF_A000 |
| RP1 peripheral window (PCIe BAR1) | 0x1F_0000_0000 |
RP1 peripheral offsets are listed on the RP1 page.
What the code supports on hardware
| Capability | State according to the source |
|---|---|
| Boot to scheduler on core 0 | Implemented; single core (secondary cores parked) |
| Timer tick (100 Hz generic timer) and preemption | Implemented; HIL timer evidence is a required but separately tracked item |
| Debug console (UART10) | Implemented |
| GPIO input/output, edge interrupts | Pin control implemented for 28 user pins via RP1 IO_BANK0; the GPIO interrupt handler is wired to GIC ID 261, but the kernel does not configure the RP1 or PCIe side of that path |
| PWM (RP1 PWM0/PWM1) | Implemented; assumes a 125 MHz input clock and does not enable an RP1 PWM clock |
| Shrike control link over RP1 UART0 (GPIO14/15) | Implemented as a polled transport; IRQ-driven RX is deferred |
| I2C, SPI, CAN, Ethernet | Not implemented (README: only GPIO, PWM, UART on RP1) |
| SD/NVMe/USB storage | Not implemented; root filesystem is an embedded RAM disk |
| Secondary cores | Not brought up in the reviewed code |
| Hardware watchdog | Not integrated (README, issue 72); a software watchdog hook triggers the e-stop path |
Bench instrumentation
From bench.rs (BCM GPIO numbering):
| Signal | GPIO | Notes |
|---|---|---|
| Sensor trigger | 23 | Reflex fires on rising edge |
| E-stop button | 24 | External 10k pull-up to 3V3; pressing pulls the pin to GND (falling edge) |
| PWM output | 12 | PWM0 channel 1 (Alt0), as numbered by the actuation monitor |
The bench feature is off by default. The repository’s CI has no hardware-in-loop job: README states Pi 5 testing is manual (issue 76).