Bare-Metal Raspberry Pi 3B
Bare-metal AArch64 firmware for a Raspberry Pi 3B — custom boot, then AUX mini UART TX on GPIO 14 with no OS.
Highlights
- AArch64 boot stub that parks cores 1–3, sets up the stack, and zeroes .bss before calling main
- Custom linker script producing a kernel8.img that the GPU firmware loads at 0x80000
- AUX mini UART at 115200 8N1 on GPIO 14 (TXD1 / Alt5), driven through BCM2837 MMIO — no HAL, no libc
Overview
Starting from an SD card with only the Pi’s GPU firmware files, this project brings up a Raspberry Pi 3B without Linux. The boot stub reads MPIDR_EL1 so only core 0 continues, points the stack just below the 0x80000 load address, clears .bss, and jumps to C. main then enables the AUX mini UART, locks baud for 115200 at a 250 MHz core clock, puts GPIO 14 in Alt5 (TXD1), and loops transmitting a string over the wire.
Try the boot stub walkthrough and mini UART TX below — both follow the real boot.S and main.c from the repo.
Boot path
- GPU firmware on the FAT32 card (
bootcode.bin,start.elf,fixup.dat) plusconfig.txtwitharm_64bit=1,enable_uart=1, andcore_freq=250. kernel8.imglinked at0x80000and copied to the card withmake flash.- Core 0 alone runs
_start→ stack → BSS clear →main; cores 1–3 sit inWFE.
Mini UART
miniUartSetup enables the AUX mini UART, disables TX while baud and line control are programmed, sets GPIO 14’s GPFSEL1 field to Alt5 (TXD1), then enables transmit. Baud is locked with AUX_MU_BAUD = 270 and core_freq=250 in config.txt:
250 MHz / (8 × 271) ≈ 115,313 — about 0.1% off 115200.
miniUartPointer walks a char * until NUL and calls miniUartTransmit for each byte, waiting on AUX_MU_LSR bit 5 (TX empty) before writing AUX_MU_IO. main passes a local string into that helper and loops with a software delay. A host serial monitor (make monitor) reads the line at 115200 8N1 — Pi GPIO14 → adapter RX, shared GND.
Interactive bring-up
Walk the AArch64 boot stub from boot.S, then step the same AUX mini UART bring-up
main.c does — enable AUX, set baud, put GPIO 14 in Alt5, and transmit bytes.
Boot stub
GPU firmware loads kernel8.img at 0x80000. Core 0 parks the others,
sets the stack, clears .bss, and calls main.
Mini UART TX
Same MMIO as the firmware: enable AUX, program baud for 115200 at 250 MHz, set GPIO 14 to
Alt5 (TXD1), then push bytes into AUX_MU_IO when the TX FIFO is empty.
0x00000000 0x00000000 0x00000000 0x00000000