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 |
console
console
用来设置linux
终端(或者叫控制台),也就是开发板安装好linux
后,我们通过什么设备来和Linux
进行交互,是串口还是LCD
屏幕?如果是串口的话串口号是多少等。这里设置console
为ttySAC2
。ttySAC2
后面有个,115200
,这是设置串口的波特率,console=ttySAC2,115200
综合起来就是设置ttySAC2
作为Linux
的终端,并且串口波特率设置为115200
。root
root
用来设置根文件系统的位置,例如
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
: 设备树的下载地址。
【注意】若不使用相应的地址,对应的位置写-
。