01. Environment Setup for Raspberry Pi OS Development¶
This series builds a small bare-metal ARM64 operating system, not a modified Raspberry Pi OS Linux installation. The primary target is Raspberry Pi 4 Model B with BCM2711 and Cortex-A72. Raspberry Pi 5 uses a different SoC, interrupt controller, peripheral map, and default kernel filename, so do not assume Pi 4 code will run unchanged.
What you need
Use a development computer, a spare microSD card, a Raspberry Pi 4, a 3.3V USB-to-TTL serial adapter, and a reliable power supply. Keep your normal Raspberry Pi OS card separate from the experimental card.
Choose a Bare-Metal Compiler¶
The preferred compiler prefix is aarch64-none-elf-, which explicitly targets freestanding AArch64 firmware. Arm publishes current builds on its GNU Toolchain downloads page.
aarch64-linux-gnu-gcc can also compile the early examples when every hosted runtime dependency is disabled, but it targets a Linux ABI by default. The two toolchains must not be mixed in one build directory.
Verify that all tools come from the expected prefix:
Create the Project Layout¶
Create a clean build directory whenever you change compilers:
CMake Toolchain File¶
Use the environment variable so the same repository works with either compiler prefix:
CMAKE_TRY_COMPILE_TARGET_TYPE prevents CMake from trying to execute an ARM test program on the development computer.
Minimal Build Definition¶
Your main CMakeLists.txt should enable C and assembly, link with the custom script, and convert the ELF into the raw image expected by Pi 4 firmware:
Validate Before Copying to the SD Card¶
A successful compiler exit does not prove the image is usable. Inspect architecture, entry point, sections, unresolved symbols, and raw image size:
Expected checks:
- Machine is
AArch64. - The entry point matches the linker script and
_startsymbol. nm -uprints no unexpected runtime symbols such asmemcpy,__stack_chk_fail, or__libc_start_main.kernel8.imgis non-empty.
Deploy Without Overwriting Your Main System¶
Start with a Raspberry Pi OS boot partition because it already contains compatible firmware and device-tree files. Back it up, then replace only kernel8.img on the experimental card.
Add these settings to that card's config.txt:
Copy the image and flush pending writes:
Connect the serial adapter with GND to GND, adapter RX to Pi GPIO14/TXD, and adapter TX to Pi GPIO15/RXD. Never connect a 5V serial signal to Raspberry Pi GPIO.
Reproducible Build Measurements¶
Record tool versions and build time before comparing optimisations:
These are host build measurements, not Raspberry Pi runtime benchmarks. Later articles add UART timestamps and the system timer for on-device measurements.
Common Failures¶
CMake says the compiler cannot build a test program¶
Confirm CMAKE_SYSTEM_NAME Generic and CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY, then delete the cached build/ directory before configuring again.
Linker reports __stack_chk_fail or PIE relocations¶
Ensure -fno-stack-protector, -fno-pie, -nostdlib, and -nostartfiles are active in the verbose command. Some Linux-targeting distributions enable hardening flags by default.
The Pi shows no UART output¶
Check the serial adapter is 3.3V, RX and TX are crossed, the baud rate matches, enable_uart=1 is present, and the boot code initialises the correct UART. Confirm that the activity LED pattern does not indicate a missing kernel file.
The image works on Pi 4 but not Pi 5¶
That is expected for this series. Pi 5 normally boots kernel_2712.img and has RP1-connected peripherals. Port the boot code and drivers deliberately instead of merely renaming the image.
FAQ¶
Why not use the normal host gcc?¶
It emits code for the development computer, usually x86-64. A cross-compiler emits AArch64 instructions and provides matching assembler, linker, objcopy, and inspection tools.
Is -mcpu=cortex-a72+nosimd required?¶
No. Start with -mcpu=cortex-a72. Disable floating-point and SIMD usage only when the kernel has not yet saved the relevant processor state or your coding rules require it.
Can QEMU replace physical hardware?¶
QEMU is useful for CPU-level experiments, but it does not accurately reproduce all Raspberry Pi 4 firmware and peripherals. UART output on a real Pi remains the reference test for this series.
Next Steps¶
- Continue to Understanding the Raspberry Pi Boot Process.
- Then build UART Hello World.
- Use the ARM64 Assembly introduction for instruction-level background.