3. STM32MP启动流程与BootROM
STM32MP1 系列(如 STM32MP157、STM32MP135)是一类异构多核处理器:内部同时集成 Cortex-A7(或 Cortex-A35)应用核与 Cortex-M4 实时核。上电之后,芯片并不会直接跳到 Linux 内核,而是经历一条由硬件固化代码、片上 ROM、外部启动介质、多级引导程序共同组成的启动链。理解这条链,是排查“板子上电无输出”“TF-A 卡在 BL2”“U-Boot 找不到内核”等问题的前提。
一、BootROM:芯片上电后的第一段代码
BootROM 是 ST 在芯片出厂时固化在片内只读存储器中的一段不可修改代码,位于启动链的最前端。它的职责非常明确:
- 读取启动模式引脚(BOOT0~BOOT2)的电平组合,判断从哪种介质启动;
- 初始化最基础的时钟与所选启动介质控制器(如 SDMMC、QSPI、FMC、USB、UART);
- 从介质固定偏移处加载第一级引导程序(FSBL)到片内 SYSRAM;
- 校验 FSBL 头部(STM32 Header)中的签名、版本、加载地址、入口地址等字段;
- 校验通过后跳转到 FSBL 入口执行。
需要特别注意的是:BootROM 只认识“STM32 头部 + 镜像”这种格式,它并不理解 ELF、不理解文件系统,也不理解 U-Boot。因此 FSBL 必须被封装成 BootROM 能识别的镜像(通常由 STM32CubeProgrammer 或 tf-a 的 fiptool 生成)。若头部校验失败,BootROM 会尝试下一个启动介质,全部失败后进入串口/USB 的 ROM 下载模式(DFU),此时可通过 CubeProgrammer 恢复。
二、启动模式选择与启动引脚
STM32MP1 通过 BOOT0、BOOT1、BOOT2 三个引脚在上电复位时的电平组合决定启动源。以常见的 STM32MP157 为例,典型映射关系如下(具体以对应型号参考手册为准):
| BOOT2 | BOOT1 | BOOT0 | 启动介质 |
|---|---|---|---|
| 0 | 0 | 0 | NOR / 并行 FMC |
| 0 | 0 | 1 | eMMC / SD 卡(SDMMC) |
| 0 | 1 | 0 | NAND |
| 1 | 0 | 0 | QSPI NOR |
| 1 | 1 | 0 | 串口 / USB 下载(DFU) |
这些引脚通常在复位释放瞬间被采样,之后即可复用为普通 GPIO。开发板上一般用拨码开关或跳线帽选择启动介质,量产板则通过电阻上下拉固定。调试阶段最常见的做法是:先用 SD 卡启动验证镜像,再烧写到 eMMC 或 QSPI 固化。
三、FSBL 与 SSBL:两级引导的分工
STM32MP1 的启动链采用“两级引导”结构:
- FSBL(First Stage Boot Loader):由 BootROM 加载到 SYSRAM 执行,容量受限(通常 256KB 以内)。在 ST 官方方案中,FSBL 就是 TF-A 的 BL2。它负责初始化 DDR、时钟树、电源、安全外设,然后从启动介质加载 SSBL 到 DDR。
- SSBL(Second Stage Boot Loader):即 U-Boot(通常为
u-boot.stm32或u-boot-spl.stm32之后的完整 U-Boot)。它运行在 DDR 中,负责加载 Linux 内核、设备树、根文件系统,并把控制权交给内核。
因此,STM32MP1 的典型启动链可以概括为:
BootROM → TF-A BL2 (FSBL) → TF-A BL32/BL33 (OP-TEE / U-Boot) → Linux Kernel
四、TF-A 与 U-Boot 在启动链中的角色
TF-A(Trusted Firmware-A) 是 ARM 官方推荐的 A 核安全启动固件,在 STM32MP1 上被拆分为多个 BL 阶段:
- BL2:即 FSBL,运行于 SYSRAM,初始化 DDR 与安全环境;
- BL32:OP-TEE OS,运行于安全世界(Secure World),提供 TrustZone 服务;
- BL33:即 U-Boot,运行于非安全世界(Non-Secure World)。
U-Boot 作为 BL33,承担内核加载任务。它读取 bootcmd,从 eMMC、SD、网络或 USB 加载 Image、stm32mp157c-xxx.dtb 与根文件系统,最后通过 booti 或 bootz 跳转到内核入口。若启用了 FIT 镜像,U-Boot 还会校验内核与设备树的签名。
五、启动介质与镜像布局
不同启动介质对镜像布局有不同要求。以 SD 卡/eMMC 为例,ST 官方推荐的分区布局为:
分区 0: 0x00000000 ~ 0x000000FF GPT 头
分区 1: 0x00000100 ~ 0x00000FFF fsbl1 (TF-A BL2)
分区 2: 0x00001000 ~ 0x00001FFF fsbl2 (备份)
分区 3: 0x00002000 ~ 0x00003FFF fip (BL32+BL33)
分区 4: 0x00004000 ~ 0x00007FFF u-boot-env
分区 5: 0x00008000 ~ ... bootfs (内核+DTB)
分区 6: ... rootfs
BootROM 会从偏移 0x100 处读取 FSBL,因此烧写时不能简单地把 tf-a.stm32 拷到卡根目录,而要用 dd 或 CubeProgrammer 按偏移写入。QSPI NOR 启动时,FSBL 位于 0x0 偏移,FIP 位于 0x40000 偏移,具体以 ST 的 Flashlayout 文件为准。
六、典型排障思路
当板子上电无任何串口输出时,可按以下顺序排查:
- 确认 BOOT 引脚电平与目标介质一致,用万用表测量复位释放瞬间的电平;
- 确认 FSBL 头部有效,可用
STM32CubeProgrammer读取介质前 0x200 字节,检查是否有0x53544D32("STM2")魔数; - 确认 DDR 初始化参数与板卡匹配,DDR 配置错误会导致 BL2 卡死且无输出;
- 确认 FIP 包中 BL32/BL33 均已包含,可用
fiptool info fip.bin查看; - 若 U-Boot 能启动但找不到内核,检查
bootcmd、bootargs与分区名是否与 Flashlayout 一致。
CONFIG_BOOTDELAY=3,便于通过串口中断进入命令行,快速验证内核与设备树。掌握 BootROM 的加载规则、启动引脚映射、FSBL/SSBL 的分工以及 TF-A 与 U-Boot 的衔接关系,就能在启动失败时快速定位问题发生在哪一级,而不是盲目重烧镜像。