Key takeaway: Das U-Boot is a modular, two-stage (sometimes three-stage) bootloader that starts where the SoC’s on-chip ROM ends and hands off to an operating system. Because every board differs, real-world projects almost always rebuild, prune or extend U-Boot. Mastering its SPL/TPL architecture, driver model, devicetree, environment system and build flow lets you shrink boot time, add new peripherals, secure the chain of trust and create production-ready update mechanisms.
1 Boot Flow and Internal Architecture
| Stage | Who loads it | Runs from | Principal duties |
|---|---|---|---|
| SoC Boot ROM | Fixed in silicon | Internal SRAM | Locate first image, set up tiny stack |
| TPL (optional) | ROM | L1/L2 cache as SRAM | Load SPL when even 32-64 kB SRAM is tight1 |
| SPL | ROM / TPL | On-chip SRAM | Init DDR, clocks, PMIC; load U-Boot proper or directly Linux (Falcon mode)123 |
| VPL (optional) | SPL | DDR | Authenticates/chooses signed SPLs for A/B or verified boot1 |
| U-Boot proper | SPL | DDR | Exposes CLI, driver model, network & filesystem stacks, loads OS kernel4 |
SPL is intentionally minimal: it drops shell commands, networking and most drivers to fit tens of kilobytes. U-Boot proper contains the full command set and the driver model that probes hardware before booting the OS.
2 Core Subsystems
2.1 Driver Model (DM)
U-Boot switched from ad-hoc, #ifdef-heavy drivers to a uclass / driver / device hierarchy.
- Each uclass (GPIO, SPI, USB, …) defines a common API.
- A driver implements that API for a given IP block.
- A device is an instantiation described by devicetree or static data.
Benefits include automatic probing, power-domain ordering and near-zero code duplication. New peripherals are added by declaring:
cstatic const struct spi_ops my_spi_ops = { … };
U_BOOT_DRIVER(my_spi_drv) = {
.name = "my_spi",
.id = UCLASS_SPI,
.ops = &my_spi_ops,
.of_match = my_spi_ids,
.priv_auto_alloc_size = sizeof(struct my_spi_priv),
};
2.2 Devicetree in U-Boot
When CONFIG_OF_CONTROL=y, a flattened devicetree (FDT) is embedded or loaded at runtime to describe clocks, GPIOs or even which drivers DM should bind. One binary can therefore support several boards by appending the correct DTB at boot.
U-Boot keeps a second, leaner DTB for SPL so that DRAM init can still use libfdt even before full driver model is available.
2.3 Environment Variables
A CRC-protected key–value store holds bootcmd, bootargs, Ethernet MACs, update scripts, etc. The store lives in NOR/NAND, eMMC, SPI-flash or UBI and is copied to RAM on power-up.env set, env save and env print manipulate it from the shell; fw_printenv/fw_setenv offer the same service from Linux user space.
| Variable | Purpose |
|---|---|
bootcmd | Script executed after bootdelay expires |
bootargs | Kernel command line |
bootdelay | Seconds before auto-boot |
ethaddr / ipaddr | Network identity |
dfu_alt_info | DFU update descriptors |
3 Building and Porting U-Boot
3.1 Typical Workflow
- Clone & configure bash
git clone https://source.denx.de/u-boot/u-boot.git export CROSS_COMPILE=arm-linux-gnueabi- make myboard_defconfig - Patch board files
include/configs/<board>.h– high-level Kconfig overrides.board/<vendor>/<board>/– DDR init, pinmux, power.
- Add/modify DTs
arch/arm/dts/<soc>-<board>.dtsplus an optional<soc>-u-boot.dtsiwith u-boot,dm-spl; tags to keep SPL lean. - Iterate with serial debug
EnableCONFIG_DEBUG_UART=yandCONFIG_DEBUG_UART_SKIP_INIT=yto print from the very first instruction in SPL.
Free-Electrons (Bootlin) and Chromium guides walk step-by-step through SoC bring-up and driver reuse.
3.2 Customizing for Production
- Boot-time reduction:
- Skip U-Boot proper by letting SPL load a FIT that contains kernel+DT (Falcon mode).
- Strip features with
CONFIG_DISTRO_DEFAULTSoff andCONFIG_AUTOBOOT_KEYEDon.
- Secure/verified boot:
Build FIT images signed with RSA; VPL or U-Boot proper checks signatures before executing. - Field updates:
Adddfu 0 mmc 0to environment or compile the EFI capsule command set for UEFI-based updates.
4 Advanced Customization Scenarios
4.1 Adding a New Peripheral Driver
- Create a driver under
drivers/<subsys>/. - Register it with
U_BOOT_DRIVER. - Describe the hardware in DT (
compatible = "vendor,my-ip"). - Add a Kconfig option so
make menuconfigcan enable it.
Because DM uses the same call patterns as Linux, many drivers are ported with minimal changes—polling replaces IRQs and dynamic memory use is reduced.
4.2 Board-Specific Start-Up Script
Embed manufacturing or recovery logic:
text# boot.scr (Hush)
if test "${upgrade_available}" = "1"; then
echo "Applying update...";
run do_upgrade; setenv upgrade_available 0; env save;
fi
run distro_bootcmd
Compile with:
bashmkimage -T script -C none -n "Boot Script" -d boot.scr boot.scr.uimg
and point bootcmd=source ${scriptaddr}.
4.3 Dual-Slot A/B Scheme
Store two FIT images plus two U-Boot SPLs. A small VPL evaluates rollback indices and chooses the newest valid pair. Environment variables track slot status (boot_a_ok, upgrade_available).
5 Debugging and Maintenance
bdinfo,fdt addr,fdt print—inspect memory map and live devicetree.dm tree—list probed devices and uclasses.crc32 ${loadaddr} ${filesize}—verify payload integrity.env default -a—recover from a corrupted environment.
When hardware is silent, JTAG or SoC ROM traces help verify that SPL is actually running before DDR training.
6 Best-Practice Checklist
- Keep SPL tiny: only one console, one storage and DRAM init code.
- Let devicetree drive configuration: hard-coding GPIO numbers in C prevents board reuse.
- Version-control the environment: store a
.envtext file in the U-Boot tree and setCONFIG_ENV_SOURCE_FILEfor reproducible builds. - Upstream early: the mainline tree already supports hundreds of boards; merging avoids re-base pain and shares the maintenance load.
- Automate boot tests: run KernelCI-style jobs that power-cycle hardware and check that SPL/U-Boot banners and kernel login appear.
Conclusion
Understanding where U-Boot splits (ROM → TPL → SPL → U-Boot), how its driver model binds devices, and why environment and devicetree exist twice is the foundation for fast boot times, reliable updates and secure products. Whether you merely tweak bootcmd or create a fully signed, A/B-capable loader, the same internals apply—and with its upstream community and Linux-like APIs, U-Boot rewards engineers who embrace its architecture.