4、U-Boot命令行基础:常用命令详解

U-Boot 的命令行,说白了就是嵌入式开发者的“救命稻草”。

我刚开始做嵌入式那会儿,板子起不来、内核挂掉、文件系统找不到,十有八九都得靠 U-Boot 命令行来排查。你想想看,系统还没跑起来,Linux 内核都没加载,你能用啥?就靠这几十条命令。

这一章,我把最常用的几条命令掰开揉碎了讲。它们分别是:printenv、setenv、saveenv、bootm、tftp、mmc、sf。掌握了这些,你就能在 U-Boot 里自由地查看环境变量、修改配置、烧写固件、引导内核。

核心观点:U-Boot 的命令行操作,是 OTA 部署的“最后一公里”。你远程下载下来的固件,最终要通过这些命令写到正确的位置。

4.1 环境变量三剑客:printenv、setenv、saveenv

环境变量是 U-Boot 的灵魂。它决定了板子从哪里启动、用什么参数、加载哪个内核。

4.1.1 printenv —— 查看当前环境变量

这条命令最简单,也最常用。我每次拿到一块新板子,第一件事就是敲 printenv,看看默认配置长什么样。

U-Boot> printenv
baudrate=115200
bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rw
bootcmd=mmc dev 0; fatload mmc 0:1 0x42000000 uImage; bootm 0x42000000
bootdelay=3
ethaddr=00:11:22:33:44:55
ipaddr=192.168.1.100
serverip=192.168.1.10
...

输出结果是一堆 key=value 对。你可以只看某个变量,比如 printenv bootargs。

小技巧:如果环境变量被意外清空,可以用 env default -a 恢复出厂设置。我曾在调试时不小心删了所有变量,差点以为板子变砖了……

4.1.2 setenv —— 设置或修改变量

语法很简单:setenv 变量名 值。如果值包含空格,记得用引号括起来。

U-Boot> setenv ipaddr 192.168.1.200
U-Boot> setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw'
U-Boot> setenv my_flag 1

想删除一个变量?把值设为空就行:setenv my_flag。

注意:setenv 只修改内存中的环境变量,断电就丢了。想永久保存?看下一条。

4.1.3 saveenv —— 保存到持久存储

这条命令把当前环境变量写入 Flash 或 EMMC。不同板子保存的位置不一样,但命令都一样。

U-Boot> setenv serverip 192.168.1.10
U-Boot> saveenv
Saving Environment to MMC... OK

我个人的习惯是:每次修改关键变量后,立刻 saveenv。别等到最后一起存,万一中间断电,改的东西全没了。

4.2 内核引导命令:bootm

bootm 是 U-Boot 里最核心的命令之一。它的作用是从内存地址启动一个内核镜像。

基本用法:

U-Boot> bootm 0x42000000

这条命令告诉 U-Boot:内存地址 0x42000000 处放着一个内核镜像,帮我启动它。

如果内核用了设备树(DTB),可以这样:

U-Boot> bootm 0x42000000 - 0x43000000

格式是 bootm [内核地址] [ramdisk地址] [dtb地址]。中间用 - 表示没有 ramdisk。

关键点:bootm 要求内核镜像是 U-Boot 特有的 uImage 格式,或者用 bootz 启动 zImage,用 booti 启动 Image(ARM64)。

我曾经踩过一个坑:用 bootm 启动一个普通的 zImage,结果 U-Boot 直接报错。后来才意识到,bootm 只认 uImage 格式。从那以后,我习惯用 bootz 启动标准 Linux 内核。

4.3 网络下载命令:tftp

OTA 部署的核心就是网络传输。tftp 命令让你通过以太网从服务器下载文件到板子内存。

前提条件:

  • 板子和 PC 在同一网段
  • PC 上运行了 TFTP 服务器
  • 设置好 ipaddr 和 serverip
U-Boot> setenv ipaddr 192.168.1.100
U-Boot> setenv serverip 192.168.1.10
U-Boot> tftp 0x42000000 uImage
Using ethernet@... device
TFTP from server 192.168.1.10; our IP address is 192.168.1.100
Filename 'uImage'.
Load address: 0x42000000
Loading: #################################################################
         3.2 MiB/s
done
Bytes transferred = 5242880 (0x500000)

这条命令把服务器上的 uImage 文件下载到板子的 0x42000000 地址。下载完成后,你就可以用 bootm 启动了。

经验之谈:如果 TFTP 下载很慢,先检查网线质量。我遇到过好几次,换了根网线速度从 100KB/s 飙到 10MB/s。

4.4 存储操作命令:mmc 和 sf

固件下载到内存后,得写到存储设备里。嵌入式设备最常见的两种存储是 MMC(eMMC/SD卡)和 SPI Flash。

4.4.1 mmc 命令

mmc 命令用来操作 MMC 设备。常用子命令:

子命令 说明 示例
mmc dev 选择设备 mmc dev 0 选择第一个 MMC
mmc info 查看设备信息 mmc dev 0; mmc info
mmc read 从 MMC 读到内存 mmc read 0x42000000 0x800 0x1000
mmc write 从内存写到 MMC mmc write 0x42000000 0x800 0x1000
mmc part 查看分区表 mmc dev 0; mmc part

写固件的典型流程:

U-Boot> tftp 0x42000000 uImage
U-Boot> mmc dev 0
U-Boot> mmc write 0x42000000 0x800 0x3000

这里 0x800 是 MMC 上的起始扇区,0x3000 是要写的扇区数。每个扇区 512 字节。

警告:写 MMC 之前,一定确认分区表。我曾经写错了扇区偏移,把分区表覆盖了,板子直接变砖。还好有备份……

4.4.2 sf 命令

sf 命令用来操作 SPI Flash。用法和 mmc 类似,但地址单位是字节,不是扇区。

子命令 说明 示例
sf probe 检测并初始化 SPI Flash sf probe
sf read 从 Flash 读到内存 sf read 0x42000000 0x100000 0x80000
sf write 从内存写到 Flash sf write 0x42000000 0x100000 0x80000
sf erase 擦除 Flash 区域 sf erase 0x100000 0x80000

写 SPI Flash 的典型流程:

U-Boot> tftp 0x42000000 uboot.bin
U-Boot> sf probe
U-Boot> sf erase 0x0 0x80000
U-Boot> sf write 0x42000000 0x0 0x80000

注意:SPI Flash 写入前必须先擦除。我见过有人直接 sf write,结果数据没写进去,还以为是 Flash 坏了。

4.5 本章知识体系

下面这张图帮你理清这些命令之间的关系:

U-Boot 常用命令知识体系 U-Boot 命令行 环境变量管理 printenv setenv saveenv 网络传输 tftp 存储操作 mmc sf 内核引导 bootm 流程:setenv 配置 → tftp 下载 → mmc/sf 写入 → bootm 启动

4.6 实战组合:一次完整的 OTA 部署流程

把上面这些命令串起来,就是一个完整的 OTA 部署流程:

  1. 配置网络:setenv ipaddr 192.168.1.100; setenv serverip 192.168.1.10
  2. 下载固件:tftp 0x42000000 uImage
  3. 写入存储:mmc dev 0; mmc write 0x42000000 0x800 0x3000
  4. 设置启动参数:setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw'
  5. 保存环境变量:saveenv
  6. 启动新系统:bootm 0x42000000

总结:这七条命令,就是 U-Boot 网络 OTA 部署的基石。后面的章节会基于这些命令,构建自动化的升级脚本和远程部署方案。