1. 课程导入

各位同学,咱们今天聊聊 BootROM。这东西听起来挺底层,其实它就是 SoC 上电后跑的第一段代码。我做了这么多年嵌入式,发现很多工程师对 BootROM 的理解停留在「知道有这么个东西」,真要问它怎么工作、存在哪、为什么非它不可,就说不清了。

这一章,咱们把 BootROM 的底裤扒干净。

1.1 什么是 BootROM

BootROM,全称 Boot Read-Only Memory。说白了,就是芯片出厂时固化在内部的一块只读存储器里的启动代码。这块存储器是 ROM,不是 Flash,也不是 SRAM。你想想看,芯片一上电,CPU 从哪取第一条指令?

对,就是 BootROM。

它有几个关键特征:

  • 只读:出厂后不可修改,除非换芯片掩膜
  • 片上集成:在 SoC 内部,不需要外部存储器就能运行
  • 最先执行:CPU 复位后,PC 指针直接指向 BootROM 入口
  • 体积小:通常 4KB ~ 256KB,视芯片复杂度而定

核心认知:BootROM 是 SoC 启动流程的「第一棒」。它不负责加载操作系统,只负责把第二级 Bootloader(比如 U-Boot)从外部存储介质搬进内存,然后跳转过去。

我在项目中遇到过有人问:「BootROM 能不能升级?」答案是——不能。除非你重新流片。所以 BootROM 里的代码必须极其稳定,bug 要少到几乎没有。嗯,这里要注意,BootROM 一旦有 bug,那就是芯片级的硬伤,只能通过后续的 Bootloader 打补丁绕过去。

1.2 BootROM 在 SoC 启动流程中的位置

咱们来看一个典型的 SoC 启动流程。我习惯把它分成四个阶段:

  1. 复位阶段:硬件复位,CPU 从复位向量取指
  2. BootROM 阶段:执行片上 ROM 代码,初始化最小系统
  3. SPL / 二级 Bootloader 阶段:从 Flash/SD/eMMC 加载 U-Boot SPL
  4. U-Boot 阶段:初始化 DDR、外设,加载内核

BootROM 处在第二阶段,承上启下。它干的事很具体:

  • 配置系统时钟和 PLL
  • 初始化片内 SRAM(通常很小,几十 KB)
  • 检测启动介质(比如先看 SD 卡有没有插,再看 SPI Flash)
  • 从选中的介质读取固定偏移处的代码到 SRAM
  • 验证签名(如果使能安全启动)
  • 跳转到加载的代码

我的经验:调试启动问题时,很多人一上来就查 U-Boot,其实问题往往出在 BootROM 阶段。比如时钟没配好、启动介质检测顺序不对、签名验证失败。我建议先确认 BootROM 有没有正确执行,再往下追。

为什么会这样?因为 BootROM 执行时,DDR 还没初始化,你连打印都看不到。只能靠 GPIO 电平、示波器抓波形、或者芯片自带的调试接口来观察。

下面这张图,是我画的一个典型 SoC 启动流程,你可以看到 BootROM 的位置和它跟其他模块的关系。

SoC 启动流程与 BootROM 位置 SoC 启动流程与 BootROM 位置 ① 硬件复位 ② BootROM 执行 初始化时钟 · 检测启动介质 · 加载二级 Boot ③ SPL / 二级 Bootloader 初始化 DDR · 加载 U-Boot 主体 ④ U-Boot 主体 加载内核 · 启动操作系统 💡 关键点: BootROM 是唯一在片内 ROM 中执行的阶段,后续所有代码都从外部存储加载。BootROM 的稳定性直接决定芯片能否正常启动。

1.3 BootROM 的硬件特性与存储介质

聊完位置,咱们看看 BootROM 的硬件底子。这部分我建议你重点理解,因为很多启动问题追根溯源,都是硬件特性没吃透。

1.3.1 存储介质:为什么是 ROM?

BootROM 用 ROM 而不是 Flash,原因很简单:

特性 ROM Flash SRAM
掉电保持 是 是 否
可修改 否(掩膜) 是 是
读取速度 快 中等 极快
面积成本 低 中等 高
上电可用性 立即 需初始化 立即

你看,ROM 在「上电可用性」和「成本」上占优。Flash 需要初始化控制器、配置时序,这本身就需要代码——鸡生蛋蛋生鸡的问题。所以 BootROM 必须用 ROM,上电就能读。

注意:有些芯片会用 Mask ROM 或 OTP ROM。Mask ROM 是流片时用光刻掩膜写入的,成本最低但改不了。OTP ROM 可以一次性编程,适合小批量定制。我见过一个项目,OTP 写错了启动介质优先级,结果只能重新流片——教训惨痛。

1.3.2 硬件特性一览

BootROM 的硬件特性,我总结成几个要点:

  • 地址映射:BootROM 通常映射在 CPU 的复位向量地址,比如 0x00000000 或 0xFFFF0000。具体看架构,ARM 一般是 0x00000000,RISC-V 可能是 0x80000000 附近。
  • 大小限制:受芯片面积限制,BootROM 通常很小。我做过一个 IoT 芯片,BootROM 只有 8KB。大一点的应用处理器,比如 i.MX 系列,也就 128KB 左右。
  • 执行环境:BootROM 在片内 SRAM 中执行,此时外部存储器(DDR、Flash)都不可用。所以它只能用 CPU 的通用寄存器、少量片内 SRAM 做临时数据存储。
  • 中断处理:BootROM 阶段通常关中断,或者只允许 NMI(不可屏蔽中断)。因为中断向量表还没配好,开中断就是找死。

1.3.3 启动介质检测机制

BootROM 怎么知道从哪加载代码?靠的是启动介质检测。我见过几种常见方案:

  • 硬件引脚选择:芯片有 BOOT0、BOOT1 引脚,外部拉高拉低决定启动介质。STM32 就是这么干的。
  • 自动探测:BootROM 按固定顺序尝试每个介质,直到成功。比如先试 SD 卡,再试 SPI Flash,最后试 UART。
  • fuse 配置:通过芯片内部的 eFuse 或 OTP 区域,烧录启动介质优先级。适合量产时锁定启动方式。

避坑指南:我曾经在一个项目里,BootROM 自动探测顺序是 SD → eMMC → SPI。结果 SD 卡槽没插卡,但卡检测引脚悬空,BootROM 误判为有卡,卡在 SD 初始化超时上。最后加了上拉电阻才解决。所以硬件设计时,启动检测引脚的上下拉一定要处理好。

1.3.4 BootROM 与安全启动

现在很多芯片要求安全启动,BootROM 是安全链的根信任锚点。它会做这几件事:

  1. 读取外部存储中的二级 Bootloader
  2. 用公钥验证代码签名
  3. 验证通过才跳转,否则死循环或进入恢复模式

公钥通常也固化在 BootROM 里,或者存在 OTP 中。这意味着一旦芯片出厂,你能信任的代码就被锁死了。嗯,这里要注意,如果你的产品需要远程升级 Bootloader,安全启动会带来额外的复杂度——你得保证签名密钥的安全。