介绍
U-Boot 就是嵌入式芯片的「开机引导程序」,相当于电脑的 BIOS + 启动管理器,是芯片上电后第一个跑起来的软件。整个流程如下:上电 → 硬件复位 → U-Boot 启动 → 初始化硬件 → 加载 Linux 内核 → 内核启动 → 跑系统 / 应用。顺序:CPU 裸机 → U-Boot → Linux 内核 → 根文件系统
U-Boot 主要做 4 件核心事
底层硬件初始化(最关键)
刚上电时内存、时钟、闪存、串口、EMMC/NAND 都处于未初始化状态,U-Boot 先把它们跑起来:配置系统时钟、PLL、电压。初始化 DDR 内存(必须先初始化,内核才能运行)。初始化 Flash、EMMC、SD 卡、串口、网口。配置引脚、电源管理。
选择并加载系统镜像
U-Boot 会按预设顺序找系统:SD 卡 → EMMC → NAND Flash,然后把 Linux 内核 (zImage/Image)、设备树 (dtb) 读到 DDR 内存里。
传递启动参数给 Linux 内核
U-Boot 会把:内存大小;根文件系统位置(EMMC 哪个分区);
串口控制台、波特率
硬件标识
这些参数传给内核,内核才能正常挂载根文件系统、识别硬件。
4. 人机交互 & 调试(命令行)
上电倒计时按空格 / 回车,就能进入 U-Boot 命令行,常用操作:
查看内存、Flash、分区
读写 Flash、烧录固件
网络下载(tftp)更新镜像
切换启动介质、修改启动参数
恢复出厂、擦除分区
基础命令
环境变量相关
| 完整命令 | 等价简写 | 功能说明 | 常用用法 |
|---|---|---|---|
env print | printenv/print | 查看环境变量 | 查看所有:env print查看单个:env print bootargs |
env set | setenv/set | 设置 / 修改 / 删除环境变量 | 设置变量:env set bootargs 'console=ttymxc0,115200'删除变量:env set 变量名 |
env save | saveenv/save | 保存变量到存储介质(永久生效) | 直接执行:env save |
内存相关
| 命令 | 全称 | 功能说明 | 基础语法 | 常用示例 |
|---|---|---|---|---|
md | memory display | 读取并显示指定内存区域的数据 | md[.b/.w/.l] 起始地址 数量 | md.l 0x80000000 20以 4 字节为单位,显示0x80000000开始的 20 个长字数据 |
mm | memory modify | 交互式逐地址修改内存内容,回车自动跳到下一个地址 | mm[.b/.w/.l] 起始地址 | mm.l 0x80000000进入交互模式,输入数值后回车修改下一个地址,输入q退出 |
mw | memory fill | 批量填充指定内存区域,最常用于内存清零 | mw[.b/.w/.l] 起始地址 填充值 数量 | mw.l 0x80000000 0x0 0x400将0x80000000开始的 0x400 个长字(共 4KB 内存)全部清零 |
cp | memory copy | 将一段内存数据完整拷贝到另一个地址 | cp[.b/.w/.l] 源地址 目标地址 数量 | cp.l 0x80000000 0x82000000 0x1000将0x80000000开始的 0x1000 个长字(共 16KB)拷贝到0x82000000处 |
cmp | memory compare | 比较两段内存数据是否一致,常用于校验拷贝 / 下载结果 | cmp[.b/.w/.l] 地址1 地址2 数量 | cmp.l 0x80000000 0x82000000 0x1000比较两段 16KB 内存是否完全一致 |
mtest | memory test | 简单内存读写测试,用于校验 DDR 硬件稳定性 | mtest 起始地址 结束地址 测试值 迭代次数 | mtest 0x80000000 0x81000000测试0x80000000~0x81000000这段 16MB 内存的读写稳定性,按Ctrl+C停止 |
网络相关
| 命令名称 | 核心定位 | 基本语法 | 使用示例 | 关键注意事项 |
|---|---|---|---|---|
| ping | 网络操作的基础前提,专门测试开发板与目标主机的网络连通性,验证 IP、网卡、物理链路是否正常 | ping <目标IP地址> | ping 192.168.1.100验证与服务器是否网络互通 | 1. 跨网段测试需提前配置gatewayip网关地址;2.单向连通特性:仅支持 U-Boot 主动 ping 主机,主机无法 ping 通 U-Boot(U-Boot 无完整 TCP/IP 协议栈,不响应 ICMP 请求);3. 成功提示host xxx is alive,失败提示host xxx is not alive。 |
| dhcp | 核心功能是自动获取网络参数,向 DHCP 服务器申请 IP、子网掩码、网关、服务器 IP;下载文件只是附加扩展能力,底层复用 TFTP 协议 | dhcp [内存加载地址] [启动文件名] | 1.dhcp最核心用法:仅自动获取网络参数并更新环境变量;2.dhcp 0x42000000 zImage扩展用法:获取 IP 后顺带调用 TFTP 下载镜像到内存 | 1. DHCP 协议本身不具备文件传输能力,下载动作底层走 TFTP;2. 执行成功后自动更新ipaddr、serverip、netmask、gatewayip等环境变量;3. 局域网必须存在可用 DHCP 服务器,若服务器未配置next-server字段,则沿用当前serverip。 |
| tftp | U-Boot 阶段最核心的文件传输工具,专门负责将服务器上的内核、设备树等镜像下载到开发板内存,是网络启动的主力加载方式 | tftp <内存加载地址> [服务器IP:]<文件名> | 1.tftp 0x42000000 zImage从已配置的serverip对应服务器下载 zImage;2.tftp 0x42000000 192.168.1.100:zImage手动指定服务器 IP 下载文件 | 1. 主机需搭建 TFTP 服务(如 tftp-hpa、tftpd32),目标文件必须放在 TFTP 根目录下;2. 基于 UDP 协议,默认端口 69,轻量高效,是嵌入式开发阶段下载镜像的首选方案;3. 使用前需先用 ping 验证网络连通性,提前配置好serverip。 |
| nfs | 具备两级能力:1. U-Boot 阶段可加载单个文件到内存(少用,TFTP 更便捷);2.核心价值:Linux 内核启动后挂载远程完整根文件系统,替代本地 Flash 的 rootfs,是开发调试的黄金方案 | 1. U-Boot 加载文件:nfs <内存加载地址> [服务器IP:]<文件绝对路径>2. 内核挂载根文件系统:在bootargs中配置 NFS 根参数 | 1. U-Boot 加载文件:nfs 0x42000000 192.168.1.100:/home/nfs/zImage2. 内核挂载 NFS 根文件系统(bootargs 配置):setenv bootargs root=/dev/nfs nfsroot=192.168.1.100:/home/nfs/rootfs,proto=tcp rw ip=192.168.1.200 | 1. U-Boot 与 Linux 内核默认均支持NFSv2、NFSv3版本,服务器端需启用对应版本;2. 挂载根文件系统需要 Linux 内核编译时开启 NFS 客户端、NFS 根文件系统挂载支持;3. 服务器端需配置 NFS 目录读写权限,关闭防火墙与 SELinux;4. 挂载后修改根文件系统内容直接在服务器端操作,无需重新烧录镜像,大幅提升开发效率。 |
DHCP:负责自动分配 IP、传递启动服务器信息,是网络启动的辅助协议,本身不提供启动文件;TFTP:负责加载内核、设备树等启动镜像到开发板内存,是 U-Boot 阶段最常用的文件传输载体;NFS:既可以加载启动镜像,更核心的作用是提供远程根文件系统,让内核启动后直接挂载服务器上的文件系统。简单说:DHCP 配网络,TFTP 载内核,NFS 挂根文件系统,三者配合可以实现完整的 “从服务器启动整个 Linux 系统”,全程不需要把系统烧写到本地 Flash。
MMC相关
| 命令 | 核心功能 | 语法 | 使用示例 | 关键说明 |
|---|---|---|---|---|
| mmc list | 列出开发板识别到的所有 MMC 设备(SD 卡、eMMC),显示设备号和设备类型 | mmc list | => mmc list FSL_SDHC: 0 (SD) FSL_SDHC: 1 (eMMC) | 输出中的数字为设备号,如上 0 是 SD 卡,1 是 eMMC,不同硬件平台编号可能不同 |
| mmc dev | 切换当前操作的 MMC 设备,或查看当前选中的设备;后续所有 mmc 命令均作用于当前设备 | mmc dev [设备号] [:分区号] | 1. 查看当前设备:mmc dev2. 切换到 0 号 SD 卡:mmc dev 03. 切换到 eMMC 的第 2 分区:mmc dev 1:2 | 默认选中设备的第 0 分区(用户主分区);操作 eMMC 的 boot 硬件分区时需指定分区号 |
| mmc info | 查看当前选中设备的详细硬件信息,包括总容量、扇区总数、总线宽度、工作频率、版本等 | mmc info | mmc info | 用于确认设备是否正常识别、容量是否匹配,排查硬件识别异常 |
| mmc part | 查看当前设备的分区表,显示每个分区的起始扇区、总扇区数、分区类型 | mmc part | mmc part | 输出的「Start Sector」是后续读写分区数据的核心参考依据 |
| mmc rescan | 重新扫描 MMC 总线,重新识别设备 | mmc rescan | mmc rescan | 用于 SD 卡热插拔后重新识别,或设备识别异常时复位扫描 |
| 命令 | 核心功能 | 语法 | 使用示例 | 关键注意事项 |
|---|---|---|---|---|
| mmc read | 从 MMC 设备的指定扇区位置,读取指定数量的扇区数据到 DDR 内存指定地址 | mmc read <内存地址> <起始扇区号> <扇区数量> | # 从eMMC第20480扇区开始,读取1024个扇区到内存0x80800000 mmc read 0x80800000 20480 1024 | 1024 扇区 = 1024 × 512 = 512KB 数据;典型用途是从 eMMC 加载内核、设备树到内存启动 |
| mmc write | 将内存中的数据写入 MMC 设备的指定扇区,是烧写系统镜像的核心命令 | mmc write <内存地址> <起始扇区号> <扇区数量> | 配合 tftp 烧写内核:1. 下载镜像到内存:tftp 0x80800000 zImage2. 写入 eMMC 第 1 分区:mmc write 0x80800000 20480 12288 | 1. 扇区数量需向上取整,确保文件完整写入;2. 写入位置不能超出分区范围,避免覆盖其他数据;3. eMMC 写入无需提前擦除,可直接覆盖 |
| mmc erase | 擦除 MMC 设备上指定范围的扇区数据 | mmc erase <起始扇区号> <扇区数量> | # 擦除eMMC前1024个扇区 mmc erase 0 1024 | 仅用于彻底清空数据、擦除旧分区表;常规烧写镜像时不需要主动擦除 |
文件相关
| 命令名称 | 核心功能 | 基本语法 | 使用示例 | 关键注意事项 |
|---|---|---|---|---|
| fatinfo | 查看指定 FAT 分区的文件系统详细信息,验证分区格式是否正常识别 | fatinfo <接口> <设备号:分区号> | fatinfo mmc 0:1查看 SD 卡第 1 分区的 FAT 文件系统信息 | 输出包含文件系统类型、簇大小、总扇区数、FAT 表位置、根目录信息等;识别失败说明分区不是 FAT 格式或分区损坏 |
| fatls | 列出 FAT 分区内指定目录的文件和子目录,确认目标文件是否存在、路径是否正确 | fatls <接口> <设备号:分区号> [目录路径] | 1. 查看根目录:fatls mmc 0:12. 查看 boot 子目录:fatls mmc 0:1 /boot | 路径相对于分区根目录,省略路径默认查看根目录;未开启长文件名支持时,仅显示 8.3 格式短文件名 |
| fatload | 最核心命令:将 FAT 分区中的指定文件加载到 DDR 内存指定地址,常用于从 SD 卡加载内核、设备树 | fatload <接口> <设备号:分区号> <内存地址> <文件名> | fatload mmc 0:1 0x80800000 zImage将 SD 卡 1 分区的 zImage 加载到内存 0x80800000 | 1. 加载成功后自动设置filesize环境变量,记录文件字节大小,可直接引用;2. 内存地址必须在 DDR 有效范围内,不能覆盖 U-Boot 运行区域;3. 文件名区分大小写,需和分区内实际名称完全一致 |
| fatwrite | 将内存中指定长度的数据写入 FAT 分区,生成指定文件,用于保存日志、导出数据、更新文件 | fatwrite <接口> <设备号:分区号> <内存地址> <文件名> <字节数> | fatwrite mmc 0:1 0x80800000 test.bin 0x100000将内存 0x80800000 开始的 1MB 数据保存为 test.bin | 1. 长度单位是字节,不是扇区,注意和mmc write区分;2. 默认多数 U-Boot 版本未启用该功能,需编译时开启CONFIG_FAT_WRITE宏;3. 不能直接覆盖已有文件,需先删除或换文件名 |
BOOT相关
命令 / 变量 | 核心定位 | 适配镜像格式 | 标准语法 | 典型使用示例 | 关键注意事项 |
|---|---|---|---|---|---|
bootz | ARM32 平台专用内核启动命令,执行 zImage 自解压并跳转内核 | 仅支持 |
|
| 1. 仅适用于 ARMv7/ARM32 架构(如 IMX6ULL);2. 无 ramdisk 时中间的 |
bootm | U-Boot 通用型启动命令,跨架构兼容,是 U-Boot 传统标准启动方式 | 仅支持 |
| 1. 无设备树老平台: | 1. uImage 加载地址必须和打包时 |
bootcmd | 本质是U-Boot 环境变量(非独立命令),是系统上电自动启动的预设脚本, | 无格式限制,可组合任意 U-Boot 命令(tftp、fatload、bootz、bootm 等) |
|
| 1. 必须执行 |
文件结构
arch/arm/cpu/u-boot.lds是 U-Boot 的核心链接脚本,它会指导链接器规划最终镜像的内存布局,明确程序入口地址、代码段、数据段、BSS 段的排列顺序与加载 / 运行地址,同时定义重定位相关的段规则,直接决定 U-Boot 在内存中的分布与启动执行的起点。
board/freescale/mx6ullevk是 i.MX6ULL 官方 EVK 开发板的板级适配目录,存放与具体硬件强绑定的定制代码,包含 DDR 初始化参数、GPIO 引脚复用配置、外设硬件参数、板级初始化函数等内容,是通用驱动与具体电路板之间的适配层,也是硬件移植时的核心修改目录。
configs目录是 U-Boot 的板级配置模板仓库,目录下所有以_defconfig结尾的文件,每一个都对应一款开发板的精简功能配置,仅保存与全局默认配置有差异的项,用于指定 CPU 型号、板级目录、启用的驱动与功能、存储介质类型,不同文件名对应不同 DDR 容量、不同存储介质的硬件组合。
移植 U-Boot 时重点关注board/freescale与configs两个目录,是因为 U-Boot 采用 “通用驱动 + 板级定制” 的架构设计,通用架构代码与外设驱动通常无需修改,只需要在 board 目录修改硬件适配参数、在 configs 目录调整功能裁剪配置,即可快速完成新硬件的适配。
Makefile
专属配置文件 de_config
CONFIG_TARGET_MX6ULL_14X14_EVK=y
核心板子标识,整条构建链路的起点,启用 mx6ull_14x14_evk 这块开发板的专属适配
CONFIG_ARCH_MX6=y
启用 NXP IMX6 系列 SoC 底层驱动与初始化代码,开启后才会编译 IMX6ULL 专属:DDR 初始化、时钟、IO 复用、OCOTP 熔丝、启动设备等底层芯片代码;关闭的话,整个 IMX6 系列底层代码不会参与编译。
CONFIG_ARM=y
指定目标 CPU 大架构为 ARM,控制全局架构分支:编译 ARM 汇编、ARM 链接脚本、ARM 交叉编译适配逻辑;会给全局传递 -D__ARM__ 宏,源码中所有 #ifdef CONFIG_ARM 的架构专用代码才会编译;同时决定交叉编译器前缀、arch/arm/ 整个目录参与构建。
CONFIG_CMD_GPIO=y
开启 uboot 命令行下的 gpio 调试命令。
开启后才会编译 cmd/gpio.c,提供引脚调试功能;去掉这条 = uboot 无 gpio 操作命令。
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ullevk/imximage.cfg"
IMX 芯片专属关键配置,给mkimage打包工具用,imx 系列 SOC 启动时,ROM 固化程序需要读取头部配置(DDR 参数、时钟、镜像加载偏移);imximage.cfg 就是这块板子的 DDR 时序、启动头参数文件;构建时 mkimage 会读取这个路径的 cfg,给 u-boot.bin 加上 NXP 专用启动头,否则芯片 ROM 无法识别镜像、无法开机。
当执行了make mx6ull_14x14_evk_defconfig后,会匹配到如下规则。
%config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@展开后为:
@make -f scripts/Makefile.build obj=scripts/kconfig mx6ull_14x14_evk_defconfig-f scripts/Makefile.build
-f 指定 make 不读当前目录默认 Makefile,而是使用通用公共构建脚本 scripts/Makefile.build。
Makefile.build 是整个 U-Boot 递归编译的通用模板,负责:接收 obj= 参数,进入对应子目录、加载该目录本地的 Makefile。
obj=scripts/kconfig 传递参数
告诉 Makefile.build:本次要操作的子目录是 scripts/kconfig。内部逻辑:
切换工作目录视角到 scripts/kconfig;自动加载 scripts/kconfig/Makefile(配置专用规则文件);
所有后续规则、变量都以 scripts/kconfig 为上下文。
末尾 mx6ull_14x14_evk_defconfig
传给下层 Makefile 的目标(target)。也就是告诉 scripts/kconfig/Makefile:我要执行 %_defconfig 这条规则。
%_defconfig: $(obj)/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)展开后为:
scripts/kconfig/conf --defconfig=arch/arm/configs/mx6ull_14x14_evk_defconfig Kconfigconf 是 C 写的二进制工具,处理分 4 大步。
步骤 1:递归解析全部 Kconfig,在内存建一张完整配置表
以根 Kconfig 为起点:执行所有 source 语句,一层一层加载 arch、board、cmd、driver 所有子 Kconfig;逐条读取每一个 config、menu、depends on、default、select;
在内存生成一张大表格,每条记录包含:
- 开关名 CONFIG_XXX
- 类型 bool/hex/string
- 默认值、依赖项、自动选中项
- 归属哪个菜单层级、帮助文本
- 此时 conf 已经掌握全工程所有配置的全部规则、约束关系。
步骤 2:读取你传入的 defconfig 板子模板
读取 arch/arm/configs/mx6ull_14x14_evk_defconfig,里面只有板子差异化开关:
plaintext
CONFIG_TARGET_MX6ULL_14X14_EVK=y
CONFIG_CMD_GPIO=y
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ullevk/imximage.cfg"
用模板里的配置,覆盖内存表格里对应的默认值。
步骤 3:自动校验、补齐所有连锁依赖
依靠内存里的 Kconfig 规则表自动推导:
你开了 CONFIG_TARGET_MX6ULL_14X14_EVK=y,它里面写了 select ARM、select ARCH_MX6 → 自动把这两个置 y;
步骤 4:输出完整 .config 文件
把内存里最终全部配置状态写入输出目录的 .config:
开启项:CONFIG_ARM=y、CONFIG_SYS_MALLOC_F_LEN=0x400;
关闭项注释:# CONFIG_USB is not set;
板子标识字符串:CONFIG_SYS_VENDOR="freescale" 等。
核心MAKE过程
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map ...ALL_y定义了最终输出文件,包含以下文件。make会触发all ---> All_y的目标。
| 目标名称 | 类型 | 说明 |
|---|---|---|
u-boot.srec | 镜像文件 | S-Record 格式的可执行镜像,常用于烧录器、调试器加载 |
u-boot.bin | 镜像文件 | 纯二进制 U-Boot 镜像,最核心的烧录产物,去掉了 ELF 头与调试信息 |
u-boot.sym | 符号文件 | 导出 U-Boot 所有符号地址表,用于调试、异常栈解析 |
System.map | 符号文件 | 全局符号映射表,按地址排序,记录所有函数 / 变量的链接地址 |
u-boot.cfg | 配置文件 | 导出当前镜像所有生效的宏定义,用于核对编译配置 |
binary_size_check | 检查伪目标 | 不生成文件,校验最终镜像大小是否超出板级配置的上限 |