331 – Android Bootloader: From Chip Power-On to Kernel Loading
Series Navigation: 330-Boot Overview | 332-init Process | 333-Zygote
In the previous article, we outlined the complete Android boot chain. This article focuses on the first software stage — the Bootloader.
The Bootloader is the first software code to run after hardware powers on (hard-coded in ROM/Flash). It is responsible for initializing hardware, loading the kernel, and verifying signatures. On Android devices, the Bootloader is often the most customized component and serves as each phone manufacturer’s “moat” — locking the bootloader is the first line of defense for system integrity.
The Bootloader’s Place
In embedded systems (phones, tablets, IoT devices), the Bootloader plays a similar role to a PC’s BIOS/UEFI, but with several key differences:
| Dimension | PC BIOS/UEFI | Phone Bootloader |
|---|---|---|
| Storage location | Motherboard SPI Flash | SoC internal ROM + eMMC/UFS |
| Upgradable | Usually upgradable | BL1 cannot be changed, BL2 can be upgraded |
| Responsibilities | Enumerate hardware, load GRUB | Initialize DRAM, load kernel, verify signatures |
| Security | UEFI Secure Boot (optional) | Mandatory signature verification, DM-Verity |
Memory layout after phone power-on:
0x00000000 ─┬─ ROM (Boot ROM, hard-coded in chip, unmodifiable)
│ └─ BL1: Burned into CPU chip at factory, executed first after CPU reset
│
0x00000000 ─┴─ SRAM (Chip internal high-speed memory, small capacity, for temporary data)
│
0x10000000 ─┬─ DRAM (External memory, must be initialized by Bootloader before use)
│ └─ Load Kernel + ramdisk (initramfs)
│
0x00000000 ─┬─ eMMC/UFS (External storage)
└─ BL2: Upgradable boot program (LK/ABOOT/U-Boot)Bootloader Two-Stage Structure
Android device Bootloaders typically use a two-stage (or even three-stage) design:
Stage 1: BL1 (Boot ROM)
The first instruction executed after CPU reset. Hard-coded inside the chip.
CPU Reset → Boot ROM (BL1)
→ Initialize minimal hardware (MMU/cache/Stack)
→ Load BL2 from storage media into SRAM
→ Jump to BL2BL1’s responsibilities are extremely streamlined — it only needs to load BL2 from persistent storage into memory. Since DRAM may not be initialized yet, many chips can only use SRAM.
Stage 2: BL2 (Little Kernel / ABOOT / U-Boot)
BL2 is the fully functional boot program that can be customized and upgraded.
Qualcomm devices commonly use LK (Little Kernel):
LK (BL2)
→ Initialize DRAM
→ Parse boot partition (kernel + ramdisk)
→ Signature verification
→ Load kernel into DRAM
→ Jump to execute kernelSpreadtrum/MediaTek devices commonly use U-Boot:
U-Boot (BL2)
→ Initialize DRAM / NAND Flash
→ Set boot parameters (ATAG/DTB)
→ Load kernel
→ bootz or bootmBootloader Detailed Workflow
┌─────────────────────────────────────────────────────────────┐
│ Chip Power-On / Reset │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ BL1: Boot ROM (CPU internal ROM) │
│ ┌──────────────────────────────────────────────────────────┐│
│ │ 1. CPU initial state: ││
│ │ - Disable MMU, disable D-Cache ││
│ │ - Set stack pointer to SRAM top ││
│ │ - Configure clock/CRG (reset default) ││
│ │ ││
│ │ 2. Minimal hardware init: ││
│ │ - Serial port (for debugging output) ││
│ │ - Clock/PLL (set CPU frequency) ││
│ │ - eMMC/NAND controller (basic init) ││
│ │ ││
│ │ 3. Load BL2: ││
│ │ - Read BL2 from boot partition (eMMC offset) ││
│ │ - Verify BL2 signature (hash check) ││
│ │ - Copy BL2 to SRAM (or DRAM if already initialized) ││
│ │ - Jump to BL2 entry point ││
│ └──────────────────────────────────────────────────────────┘│
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ BL2: Little Kernel / U-Boot / ABOOT │
│ ┌──────────────────────────────────────────────────────────┐│
│ │ 1. Full hardware initialization: ││
│ │ - DDR controller + DRAM initialization (DRAM training) ││
│ │ - eMMC/UFS controller (full init) ││
│ │ - GPIO, I2C, SPI, UART, USB, display... ││
│ │ ││
│ │ 2. Load kernel + ramdisk: ││
│ │ - Parse boot.img header (Android boot image format) ││
│ │ - Read kernel image (zImage/Image.gz) ││
│ │ - Read ramdisk (initramfs) ││
│ │ - Read DTB (Device Tree Blob) ││
│ │ ││
│ │ 3. Signature verification (if bootloader locked): ││
│ │ - Verify kernel hash against OEM public key ││
│ │ - If locked and verification fails: stop boot ││
│ │ - If unlocked: show warning (orange state) ││
│ │ ││
│ │ 4. Jump to kernel: ││
│ │ - Setup boot parameters (ATAG or DTB pointer) ││
│ │ - Set CPU to SVC mode (supervisor mode) ││
│ │ - Turn off MMU, I/D-Cache ││
│ │ - Jump to kernel entry point (usually at 0x8000) ││
│ └──────────────────────────────────────────────────────────┘│
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Linux Kernel Entry: start_kernel() │
└─────────────────────────────────────────────────────────────┘
Comments