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 容量不足的问题。
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)。
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。以下是一个典型的调试流程:
- 连接调试器:将 JTAG/SWD 调试器(如 J-Link、ST-Link)连接到目标板的调试接口。
- 启动 OpenOCD:加载目标芯片的配置文件,例如
openocd -f board/my_board.cfg。 - 启动 GDB:连接 OpenOCD 的 GDB 服务端口(默认 3333):
arm-none-eabi-gdb u-boot,然后执行target remote localhost:3333。 - 设置断点:在
board_init_f或start.S等关键函数设置断点。 - 单步执行:使用
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 阶段的早期初始化非常关键。