3. Bootloader基础:U-Boot启动流程、常用命令与环境变量

在ARM平台嵌入式Linux系统中,Bootloader是系统上电后最先执行的软件,负责初始化硬件、加载内核并传递启动参数。U-Boot(Das U-Boot)是目前最广泛使用的开源Bootloader,支持多种ARM SoC架构。本章深入剖析U-Boot的启动流程、核心命令集以及环境变量机制,为后续内核移植与设备树配置奠定基础。

3.1 U-Boot启动流程

U-Boot的启动过程分为两个阶段:SPL(Secondary Program Loader) 和 U-Boot Proper。SPL是精简版加载器,负责初始化DDR、时钟等关键外设,并从存储介质(如SD卡、eMMC、NAND Flash)加载完整的U-Boot到内存中执行。

关键概念: SPL通常存储在ROM或启动介质的固定偏移位置(如SD卡的第1个扇区),其代码大小受限于内部SRAM(通常为4KB~64KB)。U-Boot Proper则运行在DDR中,提供完整的命令行交互功能。
实战提示: 在移植U-Boot到新ARM板时,SPL的配置(如DDR时序、时钟频率)是首要调试点。SPL无法正常启动时,通常表现为串口无输出或输出“Synchronous Abort”错误。
U-Boot启动流程 U-Boot 启动流程(ARM平台) 上电 / ROM BootROM SPL 加载与执行 初始化 DDR / 时钟 / 存储 加载 U-Boot Proper 到 DDR U-Boot Proper 命令行 / 引导 SPL 阶段关键动作 • 设置栈指针 • 初始化 DDR 控制器 • 从 SD/eMMC/NAND 读取 • 跳转到 U-Boot Proper U-Boot Proper 阶段 • 完整外设初始化 • 解析环境变量 • 进入命令行或自动引导

3.2 U-Boot常用命令

U-Boot提供了一套丰富的命令行工具,用于调试硬件、操作存储设备、加载内核以及配置引导参数。以下按功能分类列出最常用的命令:

命令 功能描述 典型用法示例
printenv 打印所有环境变量 printenv
setenv 设置环境变量 setenv bootargs 'console=ttyS0,115200'
saveenv 保存环境变量到存储设备 saveenv
tftp 通过TFTP从网络加载文件到内存 tftp 0x82000000 zImage
fatload 从FAT分区加载文件到内存 fatload mmc 0:1 0x82000000 zImage
ext4load 从ext4分区加载文件到内存 ext4load mmc 0:2 0x82000000 uImage
bootm 启动内存中的内核镜像(uImage格式) bootm 0x82000000
bootz 启动内存中的zImage内核 bootz 0x82000000 - 0x83000000
mmc MMC/SD卡设备操作 mmc dev 0(切换到MMC设备0)
sf SPI Flash操作 sf probe 0; sf read 0x82000000 0x100000 0x8000
go 跳转到指定内存地址执行 go 0x82000000
reset 复位系统 reset
常见陷阱: 使用 bootm 启动uImage时,必须确保内核镜像头部的加载地址与 bootm 参数指定的地址一致。地址不匹配会导致内核解压失败或系统崩溃。建议使用 bootz 启动zImage,它不依赖固定加载地址。

3.3 U-Boot环境变量与引导参数

U-Boot环境变量是存储在非易失性存储(如eMMC、NAND、SPI Flash)中的键值对,用于配置引导行为、网络参数、内核命令行等。环境变量在U-Boot启动时自动加载,并可通过命令行动态修改。

3.3.1 核心环境变量

变量名 作用 典型值示例
bootargs 传递给Linux内核的命令行参数 console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait
bootcmd 自动引导时执行的命令序列 fatload mmc 0:1 0x82000000 zImage; fatload mmc 0:1 0x83000000 imx6ull.dtb; bootz 0x82000000 - 0x83000000
loadaddr 默认加载内核镜像的内存地址 0x82000000
fdtaddr 默认加载设备树(DTB)的内存地址 0x83000000
serverip TFTP/NFS服务器的IP地址 192.168.1.100
ipaddr 开发板的IP地址 192.168.1.50
ethaddr 以太网MAC地址 00:11:22:33:44:55
bootdelay 自动引导前的等待秒数(设为-1禁用自动引导) 3

3.3.2 引导参数(bootargs)详解

bootargs 是U-Boot传递给Linux内核的最重要环境变量,它决定了内核如何识别控制台、挂载根文件系统、配置网络等。以下是一个完整的ARM平台引导参数示例:

setenv bootargs 'console=ttyS0,115200n8 \
                 root=/dev/mmcblk0p2 rw rootwait \
                 rootfstype=ext4 \
                 init=/sbin/init \
                 ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off \
                 earlyprintk'

参数说明:

  • console:指定串口终端设备及波特率,ttyS0 对应ARM的UART0。
  • root:根文件系统设备路径,/dev/mmcblk0p2 表示SD卡第二个分区。
  • rw:以读写方式挂载根文件系统。
  • rootwait:等待根设备就绪后再挂载,避免SD卡初始化延迟导致启动失败。
  • rootfstype:强制指定根文件系统类型(可选)。
  • ip:静态IP配置,格式为 ip=开发板IP:服务器IP:网关:子网掩码::网卡名:off。
  • earlyprintk:在内核早期初始化阶段输出调试信息,便于排查启动问题。
调试技巧: 在开发阶段,建议在 bootargs 中添加 earlyprintk 和 debug 参数,以便在内核早期崩溃时获取更多诊断信息。生产环境中应移除这些参数以减少启动时间。
U-Boot环境变量与引导参数关系 U-Boot 环境变量与引导参数传递关系 eMMC / NAND / SPI Flash 环境变量存储区 U-Boot 运行时环境 bootargs 解析 Linux 内核 环境变量传递流程 1. U-Boot从存储介质读取环境变量 2. 解析 bootcmd 中的引导命令 3. 将 bootargs 放入内核 ATAG 或 设备树 chosen 节点 4. 跳转到内核入口点

3.4 实战:配置自动引导流程

以下是一个典型的ARM平台自动引导配置,适用于从SD卡启动Linux内核和设备树:

# 设置内核和设备树加载地址
setenv loadaddr 0x82000000
setenv fdtaddr 0x83000000

# 设置引导参数
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait'

# 设置自动引导命令
setenv bootcmd 'fatload mmc 0:1 ${loadaddr} zImage; \
                fatload mmc 0:1 ${fdtaddr} imx6ull.dtb; \
                bootz ${loadaddr} - ${fdtaddr}'

# 保存环境变量
saveenv

# 重启测试自动引导
reset
关键点: bootz 命令的第三个参数是设备树(DTB)在内存中的地址。如果不需要设备树,可以省略该参数或传入 -。在ARM平台中,设备树是必须的,否则内核无法正确识别硬件。

3.5 本章小结

  • U-Boot启动分为SPL和U-Boot Proper两个阶段,SPL负责早期硬件初始化和加载完整Bootloader。
  • 常用命令涵盖环境变量管理、存储设备操作、网络加载和内核启动,掌握这些命令是调试的基础。
  • 环境变量 bootargs 是连接U-Boot与Linux内核的桥梁,其配置直接影响内核的硬件识别和根文件系统挂载。
  • 通过 bootcmd 可以实现全自动引导,减少人工干预,提高开发效率。