HomeARM CourseDay 25
DAY 25 · SYSTEM & MEMORY

The ARM Boot Process — End to End

By EcrioniX · Updated Jun 6, 2026

You press power. A few seconds later, Linux is at a login prompt. In between, a careful relay race runs: from a single hardwired address, through tiny on-chip code that wakes up DRAM, through bootloaders, to the kernel — each stage building the world the next one needs. This lesson ties the whole course together.

1. Power-on: the reset vector

When the core comes out of reset it has almost nothing — caches off, MMU off, no stack, DRAM not even initialised. It does exactly one thing: start fetching from a fixed reset address, the reset vector (the first entry of the vector table, Day 17). That address points into immutable, on-chip boot ROM — the only code guaranteed to be present and trustworthy.

2. Why boot happens in stages

The boot ROM is tiny and runs from small, fast on-chip SRAM because external DRAM isn't working yet — DRAM controllers need configuration before they're usable. So boot is a relay of increasingly capable stages, each loading the next:

The boot relay (Cortex-A / Linux-class) Boot ROMimmutable(on-chip) BL1/BL2init clocks+ DRAM U-Bootload kernelfrom flash KernelLinux bootsdrivers, MMU Userlogin Each stage verifies & loads the next; size & capability grow left to right.
Figure — Boot as a relay: tiny immutable ROM → low-level init → full bootloader → OS → userspace.

3. The C runtime: making main() possible

Compiled C assumes a working environment — a stack, initialised globals, zeroed variables. Something must build that before main(). That's the startup / C runtime (crt0) code, and it ties together everything from earlier lessons:

  1. Set the stack pointer (Day 14) so functions can run.
  2. Copy .data (initialised globals) from flash to RAM.
  3. Zero .bss (uninitialised globals) — C guarantees they start at 0.
  4. Install the vector table (Day 17) and configure clocks.
  5. Enable MMU/MPU & caches via CP15 / system registers (Days 20–24).
  6. Call main() — your program finally runs.
; Simplified Cortex-M reset handler (startup code) Reset_Handler: LDR sp, =_estack ; 1. stack pointer BL copy_data ; 2. .data flash → RAM BL zero_bss ; 3. clear .bss BL SystemInit ; 4-5. clocks, caches, etc. BL main ; 6. into your code

4. Secure boot: the chain of trust

How do you know none of those stages was swapped for malware? Secure boot. The immutable boot ROM holds (or knows) a root public key. It verifies the cryptographic signature of the next stage before running it; that stage verifies the next; and so on — an unbroken chain of trust rooted in hardware, all the way to the OS. This is the foundation under TrustZone: the Secure world is brought up first, verified.

5. Cortex-M boot: much simpler

A microcontroller has no DRAM to train and no Linux to load, so its boot is tiny. At reset the Cortex-M core (Day 18) does two things automatically from the vector table: load slot 0 → the initial stack pointer, and slot 1 → the reset handler. The reset handler runs the C-runtime steps above and calls main(). Power-on to your code in microseconds — no bootloader relay required.

💡 Waking a city

Boot is like powering up a city at dawn. First a single guaranteed generator (boot ROM) starts. It powers the substations (clocks, DRAM). Those light the districts (bootloader, kernel). Finally the shops open for the public (userspace). You can't open shops before the power plant — order is everything.

✅ The mental model

Boot is a relay from a single hardwired address: the reset vector → immutable boot ROM → bootloader stages that wake up clocks/DRAM and load the OS, with C-runtime startup building the stack/globals/vectors so main() can run. Secure boot verifies each stage in a hardware-rooted chain of trust. Cortex-M does a tiny version: SP + reset handler straight from the vector table.

🎯 Day 25 takeaways

Quick check

  1. Why can't the first boot code just run from external DRAM?
  2. List two things C-runtime startup must do before main().
  3. What makes secure boot a "chain" rather than a single check?

FAQ

What runs first at power-on?

The core fetches from the fixed reset vector into immutable on-chip boot ROM — the first trusted code.

Why multiple bootloader stages?

Early code is tiny and runs before DRAM works; a small stage inits clocks/DRAM, then loads a bigger loader (U-Boot), then the OS.

What is the chain of trust?

Each boot stage cryptographically verifies the next, rooted in immutable hardware, so only authentic software runs.

Previous
← Day 24: CP15 & coprocessors

← Back to the full course roadmap  ·  Deep dive: how a boot ROM works →