U-Boot

一、U-Boot 是什么?

U-Boot 是一个裸机程序 ,属于 bootloader 的一种。它的核心作用是引导 Linux 或其他操作系统 ,最主要的工作是初始化 DDR 内存,因为操作系统内核需要在 DDR 中运行。

二、系统整体启动流程

复制代码
芯片上电
    ↓
BootROM(芯片内部ROM)
    ↓
BL1 / SPL(片上SRAM)
    ↓
BL2 / U-Boot(DDR)
    ↓
Linux Kernel(DDR)
    ↓
Rootfs(存储设备)
阶段 运行位置 主要作用
BootROM 芯片内部ROM 启动第一级程序(芯片厂商固化,不可修改)
BL1 / SPL 片上SRAM 初始化基础硬件(时钟、DDR),为加载完整U-Boot做准备
BL2 / U-Boot DDR 完成全部系统初始化,引导Linux内核
Kernel DDR 启动Linux操作系统
Rootfs 存储设备(eMMC/NAND/SD等) 提供用户空间和应用程序运行环境

三、基本引导流程详解(多级启动)

1. BootROM(芯片厂商固化)

  • 位置:芯片内部ROM,物理不可修改。
  • 上电后CPU首先执行BootROM,不依赖任何外部存储。
  • 主要工作
    • CPU最基础初始化:复位处理、设置基本运行状态、初始化关键寄存器。
    • 根据配置引脚或启动介质选择器,查找并确定启动设备(SPI Flash、NAND Flash、eMMC、SD卡等)。
    • 从选定的启动设备中加载第一级Bootloader(BL1/SPL) 到内部SRAM,然后跳转执行。

2. 为什么需要多级启动?

内部SRAM容量有限(通常几十KB~几百KB),而DDR在启动初期尚未初始化。 因此需要分阶段加载,先用小体积的SPL初始化DDR,再将完整的U-Boot加载到DDR中运行。

3. 启动链

复制代码
ROM  →  SPL  →  U-Boot  →  Linux
       (BL1)    (BL2)

每一级负责加载并验证(可选)下一级,将控制权逐级传递。

四、U-Boot 的代码执行阶段

U-Boot 被 SPL 加载到DDR后,其内部执行流程分为以下四个阶段:

复制代码
① 汇编阶段 (start.S)
       ↓
② C语言阶段(重定位前)(board_init_f)
       ↓
③ 重定位阶段 (relocate_code)
       ↓
④ C语言阶段(重定位后)(board_init_r → main_loop)

① 汇编阶段(start.S)

  • 入口文件arch/arm/cpu/armv8/start.S(以ARM64为例)
  • 主要工作
    • 设置异常向量表
    • 关闭中断、关闭MMU、关闭Cache
    • 初始化C运行环境(设置栈指针)
  • 最终跳转board_init_f()

② C语言阶段------重定位前(board_init_f)

  • 入口函数common/board_f.c 中的 board_init_f()
  • 阶段特点:此时U-Boot已在运行,但尚未搬到DDR中的最终运行地址。
  • 主要任务
    • 初始化串口、定时器等基础硬件
    • 初始化全局数据结构(GD,Global Data),包含CPU信息、内存信息、环境变量地址、重定位地址等
    • 规划内存布局,计算U-Boot在DDR顶部的重定位目标地址
  • 结束 :调用 relocate_code() 进入重定位

③ 重定位阶段(relocate_code)

  • 主要工作
    • 将U-Boot代码从当前运行位置(通常为SRAM或DDR底部临时区域)搬移到DDR中规划好的最终运行地址(通常在高地址处)
    • 修正代码中的重定位地址偏移
    • 更新运行环境(如全局数据结构中的指针)
    • 跳转到新地址继续执行

重定位的目的:将U-Boot放到DDR的高端地址,把低端内存留给内核使用,避免地址冲突。

④ C语言阶段------重定位后(board_init_r → main_loop)

  • 入口函数common/board_r.c 中的 board_init_r()
  • 阶段特点:U-Boot已运行在DDR中,拥有完整的运行环境。
  • 主要任务
    • 初始化所有外设和驱动(MMC、NAND、网络、USB等)
    • 加载并解析环境变量(从存储介质中读取)
  • 最终进入main_loop()(U-Boot命令行主循环),等待用户输入或自动执行 bootcmd 启动内核。

五、引导 Linux 内核

1. U-Boot在Linux启动中的作用

准备Linux运行环境(内存、设备树、启动参数),然后跳转到Linux内核入口执行,U-Boot不再控制CPU。

2. 启动前准备

内容 作用 存放位置
Kernel镜像 Linux内核程序(Image/uImage/zImage) DDR中指定地址
DTB设备树 描述硬件平台信息(外设、中断、内存映射等) DDR中指定地址
bootargs启动参数 告诉Linux根文件系统位置、控制台、内存配置等 通过DTB的chosen节点传递

3. 引导执行流程

text

复制代码
booti / bootm 命令
       ↓
检查Kernel镜像格式(magic number、头部信息)
       ↓
准备启动参数(从环境变量 bootargs 获取)
       ↓
传递DTB地址给内核(通过寄存器 x0/x1/x2 或约定地址)
       ↓
跳转到Kernel入口地址(CPU完全交给Linux)
       ↓
Linux接管CPU,U-Boot不再控制

4. Kernel镜像加载方式(将内核放入DDR)

加载方式 示例命令
eMMC / SD(FAT分区) fatload mmc 0:1 0x42000000 Image
eMMC / SD(EXT4分区) ext4load mmc 0:2 0x42000000 Image
TFTP网络加载 tftp 0x42000000 Image
NAND Flash nand read 0x42000000 0x100000 0x400000(读NAND偏移0x100000,大小0x400000)

5. 关键信息传递:设备树与 bootargs

  • 设备树(DTB) :通过 bootibootm 命令的第三个参数传递DTB地址,内核启动时解析DTB获取硬件信息。
  • 启动参数(bootargs) :通过DTB的 chosen 节点传递,本质是一个字符串,常见格式如下:
参数 作用 示例
console 指定Linux控制台串口及波特率 console=ttyS0,115200
root 指定根文件系统位置 root=/dev/mmcblk0p2
rootfstype 指定根文件系统类型 rootfstype=ext4
rw / ro 根文件系统挂载为读写/只读 rw

示例bootargs

text

复制代码
console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4

6. 分区表

分区表描述存储设备(eMMC、NAND、SD卡)上各区域的位置和大小,为U-Boot提供寻址依据(如内核在哪个分区、设备树在哪个分区)。常见分区信息包括:分区名称、起始地址、大小、文件系统类型、分区编号。

分区表本身不直接传给内核,而是通过 bootargs 中的 root=/dev/mmcblk0pX 等方式让内核知道根文件系统位置。

六、U-Boot 环境变量与常用操作

⚠️ 注意 :以下命令均在 U-Boot Shell(命令行环境) 中执行,而非Linux系统内部。

1. 环境变量管理

  • 存储位置:eMMC的boot分区、NAND Flash、SPI Flash等(取决于配置)。
  • 核心环境变量
变量 作用
bootcmd 自启动命令(开机自动执行)
bootargs 传递给Linux的启动参数
serverip TFTP服务器IP(即开发电脑IP)
ipaddr 开发板自身IP
loadaddr 镜像加载到DDR的默认地址

2. 环境变量操作命令

操作 命令示例
查看所有变量 printenv
查看单个变量 printenv bootcmd
修改变量 setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2"
保存变量 saveenv(写入存储介质)

3. Flash / 存储操作

命令 功能 示例
mmc list 列出MMC设备 mmc list
mmc dev <n> 选择MMC设备 mmc dev 0
mmc read 从MMC读取 mmc read 0x42000000 0x800 0x1000(块号0x800,块数0x1000)
sf probe 初始化SPI Flash sf probe
sf read 从SPI Flash读取 sf read 0x42000000 0x100000 0x400000
nand info 查看NAND信息 nand info
nand read 从NAND读取 nand read 0x42000000 0x100000 0x400000

4. 网络操作

命令 功能 示例
setenv serverip 设置TFTP服务器IP setenv serverip 192.168.1.100
setenv ipaddr 设置开发板IP setenv ipaddr 192.168.1.50
tftp 通过TFTP下载文件到DDR tftp 0x42000000 Image
ping 测试网络连通性 ping 192.168.1.100

5. 内存 / 文件系统操作

命令 功能 示例
md 读内存(dump) md.l 0x42000000 10(以32位读10个数据)
mw 写内存 mw.l 0x42000000 0x12345678 1
fatload 从FAT分区加载文件 fatload mmc 0:1 0x42000000 Image
ext4load 从EXT4分区加载文件 ext4load mmc 0:2 0x42000000 Image

6. 引导操作

命令 适用架构 用法
booti ARM64 booti <内核地址> <initrd地址> <设备树地址>
示例:booti 0x42000000 - 0x43000000-表示无initrd)
bootm ARM32(支持设备树) bootm <内核地址> [initrd地址] [设备树地址]
示例:bootm 0x42000000 - 0x43000000

七、安全启动(Secure Boot)

  • 核心思想:建立信任链,防止未经授权的代码运行。从芯片内部不可修改的信任根(Root of Trust)开始,逐级验证后续镜像的签名。
  • 信任根:系统中最初可信的软件或硬件基础,即BootROM内固化的公钥或公钥哈希。
  • 验证链

text

复制代码
BootROM(固化公钥) →  验证SPL签名  →  SPL
SPL(携带公钥)     →  验证U-Boot签名 →  U-Boot
U-Boot(携带公钥)  →  验证内核签名   →  内核(FIT Image)
  • 关键技术
    • 镜像签名 :使用私钥对镜像生成数字签名,设备端用公钥验证,确认镜像完整未被篡改来源可信
    • 验证流程:计算镜像Hash值 + 用公钥解密签名比对Hash,两者一致则验证通过。
    • FIT Image:U-Boot提供的一种带有描述信息(.its文件)和数字签名支持的镜像格式,可同时包含内核、设备树、ramdisk等多个组件,统一管理并签名。

八、补充说明

U-Boot 与 Linux 的命令区分

环境 提示符 常见命令示例
U-Boot Shell => printenvsetenvfatloadbooti
Linux Shell #$ lscatifconfigmount

两者命令完全不同,不要混淆。 U-Boot中不存在 lscat 等Linux命令。

常见术语解释

术语 解释
SPL(Secondary Program Loader) 二级加载器,在SRAM中运行,负责初始化DDR并加载完整U-Boot
SRAM 芯片内部静态随机存储器,容量小但速度快,上电即可使用
DDR 外部动态随机存储器,容量大,需初始化后才能使用
DTB(Device Tree Blob) 设备树二进制文件,描述硬件信息
FIT(Flattened Image Tree) U-Boot的统一镜像格式,支持多组件打包和签名

相关推荐
无垠的广袤2 小时前
【RA-Eco-RA4M2开发板】步进电机的串口控制和 LabVIEW 数据采集
单片机·嵌入式硬件·labview
茯苓gao3 小时前
嵌入式开发笔记:QSerialPort 完整使用指南——从基础 API 到工程实战
笔记·嵌入式硬件·qt·学习
Mr+范3 小时前
单片机 ADC 电压与电流检测及电阻选型指南
单片机·嵌入式硬件
西城微科方案开发4 小时前
LCD智能婴儿秤方案
单片机·嵌入式硬件
三佛科技-134163842126 小时前
灭蚊灯MCU方案开发,FT60E112-RB作为灭蚊灯主控芯片优势
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
起床学FPGA6 小时前
I2C、SPI
单片机·嵌入式硬件
xuxie996 小时前
start10 电机电流检测方法
单片机·嵌入式硬件
风雨中的蜜蜂6 小时前
CMT2310A 超低功耗高性能射频收发器概述
stm32·单片机·嵌入式硬件
LCG元7 小时前
STM32 ADC 多通道 DMA 采样与数字滤波实战
stm32·嵌入式硬件·microsoft