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 本章知识体系
下面这张图帮你理清这些命令之间的关系:
4.6 实战组合:一次完整的 OTA 部署流程
把上面这些命令串起来,就是一个完整的 OTA 部署流程:
- 配置网络:
setenv ipaddr 192.168.1.100; setenv serverip 192.168.1.10 - 下载固件:
tftp 0x42000000 uImage - 写入存储:
mmc dev 0; mmc write 0x42000000 0x800 0x3000 - 设置启动参数:
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw' - 保存环境变量:
saveenv - 启动新系统:
bootm 0x42000000
总结:这七条命令,就是 U-Boot 网络 OTA 部署的基石。后面的章节会基于这些命令,构建自动化的升级脚本和远程部署方案。