02. Understanding the Raspberry Pi Boot Process¶
How the Raspberry Pi 4B Boots¶
Unlike traditional PCs, the Raspberry Pi has a unique boot sequence:
- Boot ROM: The SoC's internal boot ROM initializes and looks for bootable media
- Start4.elf: The GPU loads the firmware
start4.elffrom the SD card - Kernel Load: The GPU reads
config.txtand loadskernel8.imgat address0x80000 - CPU Handoff: The GPU releases core 0 of the ARM CPU, which jumps to
0x80000
Raspberry Pi 4 vs Earlier Models
- Pi 3 and earlier: Required
bootcode.binon the SD card - Pi 4: Has internal boot ROM, so
bootcode.binis not needed
Why kernel8.img?
kernel.img= ARMv6 (32-bit)kernel7.img= ARMv7 (32-bit)kernel8.img= ARMv8 (64-bit) ← We're using this
The Linker Script¶
The linker script (kernel/linker.ld) defines where code and data live in memory:
Key Points¶
- 0x80000: Entry point address (GPU loads kernel here)
- .text.boot: Our assembly entry code goes first
- __bss_start / __bss_end: Markers for zeroing uninitialized variables
- __stack_top: Stack grows downward from this address
Writing the Boot Code¶
File: kernel/boot.S
Code Explanation¶
Multi-Core Handling¶
The Raspberry Pi 4B has 4 cores. We only want core 0 to run; the others enter proc_hang.
Clearing BSS¶
The BSS section contains uninitialized global variables. We must zero them out before running C code.
Setting the Stack¶
The C code needs a stack. We point the stack pointer (sp) to our reserved 16KB region.
Testing the Build¶
You should see kernel8.img (around 1-2KB).
Deploying to the Raspberry Pi¶
Important: Raspberry Pi 4 Boot Requirements
The Raspberry Pi 4 has an internal boot ROM, so bootcode.bin is not required (unlike Pi 3 and earlier). However, bare-metal kernels require proper device tree files (DTB) and overlays to boot correctly.
Recommended Method: Using Raspberry Pi OS Boot Partition¶
The easiest and most reliable way to test your bare-metal kernel:
- Prepare an SD card with Raspberry Pi OS (using Raspberry Pi Imager)
- Mount the boot partition on your PC
- Backup the original kernel:
- Copy your kernel:
- Insert SD card into Raspberry Pi and power on
This method works because the Raspberry Pi OS boot partition already contains all required files:
start4.elf/fixup4.dat- GPU firmwarebcm2711-rpi-4-b.dtb- Device tree for Pi 4Boverlays/- Device tree overlaysconfig.txt- Boot configuration
To restore Raspberry Pi OS, simply rename kernel8.img.backup back to kernel8.img.
Alternative: Minimal Boot Partition (Advanced)¶
If you want to create a minimal boot partition from scratch:
-
Format SD Card as FAT32 (MBR, not GPT)
-
Download required files:
-
Create
config.txt:!!! warning "Mini UART Timing Requirements" The Raspberry Pi 4's Mini UART (UART1) baud rate depends on the GPU core frequency. Dynamic frequency scaling causes timing issues, making serial output garbled or unreadable.
1 2 3 4
- **`initial_turbo=0`**: Disables initial CPU turbo mode which affects UART timing - **`core_freq_min=500`**: Locks minimum GPU core frequency to 500MHz Without these settings, you may see **garbled characters** or **no UART output** even if your code is correct. This is especially critical when using USB-to-TTL serial adapters for debugging.The
disable_overscan=1setting is important for framebuffer graphics to work correctly with the requested resolution. -
Copy all files to SD card:
-
Power on
Configuring Screen Resolution (config.txt)¶
If you are using a display and want to set a specific resolution (e.g., for the framebuffer driver later), you can add HDMI settings to config.txt.
Example: Force 1920x1080 (Full HD)
Common hdmi_mode values (for hdmi_group=2):
- 82: 1920x1080
- 85: 1280x720
- 16: 1024x768
- 9: 800x600
Troubleshooting: Black Screen
If your kernel boots but the screen remains black (and you are sure your code is correct), it might be a resolution mismatch.
1. Try adding disable_overscan=1 to config.txt.
2. Ensure framebuffer_init() in your code matches the resolution in config.txt (if set).
3. If using a specific hdmi_mode, ensure your monitor supports it.
Debugging Tip
If you see a rainbow screen that stays forever, the GPU firmware loaded but your kernel failed to start. Check that all required files are present and that kernel8.img is a valid AArch64 binary.
At this point, the Raspberry Pi will boot your kernel, but you won't see any output yet since we haven't implemented UART communication.
Next Steps¶
In the next article, we'll implement the UART driver and print "Hello World" to see our kernel actually running!