Bootloaders

The Complete Boot Process

Fundamentals explains why boot happens in stages, and U-Boot covers that one stage in detail. This page is the whole trip end to end — every stage in order, on one diagram — plus a practical, hands-on guide to environment variables: where they live, how to change them, and how to debug it when a board won't boot.

Quick reference
What it is
The full sequence from power-on to a running system: Boot ROM → SPL → U-Boot → Linux kernel → init → userspace.
Mental model
Each stage's only job is to load and verify a slightly bigger, more capable stage, then get out of the way.
Key numbers
7 stages, typically; the environment lives in its own flash partition, separate from the U-Boot binary itself.
Reach for it when
A board won't boot, or you need to change what/how it boots (a new kernel command line, a different root device, a recovery mode).

The full sequence, end to end

Seven boot stages in order: power-on, Boot ROM, SPL, U-Boot, Linux kernel, init, and the running system, each handing control to the next Power-on / Reset CPU starts executing at a fixed address Boot ROM Mask ROM, fixed at manufacture — reads boot-mode pins, loads the next stage SPL — Secondary Program Loader Initializes DRAM, loads the full bootloader into RAM U-Boot (full bootloader) Loads the environment, evaluates bootcmd, loads kernel + device tree Linux kernel Decompresses, initializes drivers, mounts root (or an initramfs first) Init / PID 1 systemd or BusyBox init — starts services, reaches a multi-user target Running system
Every stage's only responsibility is loading and handing off to the next one — see Fundamentals for why it's split this way instead of one program.

Environment variables, in depth

U-Boot's environment is a set of persistent key-value variables that control boot behavior — stored in its own flash region, separate from the U-Boot binary itself, so updating U-Boot doesn't wipe the board's configuration and vice versa.

Where it lives
A build-time U-Boot configuration choice (CONFIG_ENV_IS_IN_MMC, _SPI_FLASH, _NAND, ...) — the environment's physical storage location is fixed when U-Boot itself is compiled for a given board.
Default vs. saved
U-Boot ships with compiled-in default values; setenv changes only live in RAM until saveenv writes them to flash — the single most common "why didn't my change stick" gotcha.
bootcmd
The command sequence run automatically when the boot countdown isn't interrupted — usually a chain of "try this boot source, then that one, then fall back to network/recovery."
bootargs
The Linux kernel command line, passed at the kernel handoff — console=, root=, and anything else the kernel reads at /proc/cmdline.

Configuring the environment — a walkthrough

  1. Interrupt autoboot at the "Hit any key to stop autoboot" prompt to reach the interactive shell.
  2. Inspect the current state: printenv lists every variable currently set.
  3. Make a change, e.g. add a debug flag to the kernel command line: setenv bootargs "${bootargs} loglevel=8" — note the ${bootargs} reference, which extends the existing value instead of replacing it outright.
  4. Test it without committing: boot runs bootcmd immediately with the in-RAM changes, without touching flash.
  5. Once it's confirmed working, persist it: saveenv writes the environment to flash so it survives a power cycle.
  6. To undo a bad change, env default -a resets everything back to the compiled-in defaults (still requires saveenv to persist).

Boot scripts and extlinux.conf

Hand-editing environment variables doesn't scale well across a fleet of boards, so two higher-level mechanisms are common in real build systems (Yocto, Buildroot):

boot.scr
A compiled U-Boot script (source written as plain boot.cmd, compiled with mkimage) that U-Boot automatically looks for and runs from the boot device — a way to ship boot logic as a file alongside the kernel rather than baking it into the environment.
extlinux.conf
A simpler, GRUB-menu-like configuration format that many mainline U-Boot builds support natively via "distro boot" — lets a boot partition declare one or more boot entries (kernel, DTB, initrd, cmdline) without any U-Boot-specific scripting at all.

Both exist for the same reason: keep boot configuration as a versioned file that travels with the OS image, rather than as board-specific state living only in flash.

Debugging a board that won't boot

Where in the sequence a board gets stuck narrows the problem dramatically — work through it in order:

Real-world applications

Gotchas

Field notes