2. 启动流程基础:CPU复位后的第一条指令、启动介质选择与设备优先级
芯片上电那一刻,CPU 到底在干什么?
很多人觉得启动就是“加载操作系统”,其实没那么简单。从复位到第一条指令执行,中间藏着不少门道。我做了这么多年嵌入式,见过不少工程师在这块栽跟头——板子焊好了,死活起不来,最后发现是启动介质配置错了。
这一章,我们就从 CPU 复位后的第一行代码讲起,把启动介质的选择逻辑和优先级判定彻底说清楚。
2.1 复位向量:CPU 的第一口“奶”
CPU 复位后,内部寄存器会被硬件强制初始化。PC(程序计数器)会被赋一个固定值——这个值就是复位向量(Reset Vector)。
不同架构的复位向量地址不一样:
| 架构 | 复位向量地址 | 说明 |
|---|---|---|
| ARM Cortex-M | 0x00000000(向量表基址) | 从该地址取栈指针,0x00000004 取复位处理函数地址 |
| ARM Cortex-A | 0x00000000 或 0xFFFF0000 | 由硬件配置引脚决定,通常从 0x00000000 启动 |
| x86 | 0xFFFFFFF0 | 传统 BIOS 的入口,位于 4GB 地址空间顶端 |
| RISC-V | 0x00000000 或自定义 | 由具体芯片设计决定,常见为 0x80000000 |
关键点:复位向量指向的地址,必须是非易失性存储介质(ROM/NOR Flash)的映射区域。如果这个地址是空的,CPU 就会“跑飞”。
我个人习惯在项目初期先确认芯片的复位向量地址,然后检查 BootROM 是否真的映射到了那个位置。有一次,我发现某款 SoC 的 BootROM 默认映射在 0x00000000,但板级设计把 NOR Flash 接到了另一个片选上——结果 CPU 复位后读到的全是 0xFF,直接死机。
2.2 第一条指令:BootROM 的“开场白”
CPU 从复位向量取到的第一条指令,通常位于芯片内部的 BootROM 中。BootROM 是芯片出厂时固化的一段只读代码,不可修改。
这条指令做什么?
- 初始化基础硬件:关闭中断、设置栈指针、配置时钟(至少让 CPU 能跑起来)。
- 检测启动模式:读取芯片的启动模式选择引脚(BOOT_MODE[1:0] 之类的),判断从哪种介质启动。
- 跳转到启动加载器:根据检测结果,从对应介质加载下一级代码(SPL、U-Boot、或直接加载 OS)。
嗯,这里要注意:BootROM 的代码量非常有限,通常只有 4KB~64KB。所以它只能做最基础的事情——说白了,就是“把接力棒交给下一棒”。
实战经验:我在调试某款 ARM SoC 时,发现 BootROM 执行后系统卡死。用逻辑分析仪抓片选信号,发现 BootROM 根本没去访问外部 Flash。后来查手册才知道,该芯片的 BootROM 会先检查一个“启动有效标志”——如果该标志被擦除,BootROM 会进入下载模式,等待串口或 USB 烧录。这个坑,我踩了整整两天。
2.3 启动介质选择:NOR Flash、NAND Flash、eMMC、SD 卡
BootROM 检测到启动介质类型后,会用对应的协议去读取数据。不同介质的电气特性和读取方式完全不同。
2.3.1 NOR Flash
NOR Flash 支持随机访问,CPU 可以直接在 NOR Flash 上执行代码(XIP,eXecute In Place)。
- 优点:无需拷贝到 RAM,启动速度快。
- 缺点:容量小(通常 8MB~64MB),写入慢,价格高。
- 典型场景:BIOS/UEFI 固件存储、小容量嵌入式系统。
2.3.2 NAND Flash
NAND Flash 是块设备,不能直接执行代码。BootROM 必须先把 NAND 中的前几页读到内部 SRAM 中,然后跳转执行。
- 优点:容量大(GB 级别),成本低。
- 缺点:存在坏块,需要 ECC 校验,读取速度受限于接口。
- 典型场景:嵌入式 Linux 系统、消费电子。
避坑指南:我曾经遇到过 NAND Flash 启动失败的问题。原因是 BootROM 读取 NAND 时,默认的 ECC 强度不够,导致前几页数据出现位翻转。后来我强制在 BootROM 配置中启用更强的 ECC 算法,问题才解决。如果你用 NAND 启动,务必确认 BootROM 的 ECC 能力与 NAND 的坏块管理策略匹配。
2.3.3 eMMC
eMMC 内部集成了 Flash 控制器和坏块管理,对外提供标准的 MMC 接口。BootROM 通过 MMC 协议读取数据。
- 优点:无需关心坏块,接口标准化,读写速度快。
- 缺点:启动过程比 NOR 复杂,需要初始化 MMC 控制器。
- 典型场景:手机、平板、高端嵌入式设备。
2.3.4 SD 卡
SD 卡与 eMMC 协议类似,但通常用于可插拔场景。BootROM 通过 SPI 或 SDIO 接口访问。
- 优点:可更换,方便调试和量产。
- 缺点:速度受限于接口,可靠性不如 eMMC。
- 典型场景:开发板、单板计算机(如 Raspberry Pi)。
| 介质类型 | 是否支持 XIP | 是否需要 ECC | 典型容量 | 启动速度 |
|---|---|---|---|---|
| NOR Flash | 是 | 否 | 8MB~64MB | 快 |
| NAND Flash | 否 | 是 | 128MB~8GB | 中 |
| eMMC | 否 | 内置 | 4GB~128GB | 快 |
| SD 卡 | 否 | 内置 | 1GB~1TB | 中 |
2.4 启动设备优先级:谁先被“翻牌”?
大多数 SoC 支持从多种介质启动。BootROM 会按照预设的优先级顺序尝试每个介质,直到成功读取到有效启动代码。
优先级通常由以下因素决定:
- 硬件引脚电平:芯片的 BOOT_MODE 引脚组合决定第一优先级。
- 熔丝/OTP 配置:一次性可编程区域,固化启动顺序。
- BootROM 内部逻辑:某些芯片固定先尝试 SPI NOR,再尝试 NAND,最后尝试 SD 卡。
举个例子,某款 i.MX 系列 SoC 的默认启动顺序是:
- eMMC(如果检测到有效启动标志)
- NAND Flash(如果 eMMC 失败)
- SD 卡(如果 NAND 也失败)
- USB 下载模式(所有介质都失败后)
注意:启动优先级不是死的。你可以通过修改 OTP 或外部引脚来改变顺序。但 OTP 是一次性的,改错了就得换芯片。我建议在开发阶段用引脚配置,量产时再固化 OTP。
你想想看,如果 BootROM 按顺序尝试每个介质,但某个介质上恰好有残留数据(比如一块旧 Flash 没擦干净),BootROM 可能误判为“有效启动代码”,然后加载失败。这就是为什么很多芯片要求启动介质的前几个字节必须是特定的“启动签名”(Boot Signature)。
2.5 启动流程总览图
下面这张图展示了从 CPU 复位到 BootROM 选择启动介质的完整流程:
2.6 实际项目中的启动配置建议
说了这么多理论,最后给几条实在的建议:
- 开发阶段用 SD 卡或 USB 下载模式:方便反复烧录,不用频繁擦写 Flash。
- 量产前务必确认启动介质优先级:用硬件引脚模拟所有可能的启动失败场景,确保 BootROM 能正确 fallback。
- 检查启动签名:如果 BootROM 要求特定签名(比如 0xAA55 或自定义 Magic Number),确保你的启动镜像头部包含它。
- 预留调试接口:哪怕产品最终只用 eMMC 启动,也建议在板上留一个 SPI NOR Flash 焊盘——万一 eMMC 坏了,还能从 NOR 启动救砖。
我的习惯:每次拿到新开发板,第一件事就是看 BootROM 的启动日志。通过串口输出,你能看到 BootROM 尝试了哪些介质、在哪一步失败了。这些日志是调试启动问题的最直接线索——比看原理图快多了。