“Before Linux prints its first log, the CPU has already taken a long, carefully choreographed journey.”

The Embedded Linux boot process is best understood by tracking where the CPU executes from at each stage. From power-on to a running kernel, execution moves through ROM → SRAM → DRAM. Kernel booting begins only when the CPU starts executing kernel code from RAM.

EMB_Linux_Boot_Process

1. Power-on and CPU reset

Everything starts with power-on or a hardware reset.

At this point:

  • The CPU enters a reset state
  • The Program Counter (PC) is forced to a fixed reset vector
  • MMU, caches, and DRAM are unavailable

The CPU has no concept of Linux, bootloaders, or filesystems yet. It can only execute instructions from a predefined address.

On ARM SoCs, this address maps to on-chip ROM, commonly called Boot ROM or iROM.


2. Boot ROM – the first code ever executed

Boot ROM is vendor-provided, immutable code stored inside the SoC. It is the very first code executed by the CPU.

Its responsibilities are intentionally minimal:

  • Basic CPU setup like switching to known CPU mode. Disable MMU and caches
  • Boot source selection (SD/eMMC, SPI, NAND, USB, UART). Reads boot mode pins or fuses.
  • Load the next-stage bootloader into on-chip SRAM and jump to its entry point

Execution now transitions from ROM to SRAM.


3. First-stage bootloader (SPL / BL1)

This stage runs entirely from SRAM, because DRAM is not usable yet. Initializing DRAM is hardware-specific and timing-critical. The kernel and full bootloader are far too large and complex to handle this early.

The sole purpose of this stage is to make DRAM available:

  • Clock and PLL configuration
  • Pin multiplexing
  • DRAM controller initialization
  • Optional secure boot verification

Once DRAM is initialized, the full bootloader is loaded into DRAM and execution jumps to it.

Execution now moves from SRAM to DRAM.

[!tip] This stage is commonly known as:

  • SPL (U-Boot)
  • BL1 (ARM Trusted Firmware)

4. Second-stage bootloader (U-Boot)

Now running fully from DRAM, the bootloader has access to a complete C runtime environment.

Its main responsibilities are:

  • Final hardware setup (cache enablement, optional MMU setup)
  • Load Linux artifacts into RAM:
    • Kernel image
    • Device Tree Blob (DTB)
    • Initramfs (optional)
  • Prepare kernel boot parameters
  • Branch to the kernel entry point

After this jump, the bootloader never regains control.


5. Kernel entry – where kernel booting really starts

When U-Boot jumps to the kernel entry address:

  • The CPU begins executing kernel code from RAM
  • Control permanently leaves the bootloader

This moment marks the true start of kernel booting.

Early kernel actions include:

  • Kernel decompression (if compressed)
  • CPU mode and exception level setup
  • Stack initialization, page table setup, and MMU enablement Still no userspace. No drivers yet. Just the kernel taking control of the system.

6. Kernel initialization

With the system fully under kernel control, Linux proceeds to initialize:

  • Architecture-specific subsystems and the scheduler
  • Memory management
  • Built-in device drivers
  • Root filesystem
  • Userspace by starting init (PID 1)

Once init starts, the system transitions from kernel space to userspace.


Beyond the basic boot flow

  • Network booting: U-Boot can load the kernel and root filesystem over TFTP/NFS, commonly used during development and board bring-up.

  • Recovery and fallback boot: Multiple boot targets (primary kernel, recovery kernel, USB/UART fallback) help avoid hard bricking.

  • Secure boot chain: Each stage (ROM → SPL → U-Boot → Kernel) can authenticate the next using signatures and hardware roots of trust.

  • A/B system updates: Slot-based booting enables safe over-the-air updates with rollback support.

  • Initramfs-first boot: The kernel may boot into an initramfs for early userspace logic before switching to the real root filesystem.

  • ARM exception levels: Modern SoCs often start in EL3 or EL2 and transition through exception levels before entering the kernel.


References