3. BootROM 与一级引导:SoC 内部 BootROM 执行流程、启动设备选择、安全启动基础

ARM SoC 上电或复位后,CPU 首先执行的并非用户编写的 U-Boot 或 Linux 内核,而是固化在芯片内部只读存储器(ROM)中的一段出厂代码——BootROM。BootROM 是芯片启动的第一阶段,负责完成最底层的硬件初始化、启动设备枚举与选择,并加载一级引导程序(SPL 或类似映像)到内部 SRAM 中执行。本章深入分析 BootROM 的执行流程、启动设备选择机制以及安全启动的硬件基础。

3.1 BootROM 执行流程

BootROM 的代码由芯片厂商(如 TI、NXP、Rockchip、Allwinner 等)在流片前编写并掩膜到 ROM 中,用户无法修改。其典型执行流程如下:

  1. 上电复位向量:CPU 从复位向量地址(通常为 0x00000000 或 0xFFFF0000)取指,进入 BootROM 入口。
  2. 基础硬件初始化:设置栈指针、关闭看门狗、初始化 PLL 与系统时钟、配置内存控制器(仅限内部 SRAM 可用)。
  3. 启动设备检测:根据硬件引脚电平(Boot Mode Pins)或 eFuse 配置,确定本次启动的设备类型(如 SD 卡、eMMC、NAND Flash、SPI NOR、USB 下载等)。
  4. 设备初始化与读取:初始化对应外设控制器(如 MMC、SPI、NAND 控制器),从启动设备读取固定偏移位置的一级引导映像到内部 SRAM。
  5. 映像校验(可选):若使能安全启动,BootROM 会使用公钥哈希或证书链验证映像签名;校验失败则停止启动或进入恢复模式。
  6. 跳转执行:将 CPU 控制权交给加载到 SRAM 中的一级引导程序(SPL 或 x-loader)。
关键约束:BootROM 通常只能使用芯片内部 SRAM(大小从 32KB 到 512KB 不等),因此一级引导映像必须足够小,且必须存放在启动设备的固定扇区/偏移位置(如 SD 卡的第 1 个扇区、eMMC 的 boot partition 等)。
BootROM 执行流程图 BootROM 执行流程 上电复位 基础硬件初始化 启动设备检测 设备初始化与读取 映像校验(可选) 跳转 SPL 执行 BootROM 执行完毕后,CPU 从内部 SRAM 的固定地址开始执行一级引导程序

3.2 启动设备选择机制

BootROM 通过读取芯片特定 GPIO 引脚在复位时的电平状态(Boot Mode Pins)或一次性可编程存储器(eFuse)中的配置,来决定从哪个外设加载一级引导程序。常见的启动设备类型及特点如下表所示:

启动设备 接口类型 典型偏移/扇区 读取速度 常见应用
SD 卡 SD/MMC LBA 0(第 1 扇区) 中等 开发板、原型验证
eMMC MMC Boot Partition 或用户分区 LBA 0 高 量产嵌入式设备
SPI NOR Flash SPI 0x00000000 低 小容量固件存储
NAND Flash NAND 控制器 块 0,页 0 中等 大容量数据存储
USB 下载 USB OTG 无(由主机通过 USB 协议传输) 取决于 USB 速率 工厂烧录、恢复模式
UART 下载 UART 无(串行协议传输) 极低 调试、紧急恢复
调试技巧:在开发板上,通常通过拨码开关或跳线帽设置 Boot Mode Pins。例如,TI AM335x 系列使用 SYSBOOT[4:0] 共 5 个引脚选择启动设备;Rockchip RK3399 使用 eFuse 或 PMU 寄存器中的 boot_sel 位域。调试时,务必先确认当前启动模式与预期一致,否则 BootROM 可能从错误的设备读取数据,导致启动失败。

3.3 一级引导程序(SPL)的加载与约束

一级引导程序通常称为 SPL(Secondary Program Loader) 或 x-loader。BootROM 将其从启动设备加载到内部 SRAM 后,CPU 跳转到 SPL 入口执行。SPL 的主要职责包括:

  • DRAM 初始化:配置 DDR 控制器、时序参数,使外部 DRAM 可用。
  • 加载二级引导程序:从启动设备读取 U-Boot 完整映像(或 ATF + U-Boot)到 DRAM 中。
  • 提供串口调试输出:初始化 UART,输出启动日志。
  • 支持安全启动链:验证下一级映像的签名。

SPL 的大小受限于内部 SRAM 容量。常见 SoC 的 SRAM 大小与 SPL 大小限制如下:

SoC 系列 内部 SRAM 大小 SPL 最大尺寸 典型 SPL 实际大小
TI AM335x 64KB 约 60KB 40~55KB
NXP i.MX6 256KB 约 248KB 80~150KB
Rockchip RK3399 192KB 约 180KB 100~160KB
Allwinner H3 32KB 约 28KB 20~27KB
常见陷阱:SPL 编译时若启用了过多驱动或功能(如文件系统支持、网络协议栈),很容易超出 SRAM 容量限制,导致 BootROM 加载后无法正常执行或发生内存越界。调试时若发现 SPL 无任何串口输出,首先检查 SPL 映像大小是否超过芯片 SRAM 上限。

3.4 安全启动基础

安全启动(Secure Boot)的目的是确保只有经过签名的、未被篡改的固件才能在目标设备上执行。BootROM 是安全信任链的根(Root of Trust)。其基本流程如下:

  1. 公钥注入:在芯片生产或首次部署时,将厂商公钥的哈希值(或公钥本身)烧录到 eFuse 或 OTP 存储器中。BootROM 在启动时读取该公钥。
  2. 映像签名:一级引导映像(SPL)在构建时使用厂商私钥进行签名,签名数据附加在映像尾部或存储在固定偏移位置。
  3. BootROM 校验:BootROM 加载 SPL 后,使用 eFuse 中的公钥验证映像签名。若签名无效,则停止启动或进入恢复模式。
  4. 链式信任:SPL 在加载 U-Boot 或 Linux 内核时,同样使用公钥或证书链验证下一级映像,形成完整的信任链。
安全启动信任链 安全启动信任链 BootROM(信任根) SPL(签名校验) U-Boot(签名校验) Linux 内核(签名校验) 每一级引导程序在加载下一级之前,都必须使用 eFuse 中的公钥验证其签名
调试安全启动:若安全启动失败,BootROM 通常会在特定寄存器中记录错误状态(如 TI AM335x 的 ROM_BOOT_ERR 寄存器),或通过 GPIO 输出错误码。在开发阶段,可以暂时禁用安全启动(如不烧录 eFuse 或使用非安全版本 BootROM),待功能调试完成后再启用签名校验。

3.5 常见 BootROM 调试方法

当 BootROM 阶段出现问题时,芯片通常没有任何串口输出(因为 UART 尚未初始化),调试难度较大。以下是一些实用方法:

  • 检查 Boot Mode 引脚电平:使用万用表或示波器测量 Boot Mode 引脚在复位时的电平,确认与预期启动设备一致。
  • 观察启动设备时钟/数据信号:使用示波器或逻辑分析仪捕获启动设备接口(如 SD 卡 CLK/CMD/DATA 线)上的信号,判断 BootROM 是否尝试读取数据。
  • 读取 BootROM 错误寄存器:部分 SoC 提供调试寄存器(如 ROM 版本号、错误码),可通过 JTAG 或内存映射地址读取。
  • 使用 JTAG 单步调试:连接 JTAG 调试器,在 BootROM 入口处设置断点,单步跟踪执行流程。
  • 检查 SPL 映像放置位置:确认 SPL 映像是否烧录在启动设备正确的偏移地址(如 SD 卡 LBA 0、eMMC boot partition 的 0 偏移)。
案例:某项目使用 TI AM335x 芯片,上电后无任何输出。检查发现 Boot Mode 引脚 SYSBOOT[4:0] 被误设置为 0b10101(对应 SPI0 启动),而实际固件烧录在 SD 卡中。将引脚配置改为 0b00101(MMC0 启动)后,系统正常启动。