4. BootROM与第一阶段引导
在RISC-V启动链中,BootROM是芯片上电后执行的第一段不可修改的固件,通常固化在SoC内部掩膜ROM或受保护的安全存储区。它承担着“把系统从裸硬件状态带到可运行下一阶段引导程序”的职责。与U-Boot SPL、OpenSBI等后续阶段不同,BootROM代码量极小、功能高度受限,却决定了整个启动链的起点是否可靠。理解BootROM的作用、复位向量、硬件初始化以及加载SPL/FSBL的基本流程,是掌握OpenSBI与RISC-V启动链开发的基础。
一、BootROM的核心作用
BootROM的首要作用是提供确定性的复位入口。RISC-V处理器在复位后,PC会被设置为一个固定的复位向量地址,该地址通常指向BootROM的起始位置。由于此时DDR尚未初始化、缓存可能未使能、栈指针未设置,BootROM必须运行在极简环境中,通常直接使用芯片内部的SRAM或TCM作为临时存储。
BootROM的主要职责可以概括为以下几点:
- 建立最小运行环境:设置栈指针、清零BSS段、配置必要的CSR寄存器,使C代码可以运行。
- 硬件初始化:完成时钟、PLL、电源域、复位控制器、引脚复用等基础配置,为后续阶段准备硬件条件。
- 启动介质探测:根据启动模式引脚或eFuse配置,选择SPI Flash、SD/eMMC、UART、USB等启动源。
- 加载并校验下一阶段:从启动介质读取SPL/FSBL镜像,进行签名或校验和验证,然后跳转执行。
- 安全启动支撑:在安全启动场景中,BootROM是信任根,负责验证第一级可执行镜像的签名。
BootROM是启动链的信任根和第一段代码,它不负责完整系统启动,而是负责“把控制权安全、正确地交给下一阶段”。
二、复位向量与上电执行路径
RISC-V规范定义了复位时处理器的行为:复位向量地址由实现决定,通常通过硬件引脚或配置寄存器选择。例如,许多RISC-V SoC将复位向量设置为0x1000或0x80000000等固定地址。BootROM必须位于该地址处,且第一条指令通常是跳转到初始化代码。
上电后的典型执行路径如下:
- 处理器复位,PC指向复位向量。
- BootROM入口执行最简汇编初始化,设置栈、关闭中断、初始化时钟。
- 跳转到BootROM的C入口,完成硬件自检和启动介质选择。
- 从启动介质加载SPL/FSBL到内部SRAM。
- 校验镜像完整性,设置参数(如设备树地址、启动模式),跳转到SPL入口。
需要注意的是,BootROM阶段通常不初始化DDR,因为DDR训练耗时且依赖具体板级参数。因此,SPL/FSBL必须足够小,能够装入内部SRAM,并在自身阶段完成DDR初始化。
三、硬件初始化与启动介质选择
BootROM的硬件初始化范围因芯片而异,但通常包括:
- 时钟与PLL:将CPU时钟从低速晶振切换到PLL输出,提高执行速度。
- 电源与复位:释放相关电源域,确认复位源,记录启动原因。
- 引脚复用:配置启动介质相关引脚,如SPI、SD、UART。
- 存储控制器:初始化SPI控制器或SD控制器,使其可读取镜像。
- 安全模块:初始化TRNG、SHA、RSA等安全引擎,用于镜像校验。
启动介质选择通常由一组启动模式引脚(strap pins)或eFuse值决定。BootROM读取这些配置后,按优先级尝试启动源。例如,若SPI Flash启动失败,可能回退到UART下载模式。这种回退机制在开发和量产中都非常重要。
| 启动阶段 | 运行位置 | 主要任务 | 是否可修改 |
|---|---|---|---|
| BootROM | 芯片内部ROM | 复位入口、基础硬件初始化、加载SPL | 否,固化 |
| SPL/FSBL | 内部SRAM | DDR初始化、加载OpenSBI/U-Boot | 是,可升级 |
| OpenSBI | DDR | M模式运行时、SBI服务、跳转S模式 | 是,可升级 |
| U-Boot | DDR | 加载内核、设备树、根文件系统 | 是,可升级 |
四、加载SPL/FSBL的基本流程
BootROM加载SPL/FSBL的过程通常遵循“探测—读取—校验—跳转”四步。以SPI Flash启动为例,BootROM会从Flash的固定偏移处读取镜像头,解析镜像大小、加载地址、入口地址和校验信息,然后将镜像复制到内部SRAM,最后跳转到入口地址。
一个典型的镜像头结构可能包含以下字段:
struct boot_image_header {
uint32_t magic; // 魔数,如 0x53424F4F
uint32_t version; // 镜像版本
uint32_t load_addr; // 加载地址
uint32_t entry_addr; // 入口地址
uint32_t image_size; // 镜像大小
uint32_t checksum; // 校验和
uint8_t signature[]; // 可选签名
};
BootROM在跳转前还会传递启动参数,常见方式包括:
- 通过寄存器a0/a1传递hart ID和设备树地址。
- 通过内部SRAM固定地址传递启动信息结构体。
- 通过CSR或内存映射寄存器传递启动模式。
在开发阶段,可以通过UART输出BootROM日志,确认启动介质、镜像加载地址和校验结果。若BootROM无日志,可借助JTAG在复位向量处设置断点,单步跟踪执行路径。
五、常见实现与误区复盘
不同厂商的BootROM实现差异较大。例如,SiFive的BootROM通常从SPI Flash加载FSBL;全志D1的BootROM支持SPI、SD和USB FEL模式;StarFive JH7100的BootROM则从QSPI Flash加载SPL。尽管细节不同,但核心流程一致:复位向量→基础初始化→介质选择→镜像加载→校验→跳转。
常见误区包括:
- 误以为BootROM会初始化DDR:大多数BootROM不初始化DDR,SPL必须自行完成DDR训练。
- 忽略镜像头对齐要求:部分BootROM要求镜像按扇区或4KB对齐,否则加载失败。
- 混淆复位向量与入口地址:复位向量是CPU第一条指令地址,入口地址是SPL的起始地址,两者不同。
- 未处理启动失败回退:量产产品应配置回退启动源,避免单一介质损坏导致变砖。
复盘时,建议从复位向量开始,逐级确认BootROM日志、镜像头、校验结果和跳转地址。只有确保每一级都正确交接,OpenSBI和后续系统才能稳定启动。