Das U-Boot is a well-known bootloader which brings embedded Linux devices to life since 1999, it turns 25 this year.
My today's post walks through the complete U-Boot boot process, covering everything from SoC power-on to launching the Linux initrd
, along with hardware-specific gotchas.
The boot flow
[Power On]
↓
[SoC BootROM] → [SPL]
↓
[U-Boot Proper]
↓
[Loads kernel + dtb + initrd]
↓
[bootz / booti]
↓
[Linux Kernel starts]
↓
[initrd: /init runs]
↓
[Switch to rootfs]
🔌 1. Power-On: SoC BootROM
Every SoC contains a hardcoded BootROM:
- Executes right after power-on or reset
- Detects the boot source via boot pins
- Loads the Secondary Program Loader (SPL) from flash, SD, UART, or USB
- Minimal hardware is initialized here
📦 2. SPL (Secondary Program Loader)
SPL is a tiny version of U-Boot:
- Brings up DRAM and essential regulators
- Loads full U-Boot into RAM
- Operates within very constrained SRAM limits
💡 Hardware nuance: If DRAM init fails here, the system will hang silently. Always verify timing parameters for your DDR/LPDDR.
🚀 3. U-Boot Proper
Now the full U-Boot runs from RAM:
- Initializes serial console, eMMC/SD, network, USB, etc.
- Parses environment variables (
bootargs
,bootcmd
) - Loads:
- Linux kernel (
zImage
orImage
) - Device Tree Blob (
.dtb
) - initrd (
initramfs
)
- Linux kernel (
- Starts the boot using
bootz
orbooti
bootz ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
Regarding boot device order, modern U-Boot uses so-called "Distro Boot" framework:
-
bootcmd
runsdistro_bootcmd
-
distro_bootcmd
iterates overboot_targets
The distro_bootcmd
mechanism in U-Boot supports booting using configuration files like extlinux.conf
and scripts like boot.scr
:
-
extlinux.conf
: A configuration file that specifies kernel, initrd, and device tree paths, allowing for multiple boot entries and parameters. - boot.scr: a compiled script containing U-Boot commands, offering a way to automate complex boot sequences.
Looks for known boot files: extlinux.conf
, boot.scr
, boot.ini
, or standard kernel/initrd/fdt triplets. Usually there is '1st eMMC/SD - 1st USB - 1st NVMe' sequence of boot devices.
The setenv
command in U-Boot is used to define or override environment variables, which control nearly every aspect of how U-Boot boots your system.
🔧 Basic Syntax
setenv variable_name value
For example:
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rw"
To persist changes do saveenv
.
This writes changes to persistent storage (e.g., SPI NOR, eMMC, NAND, or a UBI volume). If you don't run saveenv
, any updates you may have made to the U-Boot environment will be lost on next system reboot.
💡 Use
printenv
andbdinfo
to check variables and layout. Be careful: U-Boot does not validate variable syntax, so typos can silently break boot! To recover from bad bootcmd or bootargs, use serial console and interrupt boot early (usually by pressing a key).
🐧 4. Linux Kernel Boot
The kernel is now in control:
- Unpacks itself into RAM
- Parses command-line and DTB
- Mounts
initrd
as the rootfs - Runs
/init
script from initrd
💡 If any addresses (kernel/initrd/fdt) overlap in RAM, the kernel may crash. Always double-check memory layout!
🐧 5. What Happens in initrd?
The initrd
:
- Loads drivers/modules
- Mounts the actual root filesystem (e.g.,
/dev/mmcblk0p2
) - May perform decryption, overlay setup, or network discovery
- Executes
switch_root
orpivot_root
to hand off to your real system (e.g.,systemd
)
⚙️ Hardware-Related Pitfalls
Some common embedded issues:
- DRAM doesn't initialize? Wrong timing in SPL.
- Kernel hangs early? Overlapping memory regions.
- Ethernet/MAC not working? Wrong or mismatched DTB.
- NAND boot fails? Missing ECC config in U-Boot.
- Secure boot halts execution? U-Boot binary not signed.
Sources:
- https://docs.u-boot.org/en/latest/
- https://samuel.dionne-riel.com/blog/2024/12/05/dtb-loading-is-harder-than-it-looks.html
- Xilinx Wiki: U-boot
- Microchip: Modifying Device Tree Overlays in U-Boot Prompt using 'fdt' utility
Todo: add more context; describe ARM related nuances...
Cover pic: Pixabay / Pexels