2. 嵌入式启动基础
理解 Bootloader 分区与根文件系统的协同,必须先回到最原始的起点:处理器从复位向量开始,究竟是怎样一步步把存储介质里的二进制代码变成可运行系统的。嵌入式启动不是“上电就跑 Linux”,而是一条由硬件固化逻辑、芯片内部 SRAM、外部启动介质和各级软件共同构成的链式过程。任何一环的地址、大小或加载顺序出错,系统都会停在“无串口输出”或“反复重启”的状态。
一、处理器上电流程:从复位到第一条指令
处理器上电或复位后,程序计数器被硬件强制指向芯片定义的复位向量地址。这个地址通常位于片内 ROM 或可配置的启动映射区,而不是外部 DDR。此时 DDR 控制器尚未初始化,外部内存不可用,因此芯片只能依赖内部 SRAM(通常几十 KB 到几百 KB)执行最初的代码。整个上电流程可以概括为:
- 复位释放:电源稳定、时钟稳定、复位引脚释放,CPU 从复位向量取指。
- ROM Code 执行:芯片固化的只读代码开始运行,完成最基础的时钟、引脚和启动介质探测。
- 加载第一阶段引导:从选定启动介质读取小体积引导镜像到内部 SRAM。
- 初始化 DDR 并搬移完整 Bootloader:由 SPL 完成内存初始化,再把 U-Boot 等完整引导程序载入 DDR。
- 跳转操作系统:Bootloader 加载内核、设备树与根文件系统,移交控制权。
这条链路的关键约束是“空间逐级放大”:ROM Code 受限于固化容量,SPL 受限于内部 SRAM,完整 Bootloader 才拥有 DDR 的大空间。分区设计必须与这个逐级放大的节奏对齐。
二、ROM Code 与 SPL:分工与边界
ROM Code 是芯片厂商固化在硅片里的第一段程序,用户无法修改。它负责最保守的工作:配置基本时钟、初始化启动引脚、按预设顺序扫描启动介质(如 eMMC、SD、NAND、SPI NOR、USB、UART),并读取介质头部信息。以常见 SoC 为例,ROM Code 会读取 eMMC 的 boot 分区或用户分区的固定偏移,校验镜像头中的魔数、长度和校验和,然后把有效载荷复制到内部 SRAM。
SPL(Secondary Program Loader)是 ROM Code 的直接后继,也叫 MLO、x-loader 或 BootROM 二级引导。它的核心使命只有两个:初始化 DDR 控制器,把完整 Bootloader 从启动介质搬到 DDR。由于运行在内部 SRAM,SPL 必须极小,通常限制在 64 KB 到 256 KB 之间,因此不能包含文件系统、网络协议栈等重型功能。
关键边界:ROM Code 决定“从哪里启动”,SPL 决定“内存能不能用”,完整 Bootloader 决定“系统怎么起来”。三者职责不可混淆,分区规划时也必须分别满足它们的读取偏移和大小限制。
三、Bootloader 阶段划分
完整 Bootloader(以 U-Boot 为代表)通常划分为多个阶段,每个阶段承担不同任务:
| 阶段 | 运行位置 | 主要任务 | 典型大小 |
|---|---|---|---|
| ROM Code | 片内 ROM | 时钟初始化、介质探测、加载 SPL | 固化,不可见 |
| SPL | 内部 SRAM | DDR 初始化、搬移完整 Bootloader | 64~256 KB |
| U-Boot Proper | DDR | 驱动初始化、环境变量、加载内核与设备树 | 几百 KB~1 MB |
| 内核与根文件系统 | DDR | 挂载根文件系统、启动用户空间 | 数 MB~数百 MB |
在分区布局上,SPL 与 U-Boot Proper 往往被放在同一个 boot 分区或相邻的裸分区中,由 ROM Code 按固定偏移读取 SPL,再由 SPL 按镜像头描述读取 U-Boot Proper。若使用 FIT 镜像,还可以把内核、设备树和 initramfs 打包在一起,由 U-Boot 统一校验后加载。
四、启动介质类型与选择依据
常见启动介质包括 eMMC、SD 卡、NAND Flash、SPI NOR、USB 和 UART。选择时通常从容量、成本、可靠性、烧录便利性和启动速度五个维度权衡:
- eMMC:容量大、有坏块管理、支持 boot 分区,适合量产设备,是主流选择。
- SD 卡:可插拔、便于开发调试,但可靠性和一致性弱于 eMMC。
- NAND Flash:成本低、容量大,但需要 ECC 和坏块管理,SPL 必须内置相应驱动。
- SPI NOR:小容量、可直接执行、可靠性高,常用于存放 SPL 和 U-Boot。
- USB/UART:用于工厂烧录或救砖,速度慢,不适合作为最终启动介质。
# 典型 eMMC 启动分区布局(偏移示意)
0x00000000 GPT / 分区表
0x00000200 SPL(ROM Code 读取)
0x00040000 U-Boot Proper
0x00100000 boot 分区(内核 + 设备树)
0x00800000 rootfs 分区(根文件系统)
选择建议:开发阶段优先使用 SD 卡或 USB 下载,便于快速迭代;量产阶段切换到 eMMC 并锁定启动顺序。若产品需要现场升级,应保留 USB/UART 恢复通道,并在分区表中预留恢复镜像区域。
五、误区与复盘
初学者最常见的误区是把“启动介质”和“根文件系统所在分区”混为一谈。实际上,Bootloader 可以从 eMMC 的 boot 分区启动,而根文件系统位于同一 eMMC 的用户分区,甚至位于另一块存储上。另一个误区是忽略 SPL 的大小限制,把 DDR 初始化参数、文件系统驱动全部塞进 SPL,导致镜像超过 SRAM 容量,ROM Code 加载时被截断,表现为“串口无输出”。
复盘时建议按以下顺序排查:先确认启动引脚和启动顺序,再确认 ROM Code 能否读到 SPL 头部,接着确认 SPL 是否成功初始化 DDR,最后确认 U-Boot 能否正确读取 boot 分区和 rootfs 分区。每一步都对应明确的分区偏移和镜像头参数,只有把上电链路与分区布局对齐,后续的根文件系统协同才有稳定基础。