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。

STM32MP U-Boot 启动链路与调试观测点 BootROM BOOT引脚选择介质 FSBL / U-Boot SPL DDR初始化、时钟、电源 U-Boot Proper env、bootcmd、驱动 Linux Kernel bootargs + DTB RootFS eMMC/NFS 环境变量存储 eMMC / SD / NAND / SPI env print / set / save bootcmd 脚本 mmc dev / ext4load bootz / booti bootargs console / root / rootwait ip / nfsroot DTB fdt_addr_r fdt print 调试观测点与常用命令 启动介质 mmc list / mmc dev 0 nand info / nand read dhcp / tftp / ping 镜像加载 ext4load / fatload nand read / tftp md / cmp 校验 设备树 fdt addr / fdt print fdt get value fdt resize 启动验证 printenv bootargs bootz / booti 内核cmdline核对

四、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
内核启动后 panicbootargs 中 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 的最终值、启动介质优先级、设备树文件名与加载地址、以及串口日志中关键行的预期内容。这份记录既是量产烧录的依据,也是现场故障排查的基线。