Uboot1.3.4下命令体系结构

时间:2024-04-03 09:24:41

2020-6-27星期六 闷热 端午节最后一天假期啦!本文仅作为技术积累的记录,方便日后查阅!

 

1.当前Uboot实现的命令流程代码分析

uboot命令解析和执行过程分析

从main_loop说起

uboot启动的第二阶段,在初始化了所有该初始化的东西后,进入了一个死循环,死循环的循环体就是main_loop()。main_loop函数执行一遍,就是一个获取命令、解析命令、执行命令的过程。

main_loop()中先通过环境变量bootdelay获取对应的时长,不输入任何按键则执行启动内核命令bootm。在该时间内按任意键可以进入uboot的命令行,输入各种命令实现在uboot下的不同功能。

Uboot1.3.4下命令体系结构

之后main_loop()会调用run_command()来解析从命令行传入的命令串,参数cmd是命令字符串

Uboot1.3.4下命令体系结构

run_command()中会对命令串做如下处理:

  • 对; 等特殊字符的处理
  • 命令解析。parse_line函数把"md 30000000 10"解析成argv[0]=md, argv[1]=30000000 argv[2]=10;

Uboot1.3.4下命令体系结构

  • 命令集中查找命令。find_cmd(argv[0])函数去uboot的命令集合当中搜索有没有argv[0]这个命令,

Uboot1.3.4下命令体系结构

  •    执行命令。最后用函数指针的方式调用执行了对应函数。

Uboot1.3.4下命令体系结构

 

关键点就在于find_cmd函数如何查找到这个命令是不是uboot的合法支持的命令?这取决于uboot的命令体系机制(uboot是如何完成命令的这一套设计的,命令如何去注册、存储、管理、索引。)。

 

2.Uboot命令行实现机制原理

可能的实现机制

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

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

(3)有第三种吗?uboot没有使用数组或者链表,而是使用了一种新的方式来实现这个功能。

Uboot下命令体系结构如下: __u_boot_cmd_start和__u_boot_cmd_end变量所在的内存地址代表命令集所占内存区域的起始地址和结束地址

Uboot1.3.4下命令体系结构

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

Uboot命令的存储管理的方法:

  • 一个命令相关信息都存储到对应的结构体实例中。将每一个命令对应的结构体变量定义时,为其添加自定义段属性(类似于代码段,数据段,只是我们这是自定义段)。
  • 链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的,但是顺序是乱序的)。

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

段起始地址和结束地址(链接地址、定义在\uboot\board\samsung\x210\u-boot.lds中)决定了这些命令集的开始和结束地址。在uboot执行前就已经在链接脚本中决定。  __u_boot_cmd_start标号所在的地址就是众多命令结构体地址集合的起始地址

Uboot1.3.4下命令体系结构

那链接脚本中的地址是如何传入C文件中的呢?

具体可以查看这篇文章  https://blog.csdn.net/thisway_diy/article/details/101016296

Uboot命令的查找方法:

内存排布与结构体数组类似,指针指向下一个结构体对应的内存就是另外一个命令对应的结构体数据

3.uboot命令定义具体实现分析

U_BOOT_CMD宏基本分析(宏定义在uboot/common/command.h中)

以uboot下敲version命令为例:

Uboot1.3.4下命令体系结构

命令行的定义:

Uboot1.3.4下命令体系结构

****begin:U_BOOT_CMD宏定义解析*******

其中U_BOOT_CMD中参数:①命令②参数最大个数③req④命令的实现函数⑤uboot下仅输入”help”时打印的信息⑥输入”help+命名名称”打印的信息

Uboot1.3.4下命令体系结构

##name是name , 转换为该命令对应的结构体变量__u_boot_cmd_name

#name 是将name ,转换为该命令对应的字符串”name”

写个代码预处理一下,简单验证下这个宏定义的替换

Uboot1.3.4下命令体系结构

Uboot1.3.4下命令体系结构

****end****

对于version命令这个宏替换后会变成:

cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}

总结:这个U_BOOT_CMD宏的理解,关键在于结构体变量的名字和段属性。名字使用##作为连字符,附加了用户自定义段属性,以保证链接时将这些数据结构链接在一起排布。

 

再看一下find_cmd()函数实现就懂了

Uboot1.3.4下命令体系结构

Uboot下新建一个命令行

命令相关的都在\uboot\common目录下以cmd_xxx.c命名,一个命令对应一个C文件。其中common.c文件中包含多个命令,可能是早期命令较少,都放入这里了。

我们先在common.c中写一个命令:Uboot1.3.4下命令体系结构

编译下载后uboot下输入help可以查看该命令

Uboot1.3.4下命令体系结构

Uboot1.3.4下命令体系结构

之后再正规一点,单独搞个文件cmd_dyztest.c。 勿忘将cmd_dyztest.o加入该目录下Makefile中

Uboot1.3.4下命令体系结构

按照uboot书写命令规范,cmdname为命令串,那么对应的回调执行函数为do_cmdname。

编译下载后:

输入help

Uboot1.3.4下命令体系结构

输入几个参数

Uboot1.3.4下命令体系结构

 

总结: 通过在链接脚本中自定义段(各个命令对应的结构体数据结构的集合),这样在访问命令时可以以类似数组形式访问。 在命令定义时,将该命令与自定义段绑定,相当于贴上了标签,链接时这些具有标签属性的结构体变量内存关联在连续的内存空间中。

实际添加命令时,仅需要U_BOOT_CMD宏中定义变量,在对应的回调函数中实现功能即可。