1. 课程导入与启动链全景
STM32MP 系列是 ST 推出的异构多核微处理器,典型型号如 STM32MP157、STM32MP135,内部同时集成 Arm Cortex-A 应用核与 Cortex-M 实时核。以 STM32MP157 为例,它包含双核 Cortex-A7(最高 650MHz/800MHz)与单核 Cortex-M4(209MHz),并配有 DDR 控制器、GPU、显示接口、以太网、USB、SDMMC、QSPI 等外设。理解这颗芯片的启动过程,是掌握 U-Boot 移植与调试的前提,因为 U-Boot 并不是"第一个运行的程序",它只是启动链中的一环,前面还有固化在芯片内部的 ROM Code 和由 ST 提供的 FSBL。
从复位释放那一刻开始,STM32MP 的启动链大致分为四个阶段:ROM Code → FSBL(TF-A)→ SSBL(U-Boot)→ Linux 内核。ROM Code 是掩膜在芯片内部的只读代码,上电后由 BOOT 引脚和 OTP 熔丝决定从哪个介质加载下一阶段镜像。它支持从 SD 卡、eMMC、QSPI NOR/NAND、USB、UART 等接口启动,并会先读取镜像头,校验签名与哈希,再把 FSBL 搬进片内 SYSRAM 执行。SYSRAM 容量有限(STM32MP157 约 256KB),所以 FSBL 必须足够小。
FSBL 通常由 TF-A(Trusted Firmware-A)实现,运行在 Cortex-A7 的 EL3 安全态。它负责初始化 DDR、时钟树、电源、安全外设,并把 SSBL 从启动介质加载到 DDR 中。FSBL 完成后会切换到 EL2 或 EL1,跳转到 U-Boot。U-Boot 作为 SSBL,承担更丰富的任务:初始化网络、USB、存储、显示等外设,提供命令行交互,加载内核镜像、设备树与根文件系统,最后通过 bootm/booti 跳转到 Linux 内核。内核启动后接管系统,挂载根文件系统,启动用户空间 init 进程,整个启动链才算完成。
把这条链画成一张全景图,能直观看到各阶段的运行位置、介质来源与交接关系。下图以 STM32MP157 为例,展示从复位到 Linux 用户空间的完整路径,并标注每个阶段的关键动作与典型镜像文件。
这张图里最容易被忽视的是"运行位置"这一行。ROM Code 和 FSBL 的前半段都在片内 SYSRAM 中执行,容量只有几百 KB,所以 FSBL 必须精简;一旦 DDR 初始化完成,U-Boot 和内核才在 DDR 中运行,空间不再受限。调试启动问题时,先判断故障发生在哪个阶段,比盲目改配置更有效。
判断当前处于哪个阶段,最直接的手段是看串口输出。STM32MP157 出厂时 ROM Code 会在 UART4(默认 115200-8-N-1)打印极简的启动信息,例如:
NOTICE: CPU: STM32MP157FAC Rev.Z
NOTICE: Model: STMicroelectronics STM32MP157F-DK2
NOTICE: Board: MB1272 Var1.0 Rev.C-01
INFO: PMIC version = 0x10
INFO: Reset reason (0x15): System reset
INFO: Boot mode: SDCARD (4)
如果串口只看到 ROM Code 的 "Boot mode" 行就停住,说明 FSBL 没有被正确加载或校验失败;如果看到 TF-A 的 NOTICE 但卡在 DDR 初始化,通常是 DDR 参数与板卡不匹配;如果 U-Boot 的 "U-Boot 2021.10" 横幅出现但无法进入命令行,则要检查环境变量或存储设备。这些判断依据都来自启动链各阶段的边界,而不是孤立地看某一条日志。
本课程后续会围绕这条链逐段展开:先讲 ROM Code 的启动介质选择与镜像头格式,再讲 TF-A 的编译、DDR 参数与安全启动,然后重点讲 U-Boot 的板级移植、驱动模型、环境变量、启动脚本与镜像加载,最后讲内核启动参数与根文件系统挂载。学习目标是能够独立完成一块 STM32MP157 板卡的 U-Boot 移植,并具备定位启动故障的能力。
工程环境准备方面,建议使用 Ubuntu 20.04/22.04 作为宿主系统,安装 STM32CubeProgrammer 用于烧录,准备一张 8GB 以上的 SD 卡,以及 USB-TTL 串口模块连接板卡的 UART4。源码获取使用 ST 官方仓库:
git clone https://github.com/STMicroelectronics/u-boot.git -b v2021.10-stm32mp
git clone https://github.com/STMicroelectronics/arm-trusted-firmware.git -b v2.6-stm32mp
git clone https://github.com/STMicroelectronics/linux.git -b v5.15-stm32mp
交叉编译工具链推荐使用 ST 提供的 SDK 或 Arm 官方 GNU Toolchain。编译 U-Boot 时,以 STM32MP157F-DK2 为例,常用命令如下:
make stm32mp15_defconfig
make DEVICE_TREE=stm32mp157f-dk2 all -j$(nproc)
生成的 u-boot.stm32 就是 SSBL 镜像,配合 TF-A 的 tf-a-stm32mp157f-dk2.stm32 一起烧录到 SD 卡的 FIP 分区即可启动。第一次上电时,建议先不修改任何代码,用官方镜像验证板卡能正常进入 U-Boot 命令行,再逐步替换自己编译的版本,这样能把"环境问题"和"代码问题"分开排查。
最后需要强调,STM32MP 的启动链不是固定不变的。在安全启动场景下,ROM Code 会校验 FSBL 的签名,FSBL 会校验 U-Boot 的签名,U-Boot 可以校验内核的签名,形成一条信任链。在开发阶段,通常关闭签名校验以方便迭代;量产阶段则必须开启。理解这条链的每个交接点,才能在安全与便利之间做出正确取舍。