LV09-02-uboot-02-命令简介
本文主要是uboot——命令的基本使用的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
| Windows | windows11 |
| Ubuntu | Ubuntu16.04的64位版本 |
| VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
| SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
| Linux开发板 | 华清远见 底板: FS4412_DEV_V5 核心板: FS4412 V2 |
| u-boot | 2013.01 |
点击查看本文参考资料
| 参考方向 | 参考原文 |
| --- | --- |
点击查看相关文件下载
| 文件 | 下载链接 |
| uboot_bin.rar | uboot原始镜像(不可以直接烧写)和LED灯闪烁测试程序 |
| WIn32_disk_imager.rar | windows下向SD卡烧写uboot镜像的软件 |
| example_uboot.rar | 可以直接烧写到SD卡的uboot镜像文件 |
一、几个常用命令
1. help
我们在SecureCRT终端输入help,便会打印出当前uboot所支持的所有命令。
点击查看相关命令
1 | ? - alias for 'help' |
2. reset
reset命令可以用于重启开发板,我们直接在命令行输入reset即可:
1 | fs4412 # reset |
3. loadb
loadb命令通过串口进行数据的传输,我们一般使用该命令进行二进制文件的传输,它使用的是kermit protocol传输协议,一般使用格式如下:
1 | loadb [ off ] [ baud ] |
off:其实就是数据要加载到内存中的起始地址,例如在fs4412开发板中,我们经常使用loadb 40008000来启动kermit的传输。baud:传输的波特率,可以不写,默认为115200。
例如,
1 | fs4412 # loadb 40008000 |
然后按下enter按键便会等待数据的传输,我们可以直接将文件拖拽到SecureCRT终端界面中,然后选择发送Kermmit即可开启文件传输,将会有以下提示:
1 | # Ready for binary (kermit) download to 0x40008000 at 115200 bps... |
4. go
go命令用于跳到指定的地址处执行应用,命令格式如下:
1 | go addr [arg ...] |
addr:是应用在DRAM中的首地址
我们上一步使用loadb命令将interface.bin文件下载到了0X40008000,现在我们使用go命令启动interface.bin这个应用,命令如下:
1 | fs4412 # go 40008000 |
5. run
run命令用于运行环境变量中定义的命令,比如可以通过run bootcmd来运行 bootcmd中的启动命令,但是run命令最大的作用在于运行我们自定义的环境变量。在后面调试Linux系统的时候可能常常要在网络启动和EMMC/NAND启动之间来回切换,而bootcmd只能保存一种启动方式,如果要换另外一种启动方式的话就得重写bootcmd,会很麻烦。这里我们就可以通过自定义环境变量来实现不同的启动方式,比如定义环境变量mybootemmc表示从emmc启动,定义mybootnet表示从网络启动,定义mybootnand表示从NAND启动。如果要切换启动方式的话只需要运行run mybootxxx(xxx为 emmc、 net或 nand)即可。一般命令格式如下:
1 | run var [...] |
var:表示需要运行的定义了命令的环境变量名。
6. mtest
mtest命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的DDR,一般命令格式如下:
1 | mtest [start [end [pattern [iterations]]]] |
start:要测试的DRAM开始地址。end:是结束地址。
【注意】如果要结束测试就按下键盘上的Ctrl + C键。
二、信息查询
1. printenv
该命令主要用于打印出所有的环境变量信息,我们在SecureCRT终端中直接执行下边的命令,便可以得到该命令的使用格式:
1 | fs4412 # ? printenv |
该命令使用方式很简单,我们直接在命令行输入:
1 | fs4412 # printenv |
然后我们会得到以下信息:
1 | baudrate=115200 |
2. bdinfo
bdinfo命令,此命令用于查看板子信息,直接输入bdinfo即可,结果如下:
1 | fs4412 # bdinfo |
3. version
version用于查看 uboot的版本号,直接输入version即可:
1 | fs4412 # version |
三、环境变量
上边我们通过printenv打印出来的信息中有很多的环境变量,比如 baudrate、 bootcmd等等。uboot中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和变量一样。比如bootdelay这个环境变量就表示 uboot 启动延时时间,默认 bootdelay=3,也就默认延时 3 秒。前面说的 3 秒倒计时就是由 bootdelay 定 义的,如果将 bootdelay 改为5的话就会倒计时 5s了。 。
1. setenv
该命令主要用于操作环境变量,我们在SecureCRT中查看一下该命令使用格式:
1 | fs4412 # ? setenv |
【注意】此命令修改完后,开发板若重启,那么所有环境变量将会复原。
1.1 修改环境变量
环境变量是可以修改的,例如我们想修改一下uboot启动linux倒计时,这个时间是由bootdelay环境变量来控制的,我们上边是5秒,我们可以通过以下命令更改秒数,例如,
1 | fs4412 # setenv bootdelay 3 |
这样便可以将bootdelay修改为3秒。
1.2 创建环境变量
我们也可以通过该命令创建新的环境变量:
1 | fs4412 # setenv name value |
例如,
1 | fs4412 # setenv aaa ccc |
1.3 删除环境变量
我们创建了不想要的环境变量怎么办呢?有创建肯定有删除,该命令同样也可以删除环境变量,去掉后边的值,就可以将一个已经存在的环境变量删除:
1 | fs4412 # setenv name |
例如,
1 | fs4412 # setenv aaa |
删除后,我们打印一个不存在测环境变量便会出错。
2. saveenv
前边的环境变量我们修改后,只在此次使用有效,当开发板关机时,修改过的环境变量全部会失效,那如何保存下来,让这些修改过的环境变量后边也依然可以生效呢?我们可以使用saveenv命令。
1 | fs4412 # saveenv |
这样我们修改过的环境变量就会被保存到eMMC,下一次开发板重新启动,环境变量还会是我们修改后的值。
四、内存操作
1. md
md命令用于显示内存值,格式如下:
1 | md[.b, .w, .l] address [# of objects] |
[.b .w .l]:对应byte、word和long,也就是分别以1个字节 、2个字节、4个字节。address:要查看的内存起始地址。[# of objects]:表示要查看的数据长度,这个数据长度单位不是字节,而是跟我们所选择的显示格式有关。比如我们设置要查看的内存长度 为20(十六进制为0x14),如果显示格式为.b的话那就表示20个字节;如果显示格式为.w的话就表示20个word,也就是20*2=40个字节;如果显示格式为.l的话就表示20个long,也就是20*4=80个字节。
【注意】uboot命令中的数字都是十六进制的,不是十进制的!命令里面的数字都是十六进制的,所以可以不用写0x前缀,十进制
的 20其十六进制为 0x14,所以命令 md后面的个数应该是 14,如果写成 20的话就表示查看32(十六进制为 0x20)个字节的数据。
2. nm
nm命令用于修改指定地址的内存值,命令格式如下:
1 | nm[.b, .w, .l] address |
nm命令同样可以以 .b、 .w和 .l来指定操作格式。例如,我们现在要以.l格式修改0x40008000地址处数据为12345678,我们输入以下命令:
1 | fs4412 # nm.l 40008000 |
其中40008000表示现在要修改的内存地址, e8bd84f0表示地址40008000现在的数据,?后面就可以输入要修改后的数据0x12345678,输入完成以后按下回车:
1 | 40008000: e8bd84f0 ? 12345678 |
这样我们便修改了相应的数据,然后输入q再按下回车就可以退出了
1 | 40008000: 12345678 ? q |
3. mm
mm命令也是修改指定地址内存值的,使用 mm修改内存值的时候地址会自增,而使用命令nm的话地址不会自增。使用格式如下:
1 | mm[.b, .w, .l] address |
使用方式与nm一致,只不过它的地址会自己增加,例如
1 | fs4412 # mm.l 40008000 |
4. mw
mw用于使用一个指定的数据填充一段内存,命令格式如下:
1 | mw[.b, .w, .l] address value [count] |
[.b .w .l]:对应byte、word和long,也就是分别以1个字节 、2个字节、4个字节。address:要查看的内存起始地址。value:为要填充的数据。count:填充的长度。
例如,
1 | fs4412 # mw.l 40008000 12345678 4 |
5. cp
cp是数据拷贝命令,用于将 DRAM中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash中的数据拷贝到 DRAM中。命令格式如下:
1 | cp[.b, .w, .l] source target count |
[.b .w .l]:对应byte、word和long,也就是分别以1个字节 、2个字节、4个字节。source:源地址。target:目的地址。count:为拷贝的长度。
例如,
1 | fs4412 # cp.l 40008000 41000000 5 |
6. cmp
cmp是比较命令,用于比较两段内存的数据是否相等,命令格式如下:
1 | cmp[.b, .w, .l] addr1 addr2 count |
[.b .w .l]:对应byte、word和long,也就是分别以1个字节 、2个字节、4个字节。addr1:第一段内存首地址。addr1:第二段内存首地址。count:为要比较的长度。
五、存储器访问
关于存储器的访问主要是mmc命令,我们使用help mmc来查看它的帮助信息:
1 | mmc - MMC sub system |
但是还有一个mmcinfo的命令,在目前使用的这个版本uboot中似乎并不被列在mmc的命令中。
1. mmcinfo
mmcinfo命令用于查看当前设备的mmc信息,直接输入命令即可,例如:
1 | fs4412 # mmcinfo |
2. mmc rescan
mmc rescan命令用于扫描当前开发板上所有的 MMC设备,包括 EMMC和 SD卡,直接输入mmc rescan即可。
3. mmc list
mmc list命令用于来查看当前开发板一共有几个MMC设备,直接输入mmc list即可,例如:
1 | fs4412 # mmc list |
4. mmc dev
mmc dev命令用于切换当前MMC设备,一般使用格式如下:
1 | mmc dev [dev] [part] |
dev:设置要切换的MMC设备号。part:分区号,如果不写分区号的话默认为分区0。
5. mmc part
有时候 SD卡或者 EMMC会有多个分区,可以使用命令mmc part来查看其分区,直接输入命令即可:
1 | mmc part |
6. mmc read
mmc read命令用于将MMC中指定扇区中的内容读取到内存中指定的地址,命令格式如下:
1 | mmc read <dev_num> addr blk# cnt |
dev_num:mmc的设备号,可以通过mmc list查询到,这个参数可以不写,不写的话默认为当前mmc设备。addr:数据读取到内存中的起始地址。blk#:要读取的块起始地址 (十六进制 ),一个块是512字节,这里的块和扇区是一个意思,在MMC设备中我们通常说扇区。cnt:要读取的块数量 (十六进制 )。
例如,
1 | mmc read 0 0x40008000 0x600 0x10 |
这个命令的含义就是,把第0个mmc设备块偏移为0x600处开始,长度为16x512大小的数据,读出到内存0x40008000处。
7. mmc write
mmc write命令用于将数据写到MMC设备里面。我们可以使用命令mmc write来 升级 uboot,也就是在 uboot中更新 uboot。这里会要用到nfs或者 tftp命令,通过nfs或者tftp命令将新的 u-boot.bin下载到开发板的DRAM中,然后再使用命令mmc write将其写入到MMC设备中。一般使用格式如下:
1 | mmc write <dev_num> addr blk# cnt |
dev_num:mmc的设备号,可以通过mmc list查询到,这个参数可以不写,不写的话默认为当前mmc设备。addr:数据将要写入到内存中的起始地址。blk#:要写入的块起始地址 (十六进制 ),一个块是512字节,这里的块和扇区是一个意思,在MMC设备中我们通常说扇区。cnt:要写入的块数量 (十六进制 )。
【注意】千万不要写 SD卡或者EMMC的前两个块 (扇区 ),里面保存着分区表。
例如,
1 | mmc write 0 0x40008000 0x600 0x10 |
这个命令的含义就是,把内存0x40008000开始,长度为16x512大小的数据,写入到第0个mmc设备块偏移位置为0x600处。
8. mmc erase
mmc erase命令用于擦除MMC设备的指定块,一般使用格式如下:
1 | mmc erase blk# cnt |
blk#:要擦除的起始块。cnt:要擦除的数量。
【注意】一般不要用 mmc erase来擦除 MMC设备。
六、网络操作
在uboot中,至少支持的外设就是串口和网口,因为我们需要通过这两个外设进行文件的传输,下边我们先来学习一下网络操作相关命令吧。
1. 网络环境变量
要使用网络的话,还是需要先设置一下网络的相关环境变量。相关的环境变量如下:
| 环境变量 | 描述 |
| ipaddr | 开发板 IP 地址,可以不设置,使用 dhcp 命令来从路由器获取 IP 地址。 |
| ethaddr | 开发板的 MAC 地址,一定要设置。 |
| gatewayip | 网关地址。 |
| netmask | 子网掩码。 |
| serverip | 服务器IP地址,也就是 Ubuntu主机 IP 地址,用于调试代码。 |
要注意,开发板的IP一定要与Ubuntu主机的IP处于网段,这样才能实现网络通信。我的一般设置如下:
1 | fs4412 # setenv ipaddr 192.168.10.102 |
2. ping
我们的开发板的网络能否使用,是否可以和服务器 (Ubuntu主机 )进行通信,可以通过ping命令验证,直接ping服务器的IP地址即可,比如我的服务器IP地址为 192.168.10.101,那么命令格式如下:
1 | fs4412 # ping 192.168.10.101 |
如果连接成功的话,会有以下信息提示:
1 | dm9000 i/o: 0x5000000, id: 0x90000a46 |
如果连接不成功(服务器没开启或者说IP不在同一网段的话),可能会有以下提示:
1 | dm9000 i/o: 0x5000000, id: 0x90000a46 |
【注意】只能在 uboot中 ping其他的机器,其他机器不能 ping uboot,因为 uboot没有对 ping命令做处理,如果用其他的机器 ping uboot的话会失败!
3. dhcp
dhcp用于从路由器获取IP地址,前提得开发板连接到路由器上的,如果开发板是和电脑直连的,那么dhcp命令就会失效。直接输入dhcp命令即可通过路由器获取到IP地址。
4. tftp
tftp命令用于通过网络下载数据到指定的内存地址中,tftp命令使用的是TFTP协议,Ubuntu主机作为TFTP服务器。因此需要在 Ubuntu上搭建TFTP服务器,之前的时候我们已经搭建并本地验证过了,在uboot中使用的格式如下:
1 | tftpboot [loadAddress] [[hostIPaddr:]bootfilename] |
tftpboot:命令的全称,但是其实我们输入一个tftp就足够了。loadAddress:是文件在内存中的存放地址。hostIPaddr:服务器的IP地址,实际就是Ubuntu主机的IP地址,如果说前边我们设置了serverip环境变量的话,这里是可以省略的。bootfilename:是要从Ubuntu中下载的文件这个文件是以服务器中tftp目录为根目录的。
例如,我们前边设置的tftp目录为/home/hk/3tftp,然后我们需要下载这个文件:
1 | /home/hk/3tftp/fs4412/interface.bin |
这个时候我们使用的命令如下:
1 | fs4412 # tftp 40008000 /fs4412/interface.bin |
按下enter按键之后,我们会得到以下提示:
1 | dm9000 i/o: 0x5000000, id: 0x90000a46 |
这个时候我们可以使用go命令运行一下程序,来看看测试程序是否确实下载到了0x40008000处:
1 | go 40008000 |
然后我们会看到开发板的led灯开始闪烁,这就说明我们已经成功下载了我们的应用程序到内存中。
七、文件系统操作
1. FAT格式文件系统
1.1 fatinfo
fatinfo命令用于查询指定MMC设备分区的文件系统信息,格式如下:
1 | fatinfo <interface> [<dev[:part]>] |
interface:表示接口,比如mmc。dev:查询的设备号。part:要查询的分区。
例如,我们要查询设备0的MMC分区1的文件系统信息,命令如下:
1 | fatinfo mmc 0:1 |
1.2 fatls
fatls命令用于查询FAT格式设备的目录和文件信息,格式如下:
1 | fatls <interface> [<dev[:part]>] [directory] |
interface:表示接口,比如mmc。dev:查询的设备号。part:要查询的分区。directory:是要查询的目录。
例如,我们要查询设备0的MMC分区1的所有目录和文件,命令如下:
1 | fatls mmc 0:1 |
1.3 fatload
fatload命令用于将指定的文件读取到内存中,命令格式如下:,格式如下:
1 | fatload <interface> [<dev[:part]>] <addr> <filename> [bytes [pos]] |
interface:表示接口,比如mmc。dev:设备号。part:分区。addr:要保存到内存中的起始地址。filename:要读取的文件名字。bytes:表示读取多少字节的数据,如果bytes为0或者省略的话表示读取整个文件。pos:是要读的文件相对于文件首地址的偏移,如果为0或者省略的话表示从文件首地址开始读取。
例如,我们将设备0的分区1中的zImage文件读取到内存中的0X40008000地址处,命令如下:
1 | fatload mmc 0:1 40008000 zImage |
2. EXT格式文件系统
由于这里使用的是uboot 2013版本的,这里的一些命令似乎并不怎么支持,后边用的也很少,这里就不写了,后边用到了再补充。
八、boot操作
1. 两个环境变量
1.1 boodcmd
bootcmd环境变量中保存着uboot的默认命令,该环境变量其实也叫做自启动环境变量。在我们重启开发板的时候,会有这么一个提示信息:
1 | Hit any key to stop autoboot : 3 |
这里就是uboot倒计时,这里的这个时间由环境变量bootdelay控制,当倒计时结束之前按下任意按键,就会进入uboot的一个命令行的模式,着大盖就类似于我们重装windows系统时的BIOS系统一样。
当我们在倒计时期间没有按下任何按键的话,倒计时结束以后就会执行bootcmd中的命令。这些命令一般用来启动linu内核,比如读取EMMC或者NAND Flash中的linux内核镜像文件和设备树文件到DRAM中,然后启动linux内核。可以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。如果 EMMC 或者 NAND 中没有保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量。
需要注意的是该环境变量中可以有多条命令,多条命令之间用\;分隔开,修改完后我们需要将环境变量进行保存,否则下次重启,我们设置的环境变量就会失效,另外,我们可以通过run命令来运行这个环境变量中的命令。例如,
1 | fs4412 # setenv bootcmd tftp 40008000 interface.bin\;go 40008000 |
1.2 bootargs
bootargs 保存着 uboot 传递给 Linux 内核的参数,也被叫做自启动参数,uboot不需要使用。例如,
1 | setenv bootargs root=/dev/nfs nfsroot=<server_ip>:<server_nfs_dir_path> rw console=ttySAC2,115200 init=/linuxrc ip=linux_ip |
consoleconsole用来设置linux终端(或者叫控制台),也就是开发板安装好linux后,我们通过什么设备来和Linux进行交互,是串口还是LCD屏幕?如果是串口的话串口号是多少等。这里设置console为ttySAC2。ttySAC2后面有个,115200,这是设置串口的波特率,console=ttySAC2,115200综合起来就是设置ttySAC2作为Linux的终端,并且串口波特率设置为115200。rootroot用来设置根文件系统的位置,例如
1 | root=/dev/mmcblk[dev_num]p[cnt] |
这就表示 mmc 设备 dev_num (从0开始)的分区 cnt(从0开始)。我们有时候也会使用上边例子中的方式:
1 | root=/dev/nfs nfsroot=<server_ip>:<server_nfs_dir_path> |
这指明了根文件系统类型(nfs),后边的nfsroot表示网络文件系统路径,可以挂载一个ubuntu服务器的nfs共享文件夹。
【注意】在root参数中,还会有一个rw,这就表示根文件系统是可以读写的,不加 rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。
init
init用来指定init进程的程序路径,一般init=/linuxrc, 或者init=/etc/preinit,preinit的内容一般是创建console、null设备节点,运行init程序,挂载一些文件系统等操作。我们可能以为init=/linuxrc是固定写法,其实不然,/linuxrc指的是/目录下面的linuxrc脚本,一般指向busybox。
ip
这就表示linux启动后自身的IP地址。
2. bootm
要启动Linux,需要先将Linux镜像文件拷贝到DRAM中,如果使用到设备树的话,也需要将设备树拷贝到DRAM中。可以从 EMMC或者NAND等存储设备中将Linux镜像和设备树文件拷贝到DRAM,也可以通过nfs或者tftp将Linux镜像文件和设备树文件下载到DRAM中。
不管用那种方法,只要能将Linux镜像和设备树文件存到DRAM中就行,然后使用boom命令来启动,boom命令用于启动linux镜像文件, boom命令格式如下:
1 | bootm [addr [arg ...]] |
addr是linux镜像在DRAM中的首地址。arg:可以是一个initrd映像的地址,当引导一个需要设备树的Linux内核时,需要第三个参数,它是设备树的地址。要在不使用initrd镜像的情况下引导内核,我们需要使用-作为第二个参数。
其实有的资料中,该命令格式是这样的,我感觉更加详细一点:
1 | bootm [addr [initrd[:size]] [fdt]] |
addr:是Linux镜像文件在DRAM中的位置,initrd:是initrd文件在DRAM中的地址,如果不使用initrd的话使用-代替即可 。fdt:就是设备树文件在DRAM中的地址。
或者直接这样写可能更清晰一点:
1 | bootm kernel-addr ramdisk-addr dtb-addr |
kernel-addr: 内核的下载地址 。ramdisk-addr: 根文件系统的下载地址。dtb-addr: 设备树的下载地址。
【注意】若不使用相应的地址,对应的位置写-。