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 启动链路与架构分层 ROM Code 芯片固化 · 加载SPL SPL / TPL DDR初始化 · 时钟配置 U-Boot Proper 命令行 · 加载内核 Linux Kernel 挂载根文件系统 U-Boot Proper 内部功能模块 命令体系 (cmd/) boot / bootm / bootz loadb / tftp / mmc env / setenv / saveenv 环境变量 (env/) bootcmd / bootargs ipaddr / serverip 存储后端:MMC / SPI / FAT 驱动模型 (DM) UCLASS / UDEVICE 设备树绑定 · 驱动探测 串口 / MMC / 网络 / GPIO 板级初始化流程 (board_init_f → board_init_r) 早期初始化:时钟 / DDR / 串口 / 环境变量重定位 后期初始化:驱动模型启动 / 设备探测 / 控制台就绪 进入主循环:解析 bootcmd → 加载内核 → 启动 命令体系 环境变量 驱动模型 板级初始化

二、启动模式与启动流程

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
ipaddrU-Boot自身IP地址192.168.1.100
serveripTFTP服务器地址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抽象设备,配合设备树实现驱动与硬件的解耦。

误区:很多开发者认为U-Boot只是“加载内核的工具”,忽略了环境变量与驱动模型对启动稳定性的影响。实际上,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启动链路。