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”错误。
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 参数,以便在内核早期崩溃时获取更多诊断信息。生产环境中应移除这些参数以减少启动时间。
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可以实现全自动引导,减少人工干预,提高开发效率。