嵌入式Linux之U-Boot

嵌入式Linux之U-Boot

1. 前言

1.1 为什么嵌入式离不开U-Boot?

嵌入式Linux无法直接启动内核,必须由Bootloader 完成硬件初始化、内存映射、内核加载、参数传递等前置工作。U-Boot(Universal Boot Loader)是当前嵌入式Linux最主流的开源Bootloader ,支持ARM/x86/RISC-V等多架构,兼容NAND/eMMC/SD/Flash等存储,解决了硬件初始化复杂、内核启动繁琐、多存储适配、量产调试四大核心痛点。

嵌入式启动痛点 U-Boot的解决思路
硬件未初始化,内核无法运行 初始化CPU/时钟/DDR/串口/存储,搭建内核运行环境
存储介质多样(SD/eMMC/NAND) 统一驱动接口,支持多介质加载内核与设备树
启动参数需灵活配置(串口/根文件系统/IP) 提供环境变量,动态修改启动参数无需重编译
量产烧录与现场调试 命令行交互,支持烧写、读取、校验镜像

1.2 U-Boot核心定位

U-Boot是硬件与Linux内核之间的桥梁,是嵌入式系统上电后第一个运行的软件,核心职责:

  • 初始化核心硬件,让系统从"裸机"进入"可运行内核"状态
  • 提供交互式命令行,用于调试、烧录、配置启动策略
  • 从存储加载Linux内核(zImage/uImage)与设备树(dtb)到内存
  • 传递启动参数(bootargs)给内核,完成内核启动

1.3 嵌入式Linux标准启动流程

Boot ROM → U-Boot → Linux Kernel → Root Filesystem

启动阶段 运行载体 核心工作
Boot ROM 芯片内置ROM 上电自动运行,检测启动介质,加载U-Boot前导程序
U-Boot DDR 初始化硬件、加载内核、传递参数、启动内核
Linux Kernel DDR 内核初始化、驱动加载、挂载根文件系统
Rootfs 存储/内存 启动init进程,运行应用程序

2. U-Boot核心基础

2.1 核心功能

  1. 硬件初始化:CPU、PLL、DDR、GPIO、串口、以太网、存储控制器
  2. 交互控制:串口命令行,支持在线调试与配置
  3. 镜像管理:读取/烧写/校验内核、设备树、文件系统镜像
  4. 启动引导:支持从SD/eMMC/NAND/网络启动内核
  5. 环境变量 :动态配置启动参数、设备路径、网络信息

2.2 关键特性

  • 开源免费,社区活跃,支持绝大多数嵌入式处理器
  • 轻量级,体积小,适配嵌入式资源受限场景
  • 可裁剪,通过配置关闭无用功能,减小体积
  • 跨平台,同一套源码支持多架构、多开发板

3. U-Boot完整启动流程

U-Boot启动分为汇编阶段C语言阶段 ,先底层初始化,再高层功能初始化,最后启动内核。

3.1 第一阶段:汇编初始化(arch/arm/cpu/start.S)

核心目标:关中断、关MMU、初始化栈、最小硬件初始化、跳转到C语言

  1. 关闭CPU中断与MMU,进入裸机运行模式

  2. 初始化CPU时钟与栈指针(SP),为C语言运行准备环境

  3. 初始化DDR控制器(最关键,没有DDR无法运行C语言)

  4. 复制U-Boot自身到DDR(部分芯片需要)

  5. 跳转到C语言入口函数board_init_f

3.2 第二阶段:C语言初始化(board_init_r)

核心目标:初始化外设、命令系统、环境变量、准备启动内核

  1. 初始化串口、以太网、存储(SD/eMMC/NAND)等外设
  2. 初始化命令系统,支持串口交互
  3. 加载环境变量(从Flash/SD/eMMC)
  4. 自动检测启动介质,执行默认启动命令
  5. 等待用户输入命令,或自动启动内核

3.3 启动内核流程

  1. 读取环境变量bootcmd,执行启动命令
  2. 从存储加载zImage(内核)与dtb(设备树)到DDR指定地址
  3. 设置bootargs启动参数,告诉内核串口、根文件系统路径
  4. 调用bootz/bootm命令,跳转到内核入口,移交控制权

4. U-Boot源码编译与配置

4.1 源码获取

bash 复制代码
# 官方源码(推荐稳定版)
git clone https://github.com/u-boot/u-boot.git
cd u-boot
# 切换到稳定版本
git checkout v2023.10

4.2 配置命令

bash 复制代码
# 清理旧配置
make distclean
# 加载开发板默认配置(以IMX6ULL为例)
make mx6ull_14x14_evk_defconfig
# 图形化配置(可选)
make menuconfig

4.3 编译命令

bash 复制代码
# 交叉编译(指定ARM交叉编译器)
make CROSS_COMPILE=arm-linux-gnueabihf- -j4

4.4 编译产物说明

产物文件 作用 烧录位置
u-boot.bin 二进制镜像,直接烧录到存储 启动介质起始位置
u-boot.img 带头部信息的镜像,部分芯片专用 芯片指定偏移地址
MLO 部分芯片(TI AM335x)的前导程序 存储起始位置
u-boot.dtb U-Boot自身设备树(非内核dtb) 无需烧录,调试用

5. U-Boot高频实用命令

5.1 信息查询类

命令 作用
version 查看U-Boot版本
bdinfo 查看板级信息(DDR大小、MAC地址)
printenv 查看所有环境变量

5.2 环境变量类

命令 作用 示例
setenv 设置环境变量 setenv bootdelay 3
saveenv 保存环境变量到存储 saveenv
editenv 编辑环境变量 editenv bootargs

5.3 存储操作类

命令 作用 示例
mmc list 列出MMC/SD设备 mmc list
mmc dev 0 切换到SD卡0 mmc dev 0
fatload 从FAT分区读取文件到DDR fatload mmc 0:1 0x80800000 zImage
nand write 烧写镜像到NAND Flash nand write 0x80800000 kernel 0x500000

5.4 启动控制类

命令 作用 适用场景
bootz 启动zImage格式内核 ARM Linux主流
bootm 启动uImage格式内核 旧版内核
boot 执行bootcmd自动启动 量产默认启动

6. U-Boot设备树(DTB)

设备树是描述硬件信息的文件,U-Boot负责加载dtb到内存并传递给内核,内核无需重编译即可适配不同硬件。

6.1 核心作用

  • 分离硬件描述与内核代码,提升内核可移植性
  • 描述CPU、DDR、外设、中断、GPIO等硬件信息
  • U-Boot传递dtb地址给内核,内核解析后初始化硬件

6.2 加载设备树命令

bash 复制代码
# 从SD卡加载dtb到DDR 0x83000000
fatload mmc 0:1 0x83000000 imx6ull-14x14-evk.dtb

7. 启动Linux内核

SD卡启动ARM Linux为例,完整命令流程:

bash 复制代码
# 1. 设置启动参数(串口、根文件系统)
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
# 2. 加载内核到DDR 0x80800000
fatload mmc 0:1 0x80800000 zImage
# 3. 加载设备树到DDR 0x83000000
fatload mmc 0:1 0x83000000 imx6ull-14x14-evk.dtb
# 4. 启动内核(内核地址 + dtb地址)
bootz 0x80800000 - 0x83000000
# 5. 保存配置,下次自动启动
setenv bootcmd 'fatload mmc 0:1 0x80800000 zImage; fatload mmc 0:1 0x83000000 imx6ull-14x14-evk.dtb; bootz 0x80800000 - 0x83000000'
saveenv

8. U-Boot移植核心要点

U-Boot移植是适配新开发板的核心工作,重点修改4个部分:

  1. DDR初始化
    修改板级配置文件(board/freescale/mx6ullevk/),配置DDR参数(时序、位宽、容量),这是移植成败关键
  2. 时钟配置
    修改CPU PLL时钟参数,保证系统稳定运行。
  3. 存储驱动
    适配SD/eMMC/NAND控制器,确保能读写存储介质。
  4. 环境变量存储
    指定环境变量保存位置(SD/eMMC/NAND),确保配置断电不丢失。

9. 常见问题与排查

9.1 无串口输出

  • 排查:串口参数(115200 8N1)、串口线连接、U-Boot串口初始化配置
  • 解决:检查board_config.h中串口宏定义,确保串口时钟配置正确

9.2 DDR初始化失败

  • 现象:U-Boot运行到DDR初始化就死机
  • 解决:重新校准DDR时序参数,核对硬件原理图与配置参数

9.3 无法加载内核

  • 排查:存储设备选择错误、镜像路径错误、DDR地址冲突
  • 解决:用mmc list确认存储设备,核对fatload地址与内核大小

9.4 内核启动后死机

  • 排查:bootargs参数错误、dtb与内核不匹配、根文件系统异常
  • 解决:核对root=/dev/xxx路径,确保dtb与内核版本一致

10. 总结

  1. 核心定位 :U-Boot是嵌入式Linux的启动基石,负责硬件初始化与内核引导
  2. 启动流程:汇编底层初始化 → C语言高层初始化 → 加载内核 → 启动内核
  3. 实战核心:环境变量配置、存储操作、内核+dtb加载、启动命令执行
  4. 移植关键:DDR初始化、时钟配置、存储驱动、环境变量存储
  5. 设计原则:轻量级、可裁剪、适配硬件、稳定可靠
相关推荐
程序设计实验室1 小时前
从挖矿木马入侵到 Docker Rootless 加固,我的服务器安全复盘
linux·docker
雷电法拉珑1 小时前
财务数据批量采集
linux·前端·python
fjh19972 小时前
使用caddy签发ip证书
运维·服务器
Roc.Chang3 小时前
Vite 启动报错:listen EACCES: permission denied 0.0.0.0:80 解决方案
linux·前端·vue·vite
暴力求解3 小时前
Linux进程(六)命令行参数
linux·运维·服务器
我怎么又饿了呀3 小时前
Linux 下 的Vim/Vi 操作指南
linux·运维·vim
今儿敲了吗3 小时前
23| 画展
c++·笔记·学习·算法
野犬寒鸦4 小时前
深入解析HashMap核心机制(底层数据结构及扩容机制详解剖析)
java·服务器·开发语言·数据库·后端·面试
我 see your eyes4 小时前
工作软件学习
学习