【DeepSeek】U-Boot 引导加载流程详细分析
U-Boot 引导加载流程详细分析
本文档详细分析了 U-Boot 的引导加载流程,包括从系统加电到将控制权转移给操作系统内核的完整过程。
1. 系统启动概述
U-Boot 的引导加载流程可以分为以下几个主要阶段:
- 硬件初始化阶段:初始化 CPU、内存、时钟等基本硬件
- 设备初始化阶段:初始化各种外设,如串口、存储设备、网络设备等
- 引导准备阶段:加载环境变量、解析配置信息
- 内核加载阶段:从存储设备或网络加载操作系统内核
- 启动参数准备阶段:准备内核启动参数和设备树
- 控制权转移阶段:将控制权转移给操作系统内核
2. 详细引导流程
2.1 硬件初始化阶段
当系统加电或复位时,CPU 会从预定义的地址开始执行代码。对于 U-Boot,这个过程通常从架构特定的 start.S 文件开始:
- 复位向量:CPU 从复位向量开始执行,通常位于闪存的起始地址
- 基本硬件初始化:
- 禁用中断
- 设置 CPU 模式(如 ARM 架构的 SVC 模式)
- 配置时钟和内存控制器
- 初始化堆栈
- 内存初始化:
- 配置 DRAM 控制器
- 测试和初始化内存
- 将 U-Boot 从闪存复制到内存中运行(如果需要)
2.2 设备初始化阶段
在硬件基本初始化完成后,U-Boot 会初始化各种外设:
- 串口初始化:配置串口波特率,用于输出调试信息
- 存储设备初始化:
- 初始化 MMC/SD 卡控制器
- 初始化 NOR/NAND 闪存控制器
- 初始化 SATA/SCSI 控制器(如果有)
- 网络设备初始化:
- 初始化以太网控制器
- 配置网络参数(IP 地址、网关等)
- 其他设备初始化:根据板级配置初始化其他必要的设备
2.3 引导准备阶段
设备初始化完成后,U-Boot 会进行引导前的准备工作:
- 加载环境变量:
- 从非易失性存储(如闪存、EEPROM)加载环境变量
- 如果环境变量损坏或不存在,使用默认环境变量
- 解析配置信息:
- 读取板级配置信息
- 解析引导命令和参数
- 显示启动信息:
- 显示 U-Boot 版本信息
- 显示板级信息和硬件配置
- 显示内存配置信息
2.4 内核加载阶段
引导准备完成后,U-Boot 会根据配置加载操作系统内核:
- 确定引导设备:
- 根据环境变量
bootcmd或用户输入确定引导设备 - 可能的引导设备包括:MMC/SD 卡、NAND 闪存、网络(TFTP)、USB 等
- 根据环境变量
- 加载内核镜像:
- 从引导设备读取内核镜像到内存指定位置
- 支持多种镜像格式,如 zImage、uImage、FIT 镜像等
- 加载设备树:
- 从引导设备读取设备树文件(.dtb)到内存
- 或者使用内置的设备树
- 验证镜像:
- 检查镜像的完整性(如校验和)
- 对于安全启动,验证镜像的数字签名
2.5 启动参数准备阶段
内核镜像加载完成后,U-Boot 会准备内核启动参数:
- 设置内核命令行参数:
- 根据环境变量
bootargs设置内核命令行 - 命令行参数包括根文件系统位置、控制台设备、调试选项等
- 根据环境变量
- 准备设备树:
- 调整设备树内容(如修改内存大小、添加节点等)
- 将设备树地址传递给内核
- 设置启动参数结构:
- 按照内核要求的格式准备启动参数
- 对于 ARM 架构,使用 ATAGs 或设备树
2.6 控制权转移阶段
一切准备就绪后,U-Boot 会将控制权转移给操作系统内核:
- 设置内核启动环境:
- 禁用中断
- 刷新缓存
- 设置 CPU 模式和状态
- 跳转到内核入口:
- 对于 ARM 架构,调用
bootm或bootz命令 - 传递内核地址、设备树地址和启动参数地址
- 对于 ARM 架构,调用
- 内核接管:
- 内核开始执行初始化代码
- U-Boot 的使命完成
3. 引导设备类型
U-Boot 支持从多种设备加载内核:
3.1 存储设备
-
MMC/SD 卡:
- 命令:
mmc read、fatload、ext2load等 - 示例:
fatload mmc 0:1 0x80000000 uImage
- 命令:
-
NAND 闪存:
- 命令:
nand read - 示例:
nand read 0x80000000 0x200000 0x400000
- 命令:
-
NOR 闪存:
- 命令:
cp.b - 示例:
cp.b 0x1000000 0x80000000 0x400000
- 命令:
-
SATA 设备:
- 命令:
sata read、ext2load等 - 示例:
ext2load sata 0:1 0x80000000 /boot/uImage
- 命令:
3.2 网络设备
-
TFTP:
- 命令:
tftpboot - 示例:
tftpboot 0x80000000 uImage
- 命令:
-
NFS:
- 命令:
nfs - 示例:
nfs 0x80000000 192.168.1.100:/nfsroot/uImage
- 命令:
3.3 其他设备
-
USB 设备:
- 命令:
usb start、fatload等 - 示例:
usb start; fatload usb 0:1 0x80000000 uImage
- 命令:
-
串口:
- 命令:
loady - 示例:
loady 0x80000000
- 命令:
4. 引导命令分析
U-Boot 提供了丰富的引导命令,用于加载和启动内核:
4.1 bootm 命令
用于启动 uImage 格式的内核:
bootm [addr [arg ...]]
addr:内核镜像在内存中的地址arg:可选参数,如设备树地址
4.2 bootz 命令
用于启动 zImage 格式的内核:
bootz [addr [initrd[:size]] [fdt]]
addr:内核镜像在内存中的地址initrd: initramfs 地址(可选)fdt:设备树地址(可选)
4.3 bootefi 命令
用于启动 EFI 格式的内核:
bootefi image_addr [fdt_addr]
image_addr:EFI 镜像在内存中的地址fdt_addr:设备树地址(可选)
4.4 run 命令
用于执行环境变量中定义的命令序列:
run var [...]
var:环境变量名称,如bootcmd
5. 环境变量与引导配置
U-Boot 使用环境变量来配置引导行为:
5.1 关键环境变量
| 环境变量 | 描述 | 示例值 |
|---|---|---|
| bootcmd | 自动引导命令 | mmc dev 0; fatload mmc 0:1 0x80000000 uImage; bootm 0x80000000 |
| bootargs | 内核命令行参数 | console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait |
| bootdelay | 自动引导延迟时间(秒) | 3 |
| serverip | TFTP 服务器 IP 地址 | 192.168.1.100 |
| ipaddr | 设备 IP 地址 | 192.168.1.10 |
| netmask | 网络掩码 | 255.255.255.0 |
| gatewayip | 网关 IP 地址 | 192.168.1.1 |
5.2 配置示例
# 设置引导命令
setenv bootcmd "mmc dev 0; fatload mmc 0:1 0x80000000 uImage; fatload mmc 0:1 0x81000000 dtb; bootm 0x80000000 - 0x81000000"
# 设置内核命令行
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait"
# 保存环境变量
saveenv
6. 设备树处理
设备树(Device Tree)是 U-Boot 和 Linux 内核之间传递硬件配置信息的重要方式:
6.1 设备树加载
-
从存储设备加载:
fatload mmc 0:1 0x81000000 board.dtb -
内置设备树:
- U-Boot 可以将设备树编译到镜像中
- 使用
bootm命令时自动使用内置设备树
6.2 设备树修改
U-Boot 提供了 fdt 命令来修改设备树:
# 查看设备树节点
fdt list /
# 修改设备树属性
fdt set /memory reg <0x80000000 0x20000000>
# 添加设备树节点
fdt mknode / new_node
7. 安全启动
U-Boot 支持安全启动功能,确保引导过程的安全性:
-
数字签名验证:
- 使用密钥对引导镜像进行签名
- 启动时验证镜像的签名
-
安全启动配置:
- 启用 CONFIG_SECURE_BOOT 选项
- 配置密钥存储位置
-
安全启动流程:
- 验证 U-Boot 自身的签名
- 验证内核镜像的签名
- 验证设备树的签名
8. 常见问题与解决方案
8.1 内核加载失败
症状:U-Boot 无法从存储设备加载内核
解决方案:
- 检查存储设备是否正确初始化
- 检查内核镜像路径是否正确
- 检查存储设备分区是否正确
8.2 内核启动失败
症状:内核加载成功但无法正常启动
解决方案:
- 检查内核命令行参数是否正确
- 检查设备树是否与硬件匹配
- 检查内核镜像是否与硬件架构匹配
8.3 网络引导失败
症状:无法通过网络加载内核
解决方案:
- 检查网络连接是否正常
- 检查 TFTP 服务器是否运行
- 检查 IP 地址配置是否正确
9. 代码分析
9.1 启动流程代码
U-Boot 的启动流程主要在以下文件中实现:
-
架构特定启动代码:
arch/<arch>/cpu/<cpu>/start.S:CPU 启动代码arch/<arch>/lib/board.c:板级初始化代码
-
通用启动代码:
common/board_f.c:第一阶段初始化common/board_r.c:第二阶段初始化common/main.c:主函数
-
引导命令代码:
cmd/bootm.c:bootm 命令实现cmd/bootz.c:bootz 命令实现
9.2 关键函数
- board_init_f():第一阶段初始化函数,初始化硬件
- board_init_r():第二阶段初始化函数,初始化设备和环境
- do_bootm():bootm 命令处理函数
- do_bootz():bootz 命令处理函数
- boot_jump_linux():跳转到 Linux 内核
10. 总结
U-Boot 的引导加载流程是一个复杂但有序的过程,从硬件初始化到内核启动,每个阶段都有其特定的功能和职责。理解这个流程对于嵌入式系统开发和调试非常重要。
通过本文档的分析,我们可以看到 U-Boot 提供了灵活、强大的引导加载能力,支持多种设备和启动方式,能够满足不同嵌入式系统的需求。同时,U-Boot 的模块化设计也使得它易于定制和扩展,可以适应各种硬件平台。
掌握 U-Boot 的引导加载流程,对于嵌入式系统开发者来说是一项基本技能,有助于快速定位和解决引导相关的问题,提高系统开发效率。
更多推荐


所有评论(0)