2. Bootloader 阶段:U-Boot 启动日志分析与常见调试方法

U-Boot(Das U-Boot)是嵌入式 Linux 系统中最通用的 Bootloader。它负责初始化硬件、加载内核镜像到内存,并将控制权交给内核。分析 U-Boot 的启动日志是定位硬件初始化失败、内存配置错误、内核无法加载等问题的第一步。本章将深入解析 U-Boot 启动流程、关键日志信息以及常用调试手段。

2.1 U-Boot 启动流程概览

U-Boot 的启动分为两个阶段:SPL(Secondary Program Loader) 和 U-Boot Proper。SPL 是体积较小的第一阶段引导程序,负责初始化最基本的硬件(如时钟、SDRAM),然后加载完整的 U-Boot 到内存中执行。

关键概念: 现代嵌入式 SoC 通常使用 SPL + U-Boot Proper 的双阶段启动模式,以解决片上 SRAM 容量不足的问题。
U-Boot 双阶段启动流程图 阶段一:SPL 片上 SRAM 执行 初始化时钟、SDRAM 阶段二:U-Boot Proper DDR 中执行 加载内核、设备树、启动 启动内核 跳转到内核入口 bootm / booti 启动流程说明: 1. SoC 上电后从 Boot ROM 加载 SPL 到 SRAM。 2. SPL 完成 DDR 初始化后,将 U-Boot Proper 从存储介质(eMMC/NAND/SD)拷贝到 DDR。 3. U-Boot Proper 解析环境变量,加载内核镜像(zImage/Image)和设备树(.dtb)到内存。 4. 执行 bootm/booti 命令,将控制权交给内核。

2.2 U-Boot 启动日志关键信息解读

U-Boot 启动日志通常通过串口输出,波特率常见为 115200。以下是一段典型的启动日志及其关键字段解析:

U-Boot 2023.04 (Jan 15 2025 - 14:30:00 +0800)

CPU:   i.MX8M Plus Quad rev1.1 at 1600 MHz
Model: MYD-Y8MPLUS Development Board
DRAM:  2 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
Net:   eth0: ethernet@30be0000
Hit any key to stop autoboot:  0
=> 
日志行 含义 调试关注点
U-Boot 2023.04 ... U-Boot 版本及编译时间 确认版本是否与板级支持包匹配
CPU: i.MX8M Plus ... SoC 型号、版本、主频 主频异常可能表示时钟配置错误
DRAM: 2 GiB 检测到的内存容量 容量不符时检查 DDR 时序参数
MMC: FSL_SDHC: 0, 1 检测到的存储设备 设备缺失表示驱动或硬件问题
Net: eth0: ... 网络接口初始化状态 网络启动时需确保此行为空
Hit any key to stop autoboot 倒计时等待用户中断 倒计时不出现可能表示串口配置错误
调试技巧: 如果串口无输出,首先检查 波特率 是否匹配(常见 115200/57600),其次检查 串口电平(RS232 vs TTL)和 硬件连接(TX/RX/GND 是否交叉)。

2.3 常见 U-Boot 调试方法与命令

U-Boot 提供了丰富的命令行接口,用于调试硬件和加载内核。以下是最常用的调试命令:

2.3.1 内存与设备调试

  • md:查看内存内容,例如 md 0x80000000 10 查看地址 0x80000000 处的 16 个字节。
  • mw:写内存,例如 mw 0x80000000 0xdeadbeef 4。
  • mmc dev:切换 MMC 设备,mmc info 查看设备信息。
  • sf probe:探测 SPI Flash 设备。

2.3.2 网络调试

  • dhcp:通过 DHCP 获取 IP 地址。
  • ping:测试网络连通性,例如 ping 192.168.1.100。
  • tftp:通过 TFTP 下载文件到内存,例如 tftp 0x80200000 zImage。

2.3.3 环境变量与启动

  • printenv:打印所有环境变量。
  • setenv:设置环境变量,例如 setenv bootargs console=ttymxc0,115200 root=/dev/mmcblk1p2。
  • saveenv:保存环境变量到存储介质。
  • bootm:启动内核镜像(uImage 格式)。
  • booti:启动内核镜像(Image 格式,ARM64)。
U-Boot 常用调试命令关系图 U-Boot 命令行 内存调试 md / mw / mtest 存储调试 mmc / sf / fatls 网络调试 dhcp / ping / tftp 启动调试 bootm / booti 提示:使用 help 命令查看所有可用命令;使用 help <command> 查看具体命令用法。

2.4 典型启动失败场景与对策

故障现象 可能原因 调试对策
串口无任何输出 串口配置错误、硬件连接问题、SPL 未正确执行 检查波特率、电平、连接线;确认 SoC 启动模式引脚设置
DRAM 检测容量错误 DDR 时序参数配置错误、硬件焊接不良 使用 mtest 命令进行内存压力测试;核对 DDR 数据手册
MMC/SD 卡无法识别 驱动未编译、硬件电源问题、卡槽接触不良 使用 mmc list 查看设备;检查板级设备树配置
网络不通 PHY 地址错误、MAC 地址未设置、网线问题 使用 mdio list 查看 PHY;使用 setenv ethaddr 设置 MAC
无法加载内核 内核镜像格式错误、加载地址错误、存储介质损坏 确认镜像格式(uImage vs Image);使用 iminfo 检查镜像头部
重要提醒: 在修改 U-Boot 环境变量前,建议先使用 printenv 备份原始配置。错误的 bootargs 或 bootcmd 可能导致系统无法启动,此时可通过串口中断进入 U-Boot 命令行进行修复。

2.5 使用 JTAG/SWD 调试 U-Boot

当串口输出完全不可用或需要单步调试时,JTAG/SWD 调试器是终极手段。常用工具包括 OpenOCD + GDB。以下是一个典型的调试流程:

  1. 连接调试器:将 JTAG/SWD 调试器(如 J-Link、ST-Link)连接到目标板的调试接口。
  2. 启动 OpenOCD:加载目标芯片的配置文件,例如 openocd -f board/my_board.cfg。
  3. 启动 GDB:连接 OpenOCD 的 GDB 服务端口(默认 3333):arm-none-eabi-gdb u-boot,然后执行 target remote localhost:3333。
  4. 设置断点:在 board_init_f 或 start.S 等关键函数设置断点。
  5. 单步执行:使用 stepi 或 next 命令跟踪执行流。
# GDB 调试会话示例
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) file u-boot
(gdb) load
(gdb) thbreak board_init_f
(gdb) continue
(gdb) info registers
r0             0x10000000       268435456
pc             0x17800200       0x17800200 <board_init_f>
(gdb) stepi
0x17800204 in board_init_f ()
调试技巧: 在 GDB 中使用 monitor reset halt 可以精确控制 SoC 复位后的第一条指令,这对于调试 SPL 阶段的早期初始化非常关键。

2.6 小结