4、ROM Code阶段:芯片上电后的第一条指令
芯片上电那一刻,CPU到底先干了什么?
很多人以为是从Flash里读代码。其实不是。芯片复位后,CPU会从一个固定的物理地址取指——这个地址,指向的就是芯片内部固化的BootROM。说白了,芯片的第一口气,是ROM给的。
4.1 芯片上电后的第一条指令
不同架构的CPU,复位向量地址不一样。ARM Cortex-A系列通常是0x00000000或0xFFFF0000,RISC-V一般是0x80000000或0x00000000。但不管地址是多少,这个位置存放的必须是有效指令,而且是在芯片流片时就写死在ROM里的。
关键点:BootROM是只读的,不可篡改。这是TEE信任链的物理根。
我调试过一块RISC-V芯片,上电后死活跑不起来。用逻辑分析仪抓片选信号,发现CPU根本没访问外部Flash。后来查手册才知道,那颗芯片的复位向量是0x00010000,不是默认的0x00000000。嗯,这种坑,手册不仔细看真的会栽。
4.2 BootROM的职责
BootROM虽然小,但活儿不少。我把它拆成几个核心任务:
- 硬件初始化——设置时钟、PLL、DDR控制器、中断控制器等。这时候连栈都还没设好,只能用汇编写。
- 自检与安全校验——检查芯片是否被篡改,比如efuse状态、调试接口是否锁定。
- 启动介质探测——按优先级扫描eMMC、UART、SPI Flash等设备,找到可用的启动镜像。
- 加载并跳转——把下一级Bootloader(比如SPL或BL2)读到SRAM或DDR里,然后跳过去执行。
我个人习惯把BootROM看作“芯片的BIOS”,但它比BIOS更封闭——你改不了它,只能用它。
经验之谈:我在项目中遇到过BootROM里有个bug,导致某些批次的芯片在低温下无法从eMMC启动。最后只能靠修改下一级Bootloader来绕过。所以,别以为ROM代码就不会出问题——它只是你改不了而已。
4.3 启动介质选择
BootROM怎么知道从哪个设备启动?
通常靠硬件管脚的电平组合。芯片会采样几个GPIO的状态,然后查表决定启动顺序。常见的启动介质有:
| 启动介质 | 典型场景 | 速度 | 安全性 |
|---|---|---|---|
| eMMC | 量产设备、手机、平板 | 高 | 中(可加密分区) |
| UART | 开发调试、工厂烧录 | 低 | 低(明文传输) |
| SPI Flash | 嵌入式设备、IoT | 中 | 低(可读可写) |
| USB | 开发板、恢复模式 | 中 | 低 |
| NAND Flash | 老旧设备、工业控制 | 中 | 低 |
你想想看,如果BootROM先尝试从UART启动,那生产线上只要插着串口线,芯片就可能卡在等待串口数据的状态,永远进不了eMMC。所以量产设备的启动顺序,通常会把eMMC放在第一位,UART放在最后。
注意:我曾经见过一块开发板,BootROM默认先检测SPI Flash,再检测eMMC。结果SPI Flash里有个残留的旧镜像,导致芯片每次都从SPI启动,eMMC里的新系统死活跑不起来。排查了一整天才发现是启动优先级的问题。
4.4 ROM Code阶段的日志输出
BootROM能不能打印日志?
能,但有限。因为这时候UART可能还没初始化,DDR也没准备好。很多芯片的BootROM会通过一个专用的调试接口(比如JTAG或SWD)输出状态码,或者用GPIO闪烁来指示进度。
我习惯在调试时先看这几个信号:
- 复位状态寄存器——确认芯片是否真的从复位中释放了。
- 启动设备选择寄存器——确认BootROM识别到的启动介质对不对。
- 错误状态寄存器——如果启动失败,这里会留下错误码。
举个例子,某款芯片的BootROM错误码定义:
0x01 — 时钟初始化失败
0x02 — DDR训练失败
0x03 — eMMC初始化超时
0x04 — SPI Flash校验失败
0x05 — 镜像签名验证失败
看到0x05,基本可以断定是安全校验没通过。这时候别急着换硬件,先检查efuse是否烧录了正确的公钥哈希。
4.5 ROM Code阶段的信任根
TEE的安全启动,起点就在BootROM。芯片出厂时,厂商会把一个公钥哈希烧进efuse。BootROM在加载下一级镜像前,会用这个哈希验证镜像的签名。如果验证失败,芯片直接死循环——这就是所谓的“硬锁”。
我遇到过最头疼的情况:efuse被误烧,导致所有镜像都无法启动。那批芯片只能报废。所以,烧efuse之前,一定要 triple-check。
一句话总结:BootROM是TEE信任链的第一环。它不可改、不可跳、不可绕过。理解了BootROM,你就理解了芯片启动的“宪法”。
4.6 ROM Code阶段流程图
下面这张图,把BootROM的完整流程画出来了。建议你对照着看,能更直观地理解每个步骤。
这张图里,从“芯片上电”到“验证签名”是一条直线。但实际项目中,每个环节都可能出岔子。比如“探测启动介质”这一步,如果eMMC没焊好,BootROM就会超时,然后尝试下一个介质。你看到的日志可能就是一行Boot device not found。
嗯,ROM Code阶段的内容就这些。别看它简单,但它是整个TEE安全启动的基石。后面所有章节,都会反复提到“信任根”这个概念——它的源头就在这里。