4. U-Boot阶段调试与定制
U-Boot 是 STM32MP 系列从 BootROM 到 Linux 内核之间的关键引导层。它承担 DDR 初始化、时钟与电源配置、外设驱动加载、镜像加载与校验、内核启动参数传递等职责。产品交付阶段,U-Boot 的调试与定制往往决定了启动速度、启动可靠性和量产可维护性。本节围绕环境变量、bootcmd/bootargs、设备树传递、MMC/NAND/网络启动、命令调试、启动脚本优化与故障排查展开。
一、环境变量与启动参数体系
U-Boot 的环境变量分为默认环境(编译进镜像,位于 CONFIG_ENV_SOURCE_FILE 或板级头文件)和持久化环境(存放在 eMMC、SD、NAND 或 SPI Flash 的 env 分区)。运行时通过 env print、env set、env save 操作。STM32MP 常见关键变量包括:
bootcmd:自动启动时执行的主命令序列,通常调用bootcmd_stm32mp或自定义脚本。bootargs:传递给 Linux 内核的 cmdline,包含 console、rootfs、rootwait、rw 等。bootdelay:自动启动倒计时秒数,量产常设为 1~3,调试可设 5。fdtfile/fdt_addr_r:设备树文件名与加载地址。kernel_addr_r、ramdisk_addr_r:内核与 initramfs 加载地址。boot_targets:启动介质优先级列表,如mmc0 mmc1 usb0 pxe。
环境变量的修改必须区分“临时生效”和“持久化”。env set 只改 RAM 中的副本,掉电即失效;env save 才写入存储介质。量产阶段建议将关键变量固化到默认环境,避免依赖现场手工保存。
二、bootcmd 与 bootargs 的定制
STM32MP 的默认启动流程通常由 bootcmd_stm32mp 驱动,它遍历 boot_targets,对每个目标执行 distro_bootcmd 或脚本。定制时常见做法是重写 bootcmd,例如从 eMMC 固定分区加载内核与设备树:
setenv bootcmd 'mmc dev 0; ext4load mmc 0:2 ${kernel_addr_r} /boot/zImage; ext4load mmc 0:2 ${fdt_addr_r} /boot/stm32mp157a-dk1.dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}'
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk0p3 rootwait rw'
saveenv
bootargs 的每一项都直接影响内核行为。例如 root=/dev/mmcblk0p3 指定根文件系统分区,rootwait 让内核等待 MMC 枚举完成,rw 表示可读写挂载。若使用 NFS 根文件系统,则改为 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot ip=dhcp。调试时可通过 printenv bootargs 确认实际值,并在内核启动日志中核对 Kernel command line 一行是否与预期一致。
三、设备树传递与启动介质选择
U-Boot 将设备树二进制(DTB)加载到内存后,通过 bootz 或 booti 的第三个参数传给内核。STM32MP 支持 U-Boot 自身设备树与 Linux 设备树分离:U-Boot 使用 u-boot.dtb 完成板级初始化,Linux 使用 stm32mp157a-dk1.dtb。若两者混用,可能出现引脚复用冲突或外设无法识别。调试时可用 fdt print /soc 查看当前 U-Boot 设备树节点,用 fdt addr ${fdt_addr_r} 切换查看 Linux DTB。
启动介质选择由 boot_targets 和硬件 BOOT 引脚共同决定。STM32MP1 的 BOOT0/BOOT1/BOOT2 引脚决定 BootROM 从哪个介质加载 FSBL。产品交付时通常固定为 eMMC 启动,同时保留 SD 卡恢复通道。NAND 启动需要额外配置 ECC 和坏块管理,网络启动则依赖 TFTP 与 DHCP。
四、MMC、NAND 与网络启动实操
MMC 启动是最常见方式。以 eMMC 为例,典型分区为:分区 1 为 FSBL,分区 2 为 boot(内核+DTB),分区 3 为 rootfs。U-Boot 中执行 mmc dev 0 切换到 eMMC,mmc part 查看分区表,ext4ls mmc 0:2 /boot 列出文件。若加载失败,优先检查分区号、文件系统类型(ext4/fat)和地址是否越界。
NAND 启动需注意页大小、ECC 模式和坏块。U-Boot 命令 nand info 显示芯片参数,nand read ${kernel_addr_r} 0x00200000 0x00800000 从偏移 2MB 读取 8MB 内核。若出现 ECC error,需核对 CONFIG_NAND_STM32_FMC2 的 ECC 配置与硬件一致。
网络启动适合开发阶段快速迭代。配置 ipaddr、serverip、gatewayip 后,执行 dhcp 获取地址,tftp ${kernel_addr_r} zImage 下载内核,tftp ${fdt_addr_r} stm32mp157a-dk1.dtb 下载设备树,再 bootz 启动。网络启动的排查顺序是:PHY 链路(mii info)→ IP 获取(dhcp)→ TFTP 服务可达性(ping ${serverip})→ 文件路径与权限。
五、启动脚本优化与故障排查
启动脚本优化的核心是减少不必要的等待和重复加载。常见措施包括:将 bootdelay 从 5 降到 1;关闭未使用的 boot_targets;使用 bootz 直接指定地址而非依赖 distro 扫描;将内核与 DTB 放在同一分区减少切换。若需要保留恢复模式,可设置 bootdelay=3 并在串口输入任意键进入命令行。
故障排查建议按“现象—观测点—判断”推进。串口无输出时,先确认 BOOT 引脚和 FSBL 是否加载;有 FSBL 输出但卡在 U-Boot 时,检查 DDR 初始化日志和 env 是否损坏;能进 U-Boot 但内核不启动时,核对 bootargs 中的 console 与 root 参数;内核启动后挂载 rootfs 失败时,检查分区号、文件系统类型和 rootwait。下表给出常见现象与对应排查方向。
| 现象 | 可能原因 | 排查命令/方法 |
|---|---|---|
| 串口无任何输出 | BOOT 引脚错误、FSBL 未加载 | 检查 BOOT0/1/2 电平,确认 FSBL 分区 |
| 卡在 U-Boot 提示符 | bootcmd 为空或 env 损坏 | printenv bootcmd、env default -a |
| 内核启动后 panic | bootargs 中 root 分区错误 | 核对 root=/dev/mmcblk0p3 与分区表 |
| DTB 加载失败 | fdt_addr_r 越界或文件不存在 | ext4ls 确认路径,fdt addr 验证 |
| NAND 读取 ECC 错误 | ECC 模式与硬件不匹配 | nand info 对比驱动配置 |
| 网络启动超时 | PHY 未链路或 TFTP 不可达 | mii info、ping ${serverip} |
env export -t ${ramdisk_addr_r} 导出到内存再通过 mmc write 保存,避免误操作导致无法启动。完成上述定制后,应形成一份可复现的启动配置记录:默认环境变量清单、bootcmd 与 bootargs 的最终值、启动介质优先级、设备树文件名与加载地址、以及串口日志中关键行的预期内容。这份记录既是量产烧录的依据,也是现场故障排查的基线。