笔记整理—uboot番外(1)命令体系
在uboot启动进行命令行的环境下,当输入命令时,将会对命令进行先解析后执行的操作。
uboot/common/cmd_xxx.c 其中就有多个命令体系(mian.c和commann.c)
uboot每个命令都对应了一个相关的函数,由此实现的命令体系与shell的方式相似。其中参数一int类型的argc与char*argv[]组成。命令+参数,在Linux体系中,之类也是算作argc中的一员。
eg:
help ping
argc=2;
argv[0]="help";
argv[1]="ping";
相关的代码为int do_help(cmd_tbl_t *cmdtp,intflag,intargc,char *argv[]);
mian_loop的函数命令解析过程:
将console_buffer复制到last_command中,console_buffer是命令(输入的命令),并以run_command函数去执行命令。
run_command(const char *cmd,int flag),clear_ctrlc()中断执行。
CFG_CBSIZE,规定的最长命令码长度一般为256/512。
将输入的指令复制到cmdbuf中进行解析,根据‘\’‘\\’‘;’等输入规则进行解析。
parse_line负责进一步对指令进行解析,将md 30000000 10解析为:
argv[0]="md";
argv[1]="30000000";
argv[2]="10";
find_cmd(argv[0]);用于查找是否有这个指令,将找到的指令写到cmdtp中,repeatable支持了在命令输入时的回车重复,max_args设定了最大的参数个数。
cmdtp->cmd存有命令的函数指针。(cmdtp->cmd) (cmdtp,flag,argc,argv)。以函数指针去调用用于执行的对应函数。
命令执行在于find_cmd对指令的查找,取决于uboot对命令体系的机制(注册、存储、管理、索引等)。
存储指令集的方法常用的有两种:①数组:大小不好确定,很容易造成浪费或不够。②链表:虽然灵活但开销大。uboot只是一个裸机程序并没有使用上面的两个方式,而是使用了结构体进行存储。
struct cmd_tbl_s {
char *name;//命令名称
int maxargs;//最大参数个数
int repeatable;//是否支持重复执行(回车)
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);//命令所对应的函数指针
char *usage;//命令短的帮助信息
#ifdefCFG_LONGHELP
char *help;//命令长的帮助信息
#endif
#ifdef CONFIG_AUTO_COMPLETE
int (*complete)(intargc, char *argv[], charlast_char, intmaxv, char *cmdv[]);
//函数指针,指向自动补全指令的函数
#endif
};
对于一个命令来说,需要解决两个问题其一是填充结构体实例,其二是给命令结构体附加特点的段属性。
给命令结构体附加特点的段属性,链接时会带有该段属性内容链接在一起排列(什么东西放什么地方)。用户自定义段命令与命令是相互紧贴的,链接器工作时会将段属性相互放在一起。命令放在u_boot.bin中,同时命令是无序的,但一定是放在一起的。段有起始与结束地址,所以知道在哪开始,在哪结束。
在uboot.lds中,uboot不支持命令在启动后进行拓展,所以使用了一种依靠链接器与段方法去实现,像是一个无序的数组。
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)\
cmd_tbl_t __u_boot_cmd_##name struct_Section = \
{#name, maxargs, rep, cmd, usage, help}
其中,cmd_tbl_t是一个结构体,struct_Section是一个宏。以U_BOOT_CMD(version,1,1,do_version,"version-print monitor version\n",NULL);为例。
使用##做连字符,U_BOOT_CMD宏,关键在于结构体变量名与段属性。段属性就是标签,附加了用户自定义的段属性,以保证链接时候数据结构能链接到一起,每个函数都对应了一个U_BOOT_CMD组成的指令。
本章先写到这,下一章我们将对find_cmd函数做解析。