3. Bootloader核心概念
在嵌入式Linux系统中,U-Boot是使用最广泛的Bootloader之一。它承担着从ROM代码到操作系统内核之间的桥梁作用:初始化关键硬件、加载内核与设备树、传递启动参数,并在必要时提供交互式命令行进行调试与维护。理解U-Boot的架构与运行机制,是掌握Bootloader分区与根文件系统协同工作的前提。
一、U-Boot架构总览
U-Boot采用典型的两阶段启动架构,并在此基础上引入了SPL(Secondary Program Loader)或TPL(Tertiary Program Loader)来适应SoC内部SRAM容量有限的约束。整体可分为以下几个层次:
- ROM Code:芯片出厂固化的引导代码,负责从启动介质加载第一级引导程序。
- SPL/TPL:运行在片内SRAM中,完成DDR初始化、时钟配置,然后加载完整的U-Boot到DDR。
- U-Boot Proper:运行在DDR中的完整引导程序,提供命令行、驱动模型、文件系统访问与内核加载能力。
- 驱动模型(DM):统一设备驱动框架,支持设备树描述、驱动绑定与生命周期管理。
U-Boot的源码目录结构也体现了这种分层:arch/存放体系结构相关代码,board/存放板级初始化,drivers/存放各类外设驱动,common/存放通用命令与启动逻辑,cmd/存放命令实现,env/存放环境变量后端。
二、启动模式与启动流程
U-Boot支持多种启动模式,常见包括:正常启动模式、下载模式、恢复模式和安全启动模式。正常启动模式下,U-Boot按bootcmd定义的顺序尝试从eMMC、SD卡、网络等介质加载内核;下载模式则通过串口、USB或网络将镜像传输到内存中再执行;恢复模式常用于系统损坏时通过外部介质重新烧录。
以典型ARM SoC为例,启动流程如下:
ROM Code → 加载SPL到SRAM → SPL初始化DDR → 加载U-Boot到DDR
→ U-Boot Proper运行 → board_init_f → board_init_r
→ 驱动模型初始化 → 控制台就绪 → 执行bootcmd
→ 加载内核与设备树 → 跳转内核入口
其中bootcmd是启动的核心环境变量,通常包含一系列命令,例如:
setenv bootcmd 'mmc dev 0; fatload mmc 0:1 0x80008000 zImage; \
fatload mmc 0:1 0x83000000 sun8i-h3-nanopi.dtb; \
bootz 0x80008000 - 0x83000000'
三、环境变量机制
环境变量是U-Boot的“配置数据库”,以键值对形式存储,分为默认环境和持久化环境。默认环境编译进U-Boot镜像,持久化环境则保存在MMC、SPI Flash、NAND或FAT文件中。常用变量包括:
| 变量名 | 作用 | 典型值 |
|---|---|---|
| bootcmd | 自动启动命令序列 | mmc dev 0; fatload ...; bootz ... |
| bootargs | 传递给内核的启动参数 | console=ttyS0,115200 root=/dev/mmcblk0p2 rw |
| ipaddr | U-Boot自身IP地址 | 192.168.1.100 |
| serverip | TFTP服务器地址 | 192.168.1.10 |
| baudrate | 串口波特率 | 115200 |
| bootdelay | 自动启动倒计时秒数 | 3 |
saveenv才能写入持久化存储,否则重启后丢失。若环境变量损坏,可通过env default -a恢复默认值。
四、命令体系与板级初始化
U-Boot命令体系采用U_BOOT_CMD宏注册,每个命令包含名称、最大参数数、是否可重复、帮助文本和执行函数。常用命令可分为:
- 启动类:
boot、bootm、bootz、booti - 存储类:
mmc、nand、sf、fatload、ext4load - 网络类:
tftp、ping、dhcp、nfs - 环境类:
setenv、printenv、saveenv、env - 调试类:
md、mw、mmc info、bdinfo
板级初始化分为两个阶段:board_init_f负责早期硬件初始化,包括时钟、DDR、串口和重定位准备;board_init_r负责后期初始化,启动驱动模型、探测设备、初始化控制台,最终进入主循环。驱动模型通过UCLASS和UDEVICE抽象设备,配合设备树实现驱动与硬件的解耦。
bootargs中的root=参数直接决定根文件系统挂载位置,若与分区表不一致,内核将无法挂载根文件系统。
五、案例:从eMMC启动完整流程
假设目标板使用eMMC启动,分区为:mmcblk0p1为FAT引导分区,mmcblk0p2为ext4根文件系统。U-Boot环境变量配置如下:
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw'
setenv bootcmd 'mmc dev 0; fatload mmc 0:1 0x80008000 zImage; \
fatload mmc 0:1 0x83000000 sun8i-h3-nanopi.dtb; \
bootz 0x80008000 - 0x83000000'
saveenv
启动时U-Boot依次执行:初始化eMMC控制器、读取FAT分区中的内核与设备树、将bootargs写入内核启动参数、跳转内核入口。内核启动后根据root=/dev/mmcblk0p2挂载根文件系统,完成从Bootloader到用户空间的交接。
理解U-Boot的架构、启动模式、环境变量、命令体系与驱动模型,是后续进行分区规划、根文件系统制作与启动优化的重要基础。只有将Bootloader与根文件系统的参数、分区布局、存储介质统一考虑,才能构建稳定可靠的嵌入式Linux启动链路。