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.
- 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
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;
setenvchanges only live in RAM untilsaveenvwrites 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
- Interrupt autoboot at the "Hit any key to stop autoboot" prompt to reach the interactive shell.
- Inspect the current state:
printenvlists every variable currently set. - 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. - Test it without committing:
bootrunsbootcmdimmediately with the in-RAM changes, without touching flash. - Once it's confirmed working, persist it:
saveenvwrites the environment to flash so it survives a power cycle. - To undo a bad change,
env default -aresets everything back to the compiled-in defaults (still requiressaveenvto 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 withmkimage) 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:
- No output at all, ever — almost certainly Boot ROM or SPL — check boot-mode strap pins, power sequencing, and that the boot device actually has valid data at the expected offset.
- A U-Boot banner appears, then it hangs or resets — SPL succeeded (DRAM is working); the problem is in U-Boot proper — check the boot device U-Boot is trying to load from, and its own environment/configuration.
- U-Boot reaches a prompt and boots fine interactively, but autoboot fails — almost always
bootcmditself — trace through what it's actually trying to do, one command at a time, from the U-Boot shell. - U-Boot successfully says it's jumping to the kernel, then nothing — check
console=inbootargsfirst (a wrong UART/baud setting looks identical to "the kernel crashed silently") before assuming the kernel itself is broken — see Linux → Boot. - Kernel boots, but userspace never comes up — the handoff worked; the problem has moved into Linux boot territory — initramfs, root filesystem, or init itself.
Real-world applications
- Field-recoverable IoT devices — a well-designed
bootcmdfallback chain (try A, then B, then network recovery) is what lets a remote device survive a corrupted primary boot source. - A/B update systems — switching which root partition
bootargspoints at is the actual mechanism behind most atomic, rollback-capable update schemes (see Snap types & Ubuntu Core). - Manufacturing/production imaging — a boot.scr or extlinux.conf shipped as part of the OS image keeps every unit's boot behavior identical without per-board manual environment configuration.
- Field debugging — the "where did it get stuck" decision tree above is close to the actual first-response checklist for a "customer's device won't turn on" support ticket.
Gotchas
- Forgetting
saveenvis the single most common environment-configuration mistake — the change works perfectly until the next power cycle, then silently reverts. - A
bootcmdthat works when typed manually can still fail on autoboot if it depends on something (a USB device enumerating, a network link coming up) that isn't ready yet at boot time — timing matters differently in an interactive shell than during autoboot. - An extlinux.conf or boot.scr sitting on the boot partition takes priority over hand-set environment variables on many distro-boot configurations — a change to
bootargsthat "doesn't take effect" is often actually being overridden by one of these files, not silently ignored.