4. U-Boot源码获取与工程化编译
STM32MP1 系列(如 STM32MP157、STM32MP135)的启动链与通用 ARM 平台有一个显著区别:它采用 ROM Code → FSBL(TF-A 或 SPL)→ SSBL(U-Boot proper)→ Linux 的分级引导结构。因此,当我们说“编译 U-Boot”时,实际上要产出两个可被 STM32 ROM Code 和 TF-A 识别的镜像:u-boot-spl.stm32(或 TF-A 的 tf-a-*.stm32)与 u-boot.stm32。本节围绕源码获取、工具链配置、defconfig 选择与 menuconfig 定制,完整走通一次工程化编译。
一、源码获取:认准 ST 官方维护的 U-Boot 仓库
STM32MP 的 U-Boot 并非直接使用 upstream 主线即可开箱可用,ST 在 GitHub 上维护了带 STM32MP 补丁的分支,仓库地址为 https://github.com/STMicroelectronics/u-boot。推荐使用与目标 BSP 版本匹配的分支,例如 STM32MP15 生态中常见的 v2022.10-stm32mp 或 v2023.10-stm32mp。获取方式如下:
git clone https://github.com/STMicroelectronics/u-boot.git
cd u-boot
git checkout v2022.10-stm32mp
git log --oneline -5 # 确认 HEAD 落在 ST 分支上
如果使用 ST 官方 Yocto/OE 层(meta-st-stm32mp),源码通常由 bitbake -c devshell virtual/bootloader 拉取到 build/tmp/work/.../u-boot-stm32mp/ 下,此时不建议手工 clone,而应复用 Yocto 已下载的源码树,避免版本漂移。判断源码是否“对”的关键点:arch/arm/dts/ 下应存在 stm32mp157c-*.dts、stm32mp135f-*.dts 等目标板设备树,board/st/stm32mp1/ 目录存在,且 configs/ 下有 stm32mp15_*_defconfig。
二、交叉编译工具链配置
STM32MP1 的 Cortex-A7 核使用 32 位 ARM 工具链,Cortex-M4 协处理器若需编译固件则使用 arm-none-eabi。U-Boot proper 与 SPL 均运行在 A7 上,因此统一使用 arm-linux-gnueabihf- 前缀工具链。推荐使用 ST 官方 SDK 中的工具链(如 SDK-x86_64 中的 arm-ostl-linux-gnueabi-),或 Linaro/ARM 官方 GCC。配置方式:
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
export PATH=/opt/st/stm32mp1/4.1-snapshot/sysroots/x86_64-ostl_sdk-linux/usr/bin/arm-ostl-linux-gnueabi:$PATH
arm-linux-gnueabihf-gcc --version # 确认可用
注意两点:其一,CROSS_COMPILE 必须以短横线结尾,否则 U-Boot 的 Makefile 会拼接错误;其二,若使用 ST SDK,工具链前缀可能是 arm-ostl-linux-gnueabi-,需相应调整。工具链版本建议 GCC 9~12,过旧可能不支持设备树中的新语法,过新可能触发 U-Boot 老分支的编译告警升级为错误。
三、defconfig 选择:从板级配置起步
U-Boot 的编译入口是 make <board>_defconfig。STM32MP15 常见配置包括:
stm32mp15_trusted_defconfig:使用 TF-A 作为 FSBL,U-Boot 作为 SSBL,最常用的生产配置;stm32mp15_basic_defconfig:使用 U-Boot SPL 作为 FSBL,适合学习 SPL 流程;stm32mp15_trusted_defconfig+ 自定义 DTS:适配具体开发板(如 DK2、EV1、自定义板)。
选择依据是启动链方案:若采用 TF-A + U-Boot,选 trusted;若希望 U-Boot 自己完成 DDR 初始化并直接产出 u-boot-spl.stm32,选 basic。执行:
make stm32mp15_trusted_defconfig
make menuconfig # 可选定制
四、menuconfig 定制要点
make menuconfig 打开的是 Kconfig 图形界面,STM32MP 场景下最值得关注的几项:
- Device Tree:
Device Tree Control→ 默认 DTB 选择目标板,如stm32mp157c-dk2; - Boot options:
Boot Media选择 eMMC/SD/NAND,影响CONFIG_SYS_MMC_ENV_DEV等; - Environment:
Environment in MMC或FAT,决定env存储位置; - SPL/TPL:basic 配置下需确认
SPL与SPL_MMC_SUPPORT已启用; - Command line:按需裁剪命令,减小镜像体积。
定制完成后保存为 .config,可用 make savedefconfig 生成精简的 defconfig 供团队复用,这是工程化的重要一步——把“某次手工 menuconfig 的结果”固化为可版本管理的板级配置。
五、编译与产物生成
编译命令与产物路径如下:
make -j$(nproc)
# 关键产物:
# u-boot.bin U-Boot proper 原始二进制
# u-boot.stm32 STM32 头部封装后的 SSBL 镜像
# spl/u-boot-spl.stm32 basic 配置下的 FSBL 镜像
# u-boot.dtb 编译进 U-Boot 的设备树
其中 u-boot.stm32 由 u-boot.bin 经 mkimage 加 STM32 头部(含加载地址、入口地址、校验)生成;u-boot-spl.stm32 同理来自 spl/u-boot-spl.bin。判断编译是否成功,除了看 make 返回 0,还应检查:u-boot.stm32 文件大小是否在预期范围(通常几百 KB),file u-boot.stm32 是否识别为 STM32 镜像,以及 u-boot.map 中 _start 是否落在 DDR 映射地址(如 0xC0100000)。
tf-a-stm32mp157c-dk2.stm32,U-Boot 只需产出 u-boot.stm32;若使用 basic 方案,则 U-Boot 同时产出 u-boot-spl.stm32 与 u-boot.stm32,两者需按 ROM Code 要求分别烧录到对应分区。六、工程化建议与常见问题
把上述过程固化为脚本或 Yocto recipe,是工程化的关键。建议在源码根目录维护一个 build.sh,固定 CROSS_COMPILE、defconfig 与 DTB,避免“换台机器就编不过”。常见问题包括:make 报 arm-linux-gnueabihf-gcc: not found(PATH 未导出)、u-boot.stm32 未生成(CONFIG_STM32MP15x 未选或 mkimage 缺失)、设备树不匹配导致启动卡在 U-Boot SPL 阶段(DTB 选错)。排查时优先看 u-boot.map 与串口早期输出,再核对 .config 中的 CONFIG_DEFAULT_DEVICE_TREE 是否与目标板一致。
完成本节后,你应能独立从 ST 官方仓库拉取源码、配置工具链、选择并定制 defconfig,最终得到可烧录的 u-boot.stm32(trusted)或 u-boot-spl.stm32 + u-boot.stm32(basic)镜像,为后续的 TF-A 集成与启动链调试打下基础。