读书笔记--uboot命令体系
1、uboot命令体系的实现代码在uboot/common/cmd_xxx.c中。有若干个.c文件和命令体系有关。(还有command.c main.c也是和命令有关的)
2、每一个uboot的命令背后都对应一个函数。
3、有些uboot的命令还支持传递参数。也就是说命令背后对应的函数接收的参数列表中有argc和argv,然后命令体系会把我们执行命令时的命令+参数(md 30000000 10)以argc(3)和argv(argv[0]=md, argv[1]=30000000 argv[2]=10)的方式传递给执行命令的函数。
4、uboot命令解析和执行过程分析
(1)uboot启动的第二阶段,在初始化了所有该初始化的东西后,进入了一个死循环,死循环的循环体就是main_loop。
(2)main_loop函数执行一遍,就是一个获取命令、解析命令、执行命令的过程。
(3)run_command函数就是用来执行命令的函数。
5、run_command函数详解(关键点分析)
(1)控制台命令获取
(2)命令解析。parse_line函数把"md 30000000 10"解析成argv[0]=md, argv[1]=30000000 argv[2]=10;
(3)命令集中查找命令。find_cmd(argv[0])函数去uboot的命令集合当中搜索有没有argv[0]这个命令,
(4)执行命令。最后用函数指针的方式调用执行了对应函数。
6、uboot如何处理命令集
命令结构体cmd_tbl_t
1 struct cmd_tbl_s { 2 char *name; /* Command Name */ 3 int maxargs; /* maximum number of arguments */ 4 int repeatable; /* autorepeat allowed? */ 5 /* Implementation function */ 6 int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); 7 char *usage; /* Usage message (short) */ 8 #ifdef CFG_LONGHELP 9 char *help; /* Help message (long) */ 10 #endif 11 #ifdef CONFIG_AUTO_COMPLETE 12 /* do auto completion on the arguments */ 13 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]); 14 #endif 15 }; 16 typedef struct cmd_tbl_s cmd_tbl_t;
(1)name:命令名称,字符串格式。
(2)maxargs:命令最多可以接收多少个参数
(3)repeatable:指示这个命令是否可重复执行。重复执行是uboot命令行的一种工作机制,就是直接按回车则执行上一条执行的命令。
(4)cmd:函数指针,命令对应的函数的函数指针,将来执行这个命令的函数时使用这个函数指针来调用。
(5)usage:命令的短帮助信息。对命令的简单描述。
(6)help:命令的长帮助信息。细节的帮助信息。
(7)complete:函数指针,指向这个命令的自动补全的函数。
总结:uboot的命令体系在工作时,一个命令对应一个cmd_tbl_t结构体的一个实例,然后uboot支持多少个命令,就需要多少个结构体实例。uboot的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。
7、uboot实现命令管理的思路
(1)填充1个结构体实例构成一个命令
(2)给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的,但是顺序是乱序的)。
(3)uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。
(4)段起始地址和结束地址(链接地址、定义在u-boot.lds中)决定了这些命令集的开始和结束地址。
8、uboot命令定义具体实现分析
(1)U_BOOT_CMD宏基本分析
这个宏定义在uboot/common/command.h中。
1 U_BOOT_CMD( 2 version, 1, 1, do_version, 3 "version - print monitor version\n", 4 NULL 5 );
这个宏替换后变成:
cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}
总结:这个U_BOOT_CMD宏的理解,关键在于结构体变量的名字和段属性。名字使用##作为连字符,附加了用户自定义段属性,以保证链接时将这些数据结构链接在一起排布。
(2)链接脚本。
9、find_cmd函数详解
(1)find_cmd函数的任务是从当前uboot的命令集中查找是否有某个命令。如果找到则返回这个命令结构体的指针,如果未找到返回NULL。
(2)函数的实现思路很简单,如果不考虑命令带点的情况(md.b md.w这种)就更简单了。查找命令的思路其实就是for循环遍历数组的思路,不同的是数组的起始地址和结束地址是用地址值来给定的,数组中的元素个数是结构体变量类型。
10、U_BOOT_CMD宏详解
(1)这个宏其实就是定义了一个命令对应的结构体变量,这个变量名和宏的第一个参数有关,因此只要宏调用时传参的第一个参数不同则定义的结构体变量不会重名。
11、在已有的c文件中直接添加自定义命令
(1)在uboot/common/command.c中添加一个命令,叫:mycmd
(2)在已有的.c文件中添加命令比较简单,直接使用U_BOOT_CMD宏即可添加命令,给命令提供一个do_xxx的对应的函数这个命令就齐活了。
(3)添加完成后要重新编译工程(make distclean; make x210_sd_config; make),然后烧录新的uboot去运行即可体验新命令。
(4)还可以在函数中使用argc和argv来验证传参。
12、自建一个c文件并添加命令
(1)在uboot/common目录下新建一个命令文件,叫cmd_aston.c(对应的命令名就叫aston,对应的函数就叫do_aston函数),然后在c文件中添加命令对应的U_BOOT_CMD宏和函数。注意头文件包含不要漏掉。
(2)在uboot/common/Makefile中添加上aston.o,目的是让Make在编译时能否把cmd_aston.c编译链接进去。
(3)重新编译烧录。重新编译步骤是:make distclean; make x210_sd_config; make
总结:
uboot中命令行的实现原理:
uboot中设备的输入输出是通过串口来作为标准输入输出的,我们可以通过securecrt软件来接受设备从串口发出的信息,也可以通过securecrt软件写入串口向设备中发送命令;
所以在设备调试的时候通常都是通过打印串口信息调试的;
第一步:在主函中设置一个死循环用来接受处理命令,并打印信息;uboot中这个函数是main_loop函数;
main_loop函数所做的具体的事情有:
1:读取sercurecrt命令行中发送的串口信息,并把读取的字符串信息保存在一个局部变量字符串数组lastcommand中:函数为 len = readline (CFG_PROMPT);
2:执行lastcommand字符串数组中保存的命令rc = run_command (lastcommand, flag);
第二步:在readline函数中所要做的事情就是把从命令行中接收到的信息进行初步处理,把处理好以后的字符串放入全局变量console_buffer中;
readline函数所做的具体事情:
1:输出x210 #
2:调用cread_line函数从securecrt中命令行中读取命令,并进行初步的处理;
分析一下cread_line函数中所做的事情:
1:ichar = getcmd_getch();这个函数是从串口中读取信息;如果读取到'\n'或者'\r'的话表示输入完成;
2:之后的代码就是处理键盘的特殊字符详细解释可以看一下这篇博客
http://blog.chinaunix.net/uid-30031530-id-5152127.html
第三步:rc = run_command (lastcommand, flag)函数中要进一步处理lastcommand中的字符串
1:调用process_macros函数 处理字符串中的转义字符;
2:调用parse_line函数统计argc、赋值argv
3:调用find_cmd命令查找相应命令返回命令的结构体指针;
4:(cmdtp->cmd) (cmdtp, flag, argc, argv)以函数指针的方式来执行命令函数;
https://www.cnblogs.com/biaohc/p/6394710.html