Skip to Content
Viewing release/v0.5.0-alpha.3 docs — not the stable branch. Changes vs main · Go to main

Raspberry Pi 5

Relevant source files

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-boot

The 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:

SettingPurpose (from the file’s comments)
arm_64bit=164-bit kernel
kernel=kernel8.imgPi 5 loads kernel8.img for 64-bit kernels
pciex4_reset=0Keep the RP1 southbridge in its firmware-initialized state; without it RP1 peripherals (UART, GPIO) are not accessible
enable_rp1_uart=1Pre-configure RP1 UART0 at 115200 8N1
enable_uart=1, uart_2ndstage=1UART output and early boot UART
dtoverlay=disable-btBluetooth otherwise uses the UART pins
disable_splash=1Skip the rainbow splash
gpu_mem=16Minimum 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.

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:

RegionPhysical address
DRAM base / kernel load0x0 / 0x8_0000
UART10 (debug console)0x10_7D00_1000
GIC-400 distributor / CPU interface0x10_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

CapabilityState according to the source
Boot to scheduler on core 0Implemented; single core (secondary cores parked)
Timer tick (100 Hz generic timer) and preemptionImplemented; HIL timer evidence is a required but separately tracked item
Debug console (UART10)Implemented
GPIO input/output, edge interruptsPin 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, EthernetNot implemented (README: only GPIO, PWM, UART on RP1)
SD/NVMe/USB storageNot implemented; root filesystem is an embedded RAM disk
Secondary coresNot brought up in the reviewed code
Hardware watchdogNot integrated (README, issue 72); a software watchdog hook triggers the e-stop path

Bench instrumentation

From bench.rs (BCM GPIO numbering):

SignalGPIONotes
Sensor trigger23Reflex fires on rising edge
E-stop button24External 10k pull-up to 3V3; pressing pulls the pin to GND (falling edge)
PWM output12PWM0 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).

Last updated on