历史上的今天
返回首页

历史上的今天

今天是:2025年02月22日(星期六)

2021年02月22日 | cortex-a8 uboot系列:第十三章 uboot命令体系

2021-02-22 来源:eefocus

一、uboot命令实现代码

Uboot命令体系的实现代码在common/cmd_xxx.c中。有若干个.c文件和命令体系有关。(还有command.c  main.c)

 

每个命令对应一个函数

每一个uboot的命令背后都对应一个函数。这就是uboot实现命令体系的一种思路和方法。

 

命令参数以argc&argv传给函数

有些uboot的命令还支持传递参数。也就是命令对应的函数接收的参数列表中有argc和argv,然后命令体系会把执行执行命令时的命令+参数(如md 0x30000000 10)以argc(3)和argv(argv[0]=”md” argv[1]=”0x30000000” argv[2]=”10”)的方式传递给执行命令的函数


二、Help命令为例

使用U_BOOT_CMD宏定义。

clip_image002

对于help命令,长说明有6行,分别用6行字符串表示,中间不能有逗号,gcc编译会自动将6行字符串合并为一个。

 

help命令背后对应的函数名叫:do_help函数(common/command.c)

clip_image004

 

1.不带参数

clip_image006

首先对参数进行判断,如果只有1个参数,说明输入是help,要打印所有的命令信息。

定义一个命令数组指针,然后循环uboot所有命令,依次赋值给数组指针cmd_array。

clip_image008

对于这段代码,调试打印出下列信息。

clip_image009

&__u_boot_cmd_end - &__u_boot_cmd_start是一个指针运算,结果为(0xc3e58f88 – 0xc3e58959) / sizeof(cmd_tbl_t) = 1584 / 24 = 66。也就是共有66个命令。


__u_boot_cmd_end和__u_boot_cmd_start两个变量是定义在链接脚本中的。对于汇编代码,或者c代码,是可以引用链接脚本中的变量的。


所以新建了66个大小的数组指针cmd_array,因为每一个cmd_array大小是4个字节(只要是指针,大小都是4个自己),所以cmd_array的总大小就是66*4 = 264

 

clip_image011

cmd_tbl_s(include/command.h)是uboot命令的结构体,里面有多个参数。

clip_image013

使用extern 从外部引入两个变量__u_boot_cmd_start和__u_boot_cmd_end。这两个变量是在链接脚本中定义的。

clip_image015

其实__u_boot_cmd_start和__u_boot_cmd_end是两个标号,分别对应两个地址,一个uboot命令集的起始地址,另一个对应uboot命令集的结束地址。

C语言中将两个标号引入为两个cmd_tbl_s结构体的变量。在后面的程序中就可以使用这两个变量。

clip_image017

执行结果:

clip_image018

反汇编程序中,autoscr命令的执行函数确实是在地址0xc3e09244。

clip_image020

 

clip_image022

使用冒泡排序,对数组指针cmd_array,按照命令的名字进行排序。

 

clip_image024

最后打印所有命令的用法。


2.带参数

help命令可以带参数,表示打印执行命令的help信息。

clip_image026

对于参数超过1个,说明是要打印第二个参数的具体用法。


使用find_cmd函数(common/command.c中)查找指定命令,找到后,返回命令的指针。利用该指针,就可以知道命令的名字,命令的帮助,命令的用法,将之打印。

如果没有找到,就打印未知命令。

clip_image028

 

三、Uboot命令解析和执行过程分析

从main_loop函数(start_armboot函数的最后)开始。main_loop函数在common/main.c中。

clip_image030

 

clip_image032

使用readline函数从串口接收一行数据,接收数据在console_buffer。然后将该数据复制到lastcommand,使用run_command函数去执行命令。

 

clip_image034

 

clip_image036

clear_ctrlc函数清除上一次输入的ctrl+c,uboot中支持输入ctrl+c打断操作。所以在命令之前之前,要将这个清除。


后面判断命令是否为空以及命令是否太长。


将命令拷贝到cmdbuf中。

 

clip_image038

parse_line函数把”md 0x30000000 10”解析成argv[0]=”md”, argv[1]=”0x30000000”  argv[2] = ”10”


find_cmd函数去uboot命令函数集合中搜索有没有argv[0]命令。在这里是找寻md命令。


检查参数对应命令是否正确。

 

clip_image040

使用函数指针执行命令函数。cmdtp->cmd。

四、Uboot的命令体系机制

1.Uboot对命令集的管理

可能的管理方式

数组: 结构体数组,数组中每一个结构体成员就是一个命令的所有信息。

链表: 链表的每个节点data段就是一个命令结构体,所有的命令都放在一条链表上。这样解决了数组方式的不灵活。坏处是需要额外的内存开销,然后各种算法(遍历、插入、删除等)需要一定复杂度的代码执行。

 

Uboot没有使用数组或者链表,而是使用了一种新的方式来实现这个功能。

 

命令结构体:cmd_tbl_s

clip_image042

name:命令的名字,字符串格式

maxargs:命令的最大接收参数个数

repeatable:命令是否可重复执行。重复执行是uboot命令行的一种工作机制,就是直接按回车则执行上一条执行的命令

cmd:命令执行函数指针,指向命令对应的执行函数,将来执行这个命令的函数时使用这个函数指针来调用

usage: 命令的短帮助信息。对命令的简单描述

help:命令的长帮助信息。命令的细节帮助信息,可以配置没有。

complete:自动补全函数指针。指向命令的自动补全函数,可以配置没有。

 

总结

Uboot的命令体系在工作时,一个命令对应一个cmd_tbl_s结构体的一个实例,然后uboot支持多少个命令,就需要多少个结构体实例。Uboot的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。


2.Uboot实现命令管理的思路

1)填充1个结构体实例构成一个命令

2)给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的)。

3)Uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。

4)段起始地址和段结束地址(链接地址、定义在u-boot.lds中)决定了这些命令的开始地址和结束地址


3.U_BOOT_CMD宏

uboot使用U_BOOT_CMD宏来进行uboot命令的定义。这个宏在common/command.h中。

clip_image044

##在宏定义中是连字符。将__u_boot_cmd_和name连在一起作为一个整体。

#a是将a转化为字符串

 

如下面这个uboot命令version:

clip_image046

U_BOOT_CMD展开后,就成为了

         cmd_tbl_t   __u_boot_cmd_version  __attribute__ ((unused,section (".u_boot_cmd"))) =

                            {“version”, 1, 1 , do_version, "version - print monitor versionn",NULL};

将结构体变量__u_boot_cmd_version,赋了初始值,然后放入到最终bin文件的.u_boot_cmd段中。


这样就定义了一个命令version,和函数do_version关联。最大参数为1,可重复执行,用法是version - print monitor version,没有帮助信息。

 

         .u_boot_cmd段定义在链接脚本中。

clip_image048

总结:

这个U_BOOT_CMD宏的理解,关键在于结构体变量的名字和段属性。变量名使用##连字符来生成。指定变量存放的段,这样链接器链接时将该变量放入到.u_boot_cmd段中。最后对该变量结构体进行赋值。


4.find_cmd函数

uboot使用find_cmd函数(common/command.c)来查找uboot命令。

         clip_image050

函数的任务就是从当前uboot的命令集中查找是否有某个命令,如果找到则返回命令的结构体指针,没有找到返回NULL。

clip_image052

定义cmd_tbl_t类型的指针cmdtp_temp,指向__u_boot_cmd_start的地址处。__u_boot_cmd_start的地址为.u_boot_cmd的起始地址。

 

clip_image054

从命令中找寻 . 的位置,因为有的命令是有带 . 的。 如md.b命令

最终len得到.之前的字符长度

如md.b  0x30000000     len = 2

如md    0x30000000    len = 2 + 4 + 10 = 16

 

clip_image056

循环从.u_boot_cmd段中的第一个cmd_tbl_t变量开始寻找,一直找到.u_boot_cmd段中的最后一个cmd_tbl_t。


通过strncmp (cmd, cmdtp->name, len),判断输入的命令是否和uboot的命令是否一样。返回0表示一样,即找到命令。

 

clip_image057

如果之前计算得到的长度和uboot的命令长度一致,说明命令匹配,返回uboot命令的cmd_tbl_t类型指针。

 

clip_image059

如果长度不一致,将命令指针保存到cmdtp_temp命令临时指针。

以上的情况是解决md.b 这种类型的命令。

 

clip_image061

当是简短命令,即md.b这种类型,就把cmdtp_temp命令临时指针返回,否则返回NULL。

 

总结:

查找命令的思路其实就是for循环遍历数组的思路,不同的是数组的起始位置和结束地址是用地址值来给定的,数组中的元素类型是结构体cmd_tbl_t类型。

5.U_BOOT_CMD宏详解

这个宏其实就是定义了一个命令对应的结构体变量,这个变量名和宏的第一个参数有关,因此只要调用时传参的第一个参数不同则定义的结构体变量不会重名。并且链接器会将该变量放入到.u_boot_cmd段中。

 

一个简单的C测试。

clip_image063

使用gcc –E 预编译。查看,宏被替换为以下。

clip_image065

五、Uboot中增加自定义命令

在已有的c文件中直接添加命令

1)在common/command.c中添加一个命令

2)直接使用U_BOOT_CMD_宏皆可添加命令,给命令提供一个do_xxx对应的函数就可对这个命令进行使用

3)添加完成后要重新编译编译工程,生成的u-boot.bin即可。

 

下面以实现一个自定义命令为例:

自建一个c文件并添加命令

1) 在common目录下新建一个命令文件,名字如cmd_weiqi.c(相应的命名就叫weiqi,对应的函数就叫do_weiqi函数),然后在c文件中添加命令所对应的U_BOOT_CMD宏和函数。

clip_image067

2)在common里的makefile中添加上对应的cmd_weiqi.o,目的是让make在编译时能够把cmd_weiqi.c编译进去

clip_image069

对于COBJS-$(CONFIG_CMD_AMBAPP) += cmd_ambapp.o

如果宏CONFIG_CMD_AMBAPP定义,COBJS-y就加cmd_ambapp.o

宏CONFIG_CMD_AMBAPP如果定义,定义为y。没有定义,就是n。

 

3)重新编译烧录执行

clip_image070

推荐阅读

史海拾趣

BETA Transformer Technology Corp公司的发展小趣事

随着电子行业的快速发展和变革,BETA Transformer Technology Corp公司面临着前所未有的挑战。为了应对这些挑战,公司不断加大研发投入,加强技术创新,推出了一系列符合市场需求的新产品。同时,BETA公司还积极调整生产结构,优化供应链管理,降低成本,提高产品质量。这些举措使得BETA公司在激烈的市场竞争中保持了领先地位。

CSB公司的发展小趣事

在电子行业的初期,CSB公司以其独特的技术创新能力脱颖而出。公司研发团队在某一关键领域取得了重大突破,开发出了一款具有市场竞争力的新产品。这款产品不仅满足了消费者对性能和品质的高要求,还凭借其独特的设计和功能,吸引了大量忠实用户。随着产品的热销,CSB公司的知名度逐渐提升,市场份额也稳步增长。

富芯森美(FUXINSEMI)公司的发展小趣事

随着新能源汽车产业的快速发展,富芯森美敏锐地捕捉到了这一市场机遇。公司投入大量资源研发车规级功率半导体器件,产品设计遵循APQP标准,制造管理符合IATF 16949要求,质量检验则严格遵循AEC-Q101标准。这些举措使得富芯森美的车规级产品能够满足汽车行业的严苛要求,成功打入新能源汽车供应链体系,为公司带来了新的增长点。

Hoffman Engineering公司的发展小趣事

在Harry Hoffman的领导下,Hoffman Engineering不断扩展其产品线。从最初的压力机安全保护装置,公司逐渐研发出蒲公英掘具、碟靶投掷器、厨房用电动搅拌器等一系列创新产品。这些产品不仅丰富了Hoffman Engineering的市场布局,也展现了公司在不同领域的技术实力。特别是Hoffman的机柜系列产品,如接线箱和电源插座,逐渐成为市场上的热门产品,为公司带来了稳定的收入来源。

Computer Conversions Corp公司的发展小趣事

Computer Conversions Corp非常重视人才的培养和团队建设。公司定期组织内部培训和技术交流活动,鼓励员工分享经验和创新想法。同时,公司还建立了完善的激励机制,为员工提供广阔的发展空间。这种以人为本的管理理念,不仅增强了团队的凝聚力和创新力,也为公司的持续发展注入了强大的动力。通过这些举措,Computer Conversions Corp打造出了一支高素质、高效率的技术团队,为公司的长远发展奠定了坚实的基础。

Delta Electronics公司的发展小趣事

Delta Electronics在电源管理技术方面一直处于行业领先地位。公司不断投入研发资源,推动电源技术的创新和进步。其中,Delta开发的高效率开关式电源供应器,以其高效、稳定和可靠的性能,赢得了全球客户的广泛认可。此外,公司还积极推广绿色能源和节能技术,为客户提供环保、节能的电源解决方案。

问答坊 | AI 解惑

回答: ASIC是什么?FPGA是什么?

问: ASIC的中文翻译是专用集成电路,为什么说它是一种嵌入式微处理器呢?FPGA也是一种嵌入式微处理器吗?我听有人说FPGA指的是一种封装结构,这是正确的吗? 答: 用于专用应用场合的处理器就是嵌入式处理器,不管它是可编程的还是不可编程的。 ...…

查看全部问答>

LEM电流电压传感器

瑞士LEM互感器、LEM电流互感器、LEM电涌保护器、LEM传感器、LEM电压互感器、LEM电量传感器、LEM无线电能表 LEM 是全球电量传感器的知名制造者,也是电量传感器领域的领导者。 LEM集团全球拥有多家公司,销售办事处遍布全球。其中瑞士日内瓦、中 ...…

查看全部问答>

同步整流在WK283R3S-33M中的应用

1 概述 WK283R3S-33M电源模块为非密封灌封系列,其主要技术参数:VOUT=3.3 V,VIN=18 V~36 V,POUT=33 W,SI/Sv=0.5%,η=85%,VP-P=100 mV。该电源模块的外形为1/4砖,其主要特点为低压大电流输出模块、高效率和低纹波电压值、体积为1/4砖可 ...…

查看全部问答>

LPC2101无法仿真。看看是不是编译器的错?

RealView MDK-ARM Version:3.24 CPU是LPC2101 H-JTAG 0.8 软件仿真正常。 现象是仿真器连接都正常。 硬件仿真 在Startup.s中还正常,转向main()函数就死机。 查了好多天了。今天忽然注意到软件仿真的程序地址0x000041A4(比16K还多) 而LPC2 ...…

查看全部问答>

今年的电子设计大赛专科组的怎么做啊?

本帖最后由 paulhyde 于 2014-9-15 09:09 编辑 今年的电子设计大赛专科组的怎么做啊?  …

查看全部问答>

【藏书阁】贴片元器件应用手册

目录: 第一部分 贴片元器件基础知识 1.1片状电阻器 1.1.1片状电阻器的阻值和允差标注方法 1.1.2常见片状电阻器介绍 1.1.3片状电阻器的使用 1.2片状电容器 1.2.1片状电容器容量和允差标注方法 1.2.2常见片状电容器介绍 1.2 ...…

查看全部问答>

三端稳压器(78、79系列)管脚序号判断技巧 大赛资料

本帖最后由 paulhyde 于 2014-9-15 09:21 编辑 在78**、79**系列三端稳压器中最常应用的是TO-220和TO-202两种封装。这两种封装的图形以及引脚序号、引脚功能如附图所示。 图中的引脚号标注方法是按照引脚电位从高到底的顺序标注的。这样 ...…

查看全部问答>

就做开发板吧:

    就做开发板吧!可以大家一起做。分析如下:     驱动2.4寸320*240 TFT 彩色液晶,这个只有用IO口模拟LCD的8位总线,最低需要耗费10个IO。这个并不难,难度系数0.3。     驱动SD卡,通过SPI接口 ...…

查看全部问答>

S3C2440平台WinCE5.0中串口发送堵塞现象的疑惑

S3C2440平台WinCE5.0中串口发送堵塞现象的疑惑:    本人开发一个软件,使用TQ公司的SKY2440开发板为模板,使用的是从4.2移植到wince5.0使用的BSP包。    该软件需要用到2个串口(COM0和COM1),TCP/UDP编程;修改MDD层的mdd ...…

查看全部问答>

2440 Camera接口配置

大家好,我请教一个关于2440的问题。我用2440连接一个ITU656接口时序的摄相头,为什么一直接不到同步信号?模块出来的同步开始是(FF,00,00,80),结束是(FF,00,00,90)。2440的ForthWord中的F,V,H是不是同步信号线上的电平?…

查看全部问答>