331 Android Bootloader:从芯片上电到内核加载
系列导航:330-启动总览 | 332-init进程 | 333-Zygote
上篇我们梳理了 Android 启动的完整链路。本篇聚焦第一个软件阶段——Bootloader。
Bootloader 是硬件上电后第一个运行的软件代码(固化在 ROM/Flash 中),它负责初始化硬件、加载内核、验证签名。在 Android 设备上,Bootloader 往往是定制最深的组件,也是各手机厂商的”护城河”——锁 bootloader 是保证系统完整性的第一道防线。
Bootloader 的位置
在嵌入式系统(手机、平板、IoT 设备)中,Bootloader 和 PC 的 BIOS/UEFI 扮演类似角色,但有几大区别:
| 维度 | PC BIOS/UEFI | 手机 Bootloader |
|---|---|---|
| 存储位置 | 主板 SPI Flash | SoC 内部 ROM + eMMC/UFS |
| 是否可升级 | 通常可升级 | BL1 不可改,BL2 可升级 |
| 职责 | 枚举硬件、加载 GRUB | 初始化 DRAM、加载内核、验证签名 |
| 安全 | UEFI Secure Boot(可选) | 强制签名验证、DM-Verity |
手机上电后的内存布局:
0x00000000 ─┬─ ROM(Boot ROM,芯片内固化,不可修改)
│ └─ BL1:CPU 芯片出厂时烧录,CPU 复位后首先执行这段代码
│
0x00000000 ─┴─ SRAM(芯片内部高速内存,容量小,用于临时数据)
│
0x10000000 ─┬─ DRAM(外部内存,需 Bootloader 初始化后才能使用)
│ └─ 加载 Kernel + ramdisk(initramfs)
│
0x00000000 ─┬─ eMMC/UFS(外部存储)
└─ BL2:可升级的引导程序(LK/ABOOT/U-Boot)Bootloader 的两阶段结构
Android 设备的 Bootloader 通常采用两阶段(甚至三阶段)设计:
第一阶段:BL1(Boot ROM)
CPU 复位后执行的第一条指令。固化在芯片内部。
CPU Reset → Boot ROM(BL1)
→ 初始化最少硬件(MMU/cache/Stack)
→ 从存储介质加载 BL2 到 SRAM
→ 跳转到 BL2BL1 的职责极度精简——它只需要能把 BL2 从持久存储加载到内存。因为此时 DRAM 可能还没初始化,很多芯片只能用 SRAM。
第二阶段:BL2(Little Kernel / ABOOT / U-Boot)
BL2 是真正功能完整的引导程序,可以定制升级。
高通设备常用 LK(Little Kernel):
LK(BL2)
→ 初始化 DRAM
→ 解析 boot 分区(kernel + ramdisk)
→ 签名验证
→ 加载 kernel 到 DRAM
→ 跳转执行 kernel展讯/联发科设备常用 U-Boot:
U-Boot(BL2)
→ 初始化 DRAM / NAND Flash
→ 设置启动参数(ATAG/DTB)
→ 加载 kernel
→ bootz 或 bootmBootloader 详细工作流程
┌─────────────────────────────────────────────────────────────┐
│ 芯片上电 / 复位 │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Boot ROM(BL1,芯片内固化) │
│ ・关闭中断、设置栈 │
│ ・初始化 MMU、指令/数据缓存 │
│ ・从存储介质(eMMC/UFS)特定地址加载 BL2 到 SRAM │
│ ・验证 BL2 签名(可选,如果开启了 secure boot) │
│ ・跳转到 BL2 入口 │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Bootloader Stage 2(BL2:LK / ABOOT / U-Boot) │
│ ・初始化 DRAM 控制器 │
│ ・配置时钟树(PLL)、电源管理 │
│ ・初始化显示(early console,可打印 logo) │
│ ・解析 boot 分区(kernel + ramdisk) │
│ ・验证 boot.img 签名(Image signatures) │
│ ・验证 dtb(Device Tree Blob) │
│ ・加载 kernel 到 DRAM(0x00080000 或 0x40080000) │
│ ・加载 ramdisk 到 DRAM │
│ ・配置 ATAG 或 DTB 传递给内核的参数 │
│ ・跳转执行 kernel │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Linux Kernel │
│ ・解压内核(如果内核是压缩格式) │
│ ・初始化内核子系统 │
│ ・执行 /sbin/init(PID 1) │
└─────────────────────────────────────────────────────────────┘Boot.img 的结构
Android 的 kernel 和 ramdisk 不是独立文件,而是打包进一个 boot.img 镜像:
boot.img 结构:
┌────────────────┬────────────────┬────────────────┬─────────────┐
│ kernel │ ramdisk │ second stage │ dtb │
│ (压缩内核) │ (cpio归档) │ (可选) │ (设备树) │
└────────────────┴────────────────┴────────────────┴─────────────┘
↑ ↑ ↑ ↑
内核镜像 根文件系统 备用内核 硬件描述boot.img 的头部(boot header)包含元数据:
struct boot_img_hdr {
uint8_t magic[8]; // "ANDROID!"
uint32_t kernel_size; // kernel 大小
uint32_t kernel_addr; // 内核加载地址
uint32_t ramdisk_size; // ramdisk 大小
uint32_t ramdisk_addr; // ramdisk 加载地址
uint32_t second_size; // second stage 大小
uint32_t second_addr; // second stage 加载地址
uint32_t tags_addr; // ATAG/DTB 地址
uint32_t page_size; // Flash 页大小(通常 2048 或 4096)
uint32_t flags; // 标志位(签名验证等)
uint32_t cmdline[10]; // 内核命令行
uint32_t id[8]; // SHA1 镜像 ID
};kernel_addr 和 ramdisk_addr 是关键——这两个地址是 Bootloader 加载内核和 ramdisk 的物理地址。如果地址写错,内核会跑飞。
签名验证原理
Bootloader 是 Android 安全的核心环节。一个锁了 bootloader 的设备,意味着:
- BL1 不可修改(固化在芯片 ROM)
- BL2 必须是厂商签名(无法自行编译 U-Boot/LK 刷入)
- boot.img 必须是官方签名(无法用自编译内核替代)
签名验证流程
BL2 检查 boot.img 头部的 signature
↓
用公钥验证 kernel + ramdisk 的 HMAC/SHA256
↓
验证通过 → 加载 kernel + ramdisk
验证失败 → 进入 fastboot 模式或拒绝启动AVB(Android Verified Boot)2.0
Android 8.0+ 引入 AVB2.0 作为统一的验证启动框架:
AVB 2.0 验证链:
┌───────────────────────────────────────────────────────────┐
│ Bootloader(AVB 验证启动) │
│ → 读取 AVB footer(分区末尾的元数据) │
│ → 读取 vbmeta 分区(包含哈希树/公钥) │
│ → 逐级验证各分区:system/vendor/product │
│ → 验证失败 → 强制进入 recovery 或停机 │
└───────────────────────────────────────────────────────────┘AVB2.0 相比旧的 DM-Verity 的进步:支持 rollback protection(防止降级攻击)和 unlocked boot loader 检测。
fastboot 协议
当 Bootloader 检测到特殊按键组合(音量下 + 电源键),会进入 fastboot 模式。这是 Bootloader 提供的 USB 刷机协议:
# 进入 fastboot 模式后,PC 端可以用 fastboot 工具
fastboot devices
# 列出 fastboot 设备
fastboot flash boot boot.img
# 刷写 boot 分区
fastboot flash system system.img
# 刷写 system 分区
fastboot oem unlock
# 解锁 bootloader(会清除数据)
fastboot flashing unlock_critical
# 解锁关键分区(刷机用)
fastboot erase userdata
# 擦除用户数据fastboot 的本质:Bootloader 提供一个简单的 USB bulk 传输协议,接收 PC 发来的命令和数据。设备处于 fastboot 模式时,BL2 在跑,但内核还没加载。
一个重要区别:edify(recovery 的脚本引擎)可以解析 update.zip 里的签名,但 fastboot 直接烧写裸数据,没有脚本层。这影响了线刷包的格式。
高通 Bootloader:EL3 / EL2 / EL1
高通的 Bootloader 还有一个特殊之处——它运行在 ARM Exception Level 的不同层级:
EL3(Secure Monitor)→ BL1(boot ROM)的一部分,运行在安全世界
EL2(Hypervisor) → 可选,SMMU 配置
EL1(Kernel) → 正常的内核态高通的安全设计:
EL3: QSEE(Qualcomm Secure Environment)
→ 处理 DRM、密钥存储、指纹/人脸生物数据
EL2: hypervisor 分区隔离
EL1: 非安全世界(Normal World)
→ Linux kernel + Android这意味着即使 Linux 内核被攻破,EL3 的安全世界仍然是隔离的。这和苹果的 SEP(Secure Enclave Processor)是类似思路。
U-Boot 命令实践
如果你在嵌入式开发板(而非手机)上工作,很可能遇到 U-Boot。以下是常用命令:
# 查看环境变量
printenv
# 设置启动参数
setenv bootcmd 'mmc dev 1; ext4load mmc 1:2 0x40080000 /boot/zImage; bootz 0x40080000'
setenv bootargs 'console=tty0 console=ttyS0,115200 root=/dev/mmcblk0p2'
# 保存环境变量
saveenv
# 从网络加载内核(开发阶段有用)
tftp 0x40080000 zImage
# 打印启动信息
bdinfo
printenv bootargs和 Windows Boot 对比
| 阶段 | Android Bootloader | Windows Boot |
|---|---|---|
| 固件 | Boot ROM(芯片内固化) | BIOS/UEFI(主板 SPI) |
| 引导程序 | LK/ABOOT/U-Boot | winload.exe/bootmgfw.efi |
| 签名验证 | AVB2.0 + 厂商密钥 | UEFI Secure Boot(PK/KEK/DB) |
| 启动参数 | ATAG/DTB → kernel cmdline | BCD(Boot Configuration Data) |
| 刷机协议 | fastboot / edify (recovery) | DISM / WIM / recovery |
Windows 的 Secure Boot 原理和 Android AVB 类似,都是用公钥验证下一阶段代码。但 Windows 的 UEFI 证书存储在 NVRAM,而 Android 的 AVB 公钥存在 vbmeta 分区。
Wandos 对比
Wandos 实现了简化的 PE loader 来模拟 Windows 启动过程:
BIOS → MBR → wandos bootloader (PE loader)
↓
自研 kernel
↓
自研 initWandos 的 Bootloader 比 Android 的简单得多:
- 不需要签名验证(教学目的)
- 不需要多阶段设计
- 不需要处理 DRM/密钥
这让我们可以把注意力集中在”加载内核并跳转执行”这个核心逻辑上,而不是安全基础设施。
动手环节
1. 进入 Bootloader 模式
不同设备的进入方式不同:
# 高通设备:关机后按 音量下 + 电源键
# 华为设备:音量下 + 电源键(部分型号是音量上)
# 通用方法:adb reboot bootloader
adb reboot bootloader2. 查看 fastboot 设备
fastboot devices
# 列出 fastboot 模式下的设备
fastboot oem device-info
# 查看设备解锁状态(高通设备)3. 解锁 Bootloader(会清除数据!)
# 高通设备
fastboot oem unlock
# 华为设备(需要申请解锁码)
fastboot oem unlock <unlock_code>4. 提取 boot.img 并查看内容
# 从设备提取 boot 分区
adb shell dd if=/dev/block/bootdevice/by-name/boot of=/sdcard/boot.img
adb pull /sdcard/boot.img
# 用 binwalk 分析 boot.img 结构
binwalk boot.img
# 显示各段(kernel/ramdisk/dtb)的偏移量
# 提取 ramdisk
mkdir boot_parts
cd boot_parts
dd if=../boot.img bs=1 skip=$((0x800)) count=$((0x100000)) of=ramdisk.cpio.gz系列导航
- 330 Android 启动总览:整体链路、时间分布、boot_completed 机制
- 332 Android init 进程:init.rc 配置语言、服务启动、属性服务
- 333 Android Zygote:Zygote 预加载、fork 模型、APP 进程诞生
附录:常见 Bootloader 错误及排查
| 症状 | 原因 | 解决 |
|---|---|---|
| Bootloader 卡住不动 | BL2 损坏或签名验证失败 | 进入 fastboot 重新刷写 boot |
| fastboot 无法识别设备 | USB 驱动未安装 | 安装高通/MTK USB 驱动 |
FAILED (remote: invalid magic) |
boot.img 损坏 | 重新提取或从 ROM 包重新打包 |
FAILED (remote: signature verify fail) |
签名验证失败(BL 已锁) | 解锁 bootloader 或使用官方 boot.img |
| 循环重启进入 fastboot | 内核 panic 或 bootreason 错误 | 查看 adb shell dmesg 或 adb logcat |
作者:公众号「解码日记」,专注于操作系统、虚拟机、内核级技术深度解析。每周三更新。
评论