The Many Paths to init, Part 3: The Embedded Frontier
While the PC and server world has evolved towards the simplicity of Unified Kernel Images, the embedded systems domain—dominated by ARM and RISC-V architectures—operates under a completely different set of rules. Here, the boot process is dictated by resource constraints, non-discoverable hardware, and a relentless focus on cost optimization.
The Multi-Stage Ascent from Silicon to RAM
The boot process on a typical System-on-Chip (SoC) is a multi-stage climb, with each loader establishing a more capable environment for the next. This is a direct consequence of the hardware’s initial memory limitations.

Raghu Bharadwaj
His writing style encourages curiosity and helps readers discover fresh perspectives that stick with them long after reading
- Stage 0: Boot ROM: Execution begins with immutable code etched directly into the SoC’s silicon. This Boot ROM is the ultimate root of trust. Its job is minimal: perform basic setup and search a predetermined sequence of boot devices (eMMC, SD card, etc.) for the next-stage loader. It loads this next stage into the SoC’s small, on-chip Static RAM (SRAM).
- Stage 1: Secondary Program Loader (SPL): The on-chip SRAM is often too small (just a few kilobytes) to hold a full-featured bootloader. Therefore, a tiny intermediate loader, the SPL, is loaded first. The SPL has one critical function: to initialize the main system Dynamic RAM (DRAM) controller.
- Stage 2: Main Bootloader: Once the much larger off-chip DRAM is available, the SPL loads the full-featured bootloader into it. This is typically Das U-Boot or its modern alternative, Barebox. This environment is far more powerful, providing an interactive shell, filesystem support, and networking capabilities. Its final task is to load the Linux kernel and hand over control.
U-Boot vs. Barebox: A Tale of Two Philosophies
While U-Boot and Barebox serve the same function, they represent different design philosophies.
- U-Boot is the long-standing industry standard, known for its vast hardware support. Its configuration and scripting model is powerful but idiosyncratic, relying on a set of environment variables stored in non-volatile memory.
- Barebox, which began as a fork of U-Boot, was created with the explicit goal of adopting a more Linux-like design. It provides a true shell environment where scripts are actual files, incorporates a Linux-style driver model, and even presents hardware resources through a virtual filesystem (e.g., /dev/mem). This makes development more intuitive for those already familiar with the Linux kernel.
The Device Tree Blob (DTB): Describing the Undiscoverable
Unlike the PC world with its self-enumerating buses like PCI, the hardware peripherals on an SoC (UARTs, I2C controllers, etc.) are at fixed memory addresses and cannot be discovered by the kernel at runtime.
The Device Tree is the solution. It is a data structure, written in a human-readable text file (.dts), that explicitly describes all the hardware on a specific board: what peripherals exist, their memory addresses, their interrupt connections, and other properties. This file is compiled into a compact Device Tree Blob (.dtb). The bootloader loads this .dtb into memory alongside the kernel and passes a pointer to it. The kernel then parses this data to learn what hardware it is running on, allowing a single, generic kernel binary to support a wide variety of boards.
From the resource-constrained world of embedded devices, we next turn to even more specialized platforms. In Part 4, we will examine the highly controlled boot flows of Android, IBM Z mainframes, and QEMU/KVM virtual machines.
Recent Posts

The sched_ext Revolution: A Comprehensive Analysis of BPF-Powered CPU Scheduling in the Linux Kernel – Part 2
To fully appreciate the capabilities of sched_ext, it is essential to understand its internal architecture and the flow of a task through its components. The framework is designed as a multi-layered system that carefully mediates the interaction between ..

The sched_ext Revolution: A Comprehensive Analysis of BPF-Powered CPU Scheduling in the Linux Kernel – Part 1
For decades, the Linux kernel has relied on a monolithic, general-purpose scheduler designed to perform reasonably well across a vast and diverse ecosystem. However, the accelerating complexity of both hardware and software has exposed the inherent limitations of this “one-size-fits-all” approach, creating an imperative for a more flexible and extensible scheduling paradigm

The Many Paths to init, Part 5: Unifying Themes
In this final installment of our series, we synthesize our exploration of diverse Linux boot processes by examining two critical, cross-platform themes: securing the chain of trust and ensuring system resiliency through atomic updates

The Many Paths to init, Part 4: The Specialists
Beyond PCs and general-purpose embedded systems lie platforms where the Linux boot process has been specialized to an extreme degree. In this installment, we explore three of these unique environments