U-Boot命令解析
第一节 U-Boot中命令的定义方式
uboot中使用U_BOOT_CMD来定义命令,宏U_BOOT_CMD定义在文件include/command.h中,定义如下:
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL) |
U_BOOT_CMD命令以dhcp命令为例:
dhcp命令宏定义 U_BOOT_CMD(dhcp,3,1,do_dhcp,”boot image via network using DHCP/TFTP protocol”,”[localAddress] [[hostIPaddr:]bootfilename]”); |
展开以后的模样:
dhcp命令展开 U_BOOT_CMD(dhcp,3,1,do_dhcp,”boot image via network using DHCP/TFTP protocol”,”[localAddress] [[hostIPaddr:]bootfilename]”); 1.将U_BOOT_CMD展开后为: U_BOOT_CMD_COMPLETE(dhcp,3,1,do_dhcp,”boot image via network using DHCP/TFTP protocol”,”[localAddress] [[hostIPaddr:]bootfilename]”,NULL); 2.将U_BOOT_CMD_COMPLETE展开后为: ll_entry_declare(cmd_tbl_t,dhcp,cmd) = \ U_BOOT_CMD_MKENT_COMPLETE(dhcp,3,1,do_dhcp,”boot image via network using DHCP/TFTP protocol”,”[localAddress] [[hostIPaddr:]bootfilename]”,NULL); 3.将ll_entry_declare和U_BOOT_CMD_MKENT_COMPLETE展开后为: cmd_tbl_t u_boot_list_2_cmd_2_dhcp __aligned(4) \ __attribute__((unused,section(.u_boot_list_2_cmd_2_dhcp))) \ { dhcp,3,1,do_dhcp,”boot image via network using DHCP/TFTP protocol”,”[localAddress] [[hostIPaddr:]bootfilename]”,NULL} |
最终展开结果:
dhcp命令最终结果 1 cmd_tbl_t u_boot_list_2_cmd_2_dhcp __aligned(4) \ 2 __attribute__((unused,section(.u_boot_list_2_cmd_2_dhcp))) \ 3 { dhcp,3,1,do_dhcp, \ 4 ”boot image via network using DHCP/TFTP protocol”, \ 5 ”[localAddress] [[hostIPaddr:]bootfilename]”, \ 6 NULL} |
第1行定义了一个cmd_tbl_t类型的变量,变量名为u_boot_list_2_cmd_2_dhcp,此变量4字节对齐。
第2行,使用__attribute__关键字设置变量u_boot_list_2_cmd_2_dhcp存储在.u_boot_list_2_cmd_2_dhcp段中。u-boot.lds链接脚本中有一个名为“.u_boot_list”的段,所有.u_boot_list开头的段都存放到.u_boot.list中。
总结:
(1)在command目录下有很多cmd_name.c类似的文件。每个文件都传建一个cmd_tbl_t结构体并存在.u_boot_list段中。主要指定名字和所要执行的函数do_name
(2)run_command函数接受参数,解析,然后根据参数第一个单词,遍历.u_boot_list段,找到name相同的结构体,调用该结构体的do_name函数。
第二节 U-Boot命令的使用
2.1 help命令
输入help或问号,即可查看某一个命令帮助信息。
使用方法:(1)help或? 命令名;(2)help或?
如help boot或? boot,即可查看boot命令的帮助信息。
2.2 信息查询
1.bdinfo
打印板子信息。
2.printenv
查看当前板子的环境变量。
2.3 setenv命令
设置环境变量,也可以自定义环境变量,也可以删除环境变量。
如更改倒计时时间bootdelay为3秒,可使用命令setenv bootdelay 3,然后输入命令saveenv保存环境变量回eMMC即可。
而如果要设置复杂的环境变量,如一串字符串时,则需要使用命令 setenv 环境变量名 ‘字符串’.
若setenv一个不存在的环境变量,如setenv author yky,即可创造一个环境变量author,值为yky。
若setenv环境变量,即可删除这个环境变量。
2.4 saveenv命令
保存环境变量。
2.5 内存操作命令
1.md
用于显示内存值,格式如下:
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,也就是80个字节。另外要注意:uboot命令中的数字都是十六进制的,不是十进制的!
如想查看已0x80000000开始的20个字节的内存值,显示格式为.b的话,应该使用如下所示命令:
md.b 80000000 14而不是md.b 80000000 20
2.nm
nm命令用于修改指定地址的内存值,命令格式如下:
nm[.b,.w,.l] addresss |
nm命令同样可以以.b、.w和.l来指定操作格式,比如现在以.l格式修改0x80000000地址的数据为0x12345678。输入命令:
nm[.b,.w,.l] addresss |
此时会弹出 80000000: ffffff00 ?。ffffff00表示0x80000000现在的数据,?后面就可以输入要修改后的数据0x12345678,输入完成后按下回车,然后在输入’q’即可退出,即:
80000000: ffffff00 ? 12345678 80000000:12345678 ? q |
3.mm
mm命令也是修改指定地址内存值的,使用mm修改内存值的时候地址会自增,而使用命令nm的话地址不会自增。比如以.l格式修改地址0x80000000开始的连续3个内存块(3*4=12个字节)的数据为0x05050505,操作如图1所示。
图1 mm命令 |
4.mw
命令mw用于使用一个指定的数据填充一段内存,命令格式如下:
mw[.b,.w,.l] address value [count] |
mw命令同样可以以.b、.w和.l来指定操作格式,address表示要填充的内存起始地址,value为要填充的数据,count是填充的长度 。比如使用.l格式将以0x80000000为起始地址的0x10个内存块(0x10*4=64字节)填充为0x0A0A0A0A,命令如下:
mw.l 80000000 0A0A0A0A 10 |
5.cp
cp是数据拷贝命令,用于将DRAM中的数据从一段内存拷贝到另一段内存中,或者把Nor Flash中的数据拷贝到DRAM中。命令格式如下:
cp[.b,.w,.l] source target count |
cp命令同样可以以.b、.w和.l来指定操作格式,source为源地址,target为目的地址,count为拷贝的长度。我们使用.l格式将0x80000000处的地址拷贝到0x80000100处,长度为0x10个内存块(0x10*4=64字节),命令如下所示:
cp.l 80000000 80000100 10 |
6.cmp
cmp是比较命令,用于比较两端内存的数据是否相等,命令格式如下:
cmp[.b,.w,.l] addr1 addr2 count |
cp命令同样可以以.b、.w和.l来指定操作格式,addr1为第一段内存首地址,addr2为第二段内存首地址,count为要比较的长度。我们使用.l格式来比较0x80000000和0x80000100这两个地址数据是否相等,比较长度为0x10个内存块(0x10*4=64字节),命令如下所示:
cmp.l 80000000 80000100 10 |
2.6 网络操作命令
1.ping
测试网络是否连通
2.dhcp
由系统自动分配ip地址。
注意:通过DHCP命令获取到的IP地址仅本次有效,不会修改环境变量中ipaddr的值,下次重启以后依旧用的ipaddr里面的地址!除非使用saveenv将地址保存会eMMC中存储的环境变量方可永久保存。
3.nfs
也就是网络文件系统,可通过nfs命令将文件系统挂载到指定ip地址的指定目录。其实目的就是为了调试代码。
用法:nfs [localAddress] [[hostIPaddr:]bootfilename]
如:nfs 80800000 192.168.31.80:/home/yky/nfs_rootfs
4.tftp
用于到指定ip地址的指定目录下载指定文件到开发板的指定地址中。
注意:在指定ip地址上需要先按照tftp-hpa和tftpd-hpa。
2.7 EMMC和SD卡操作命令
1.mmc info
显示当前mmc设备的信息
2.mmc rescan
重新扫描mmc设备
3.mmc part
列出当前mmc设备的分区情况
4.mmc dev [dev] [part]
显示或设置当前mmc设备
5.mmc list
列出所有可用的mmc设备
6.mmc read
用于读取mmc设备的数据,命令格式如下:
mmc read addr blk# cnt |
addr是数据读取到DRAM中的地址,blk是要读取的块起始地址(十六进制),一个块是512字节,这里的块和扇区是一个意思,cnt是要读取的块数量(十六进制)。比如从EMMC的第1536(0x600)个块开始,读取16(0x10)个块的数据到DRAM的0x80800000地址处,命令如下:
mmc dev 1 0 //切换到MMC分区0 mmc read 80800000 600 10 //读取数据 |
7.mmc write
用于将数据写到mmc设备里面,命令格式如下:
mmc write addr blk# cnt |
addr是要写入mmc中的数据在DRAM中的起始地址,blk是要写入mmc的块起始地址(十六进制),一个块是512字节,这里的块和扇区是一个意思,cnt是要读取的块数量(十六进制)。我们可以使用命令“mmc write”来升级uboot,也就是在uboot中更新uboot。这里要用到nfs或者tftp命令,通过nfs或tftp命令将新的u-boot.stm32下载到开发板的DRAM中,然后再使用命令“mmc write”将其写入到mmc设备中。
8.mmc erase
如果要擦除mmc设备的指定块就是用命令“mmc erase”,命令格式如下:
mmc erase blk# cnt |
blk为要擦除的起始块,cnt是要擦除的数量。没事不要用mmc erase来擦除mmc设备!!!
2.8 文件操作命令
1.fstype命令
fstype用于查看mmc设备某个分区的文件系统格式,命令格式如下:
fstype <interface> <dev>:<part> |
如AHL-STM32MP157核心板上的EMMC默认有3个分区,我们可以查看这三个分区的文件系统格式,输入命令:
fstype mmc 1:1 fstype mmc 1:2 fstype mmc 1:3 |
显示结果如图4-2所示。
图4-2 fstype查看开发板分区文件系统格式 |
2.ext4load
用于将指定的ext4格式文件读取到DRAM中,命令格式如下:
ext4load <interface> [<dev[:part]> [addr [filename [bytes [pos]]]]] |
interface为借口,如mmc;dev是设备号;part是分区;addr是保存在DRAM中的起始地址;filename是要读取的文件名字;bytes表示读取多少字节的数据,如果bytes为0或者省略的话表示读取整个文件;pos是要读的文件相对于文件首地址的偏移,如果为0或者省略的话表示从文件首地址开始读取。我们将EMMC分区2中的uImage文件读取到DRAM中的0xc2000000地址处,命令如下:
ext4load mmc 1:2 c2000000 uImage |
3.ext4ls
列出指定mmc设备的指定分区中的文件和目录,命令格式如下:
ext4ls <interface> <dev[:part]> [directory] |
如输入命令,查看EMMC的分区2中文件和目录:
ext4ls mmc 1:2 |
显示结果如图4-3所示:
图4-3 ext4ls列出EMMC的分区2中文件和目录 |
2.9 BOOT操作命令
uboot的本质工作是引导Linux,所以uboot肯定有相关的boot命令来启动Linux,常用的跟boot有关的命令有bootz、bootm和boot。
1.bootz命令
要启动Linux必须将zImage和dtb放到DRAM。然后使用bootz命令来启动,bootz命令用来自启动zImage镜像文件,bootz命令格式如下:
bootz [addr [initrd[:size]] [fdt]] |
addr是Linux镜像文件在DRAM中的位置,initrd是initrd文件在DRAM中的地址,如果不使用initrd的话使用’-’代替即可,fdt就是设备树文件在DRAM中的地址。现在我们使用网络和EMMC两种方法来启动Linux系统,首先通过tftp命令下载Linux镜像zImage和设备树dtb文件下载到开发板的指定地址,然后使用bootz命令启动:
bootz c2000000 – c4000000 |
2.go命令
go命令用于跳到指定的地址处执行应用,命令格式如下:
go addr [arg…] |
addr是应用在DRAM中的首地址。
可以使用go命令来运行DRAM指定地址上的程序,也就是可以用来运行裸机程序。
3.run命令
run命令用于运行环境变量中定义的命令,比如可以通过“run bootcmd”来运行bootcmd中的启动命令,但是run命令最大的作用在于运行我们自定义的环境变量。如运行AHL-STM32MP157开发板时,输入命令run bootcmd_stm32mp即可。
4.mtest命令
mtest命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的DDR,命令格式如下:
mtest [start [end [pattern [iterations]]]] |
start是要测试的DRAM开始地址,end是结束地址,比如我们测试0x80000000~0x80001000这段内存,输入“mtest 80000000 80001000”。
后记
本文中仅包括U-Boot中的部分命令,更多命令欢迎各位在评论区讨论和反馈!