main.c中的代码实现了将一个命令的所有参数分离存放在argv数组中,参数的数目为argc,完成了读取命令行和解析命令行的工作。命令的处理由common/command.c文件中的函数完成。U-Boot在include/command.h中定义了一个非常重要的cmd_tbl_s结构体,它在命令的实现方面起着至关重要的作用。
struct cmd_tbl_s {
char *name; /* 命令名称 */
int maxargs; /* 命令的最大参数 */
int repeatable; /* 是否可重复(按回车键是否会重复执行)
*/
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []); /* 命令响应函数*/
char *usage; /* 简短的用法说明 */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* 较详细的帮助*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* 响应自动补全参数*/
int (*complete)(int argc,char*const argv[],char last_char,int maxv,char*cmdv[]);
#endif
};
cmd_tbl_s结构体包含的成员变量:命令名称、最大参数个数、可重复性、命令响应函数、用法、帮助和命令补全函数,每个命令都由这个结构体来描述。当输入“help”或者“?”会打印出所有的命令和它的usage,输入“help”或者“?”和命令名称时,会打印出help信息。
添加一个命令时,利用宏U_BOOT_CMD定义一个新的cmd_tbl_s结构体,并对这个结构体初始化和定义结构体的属性。例如,在文件common/cmd_bdinfo.c中:
U_BOOT_CMD(
bdinfo, 1, 1, do_bdinfo,
"print Board Info structure",
""
);
增加了一个命令,它的名称为bdinfo,最大参数数目为1,可重复,响应函数是do_bdinfo, usage为“print Board Info structure”,没有帮助信息。U_BOOT_CMD宏在include/command.h中定义,当不配置命令补全时,它最终被展开为:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
cmd_tbl_t __u_boot_cmd_##name __attribute__((unused, section(".u_boot_cmd"), aligned( 4))) = {#name, maxargs, rep, cmd, usage, help}
其中,“##”与“#”是预编译操作符,“##”表示字符串连接,“#”表示后面紧接着的是一个字符串。cmd_tbl_t就是struct cmd_tbl_s,用于__u_boot_cmd_##name结构体。
__attribute__定义了结构体的属性,将结构体放在.u_boot_cmd段中。简单的说,就是利用U_BOOT_CMD定义struct cmd_tbl_s结构体变量,并把类变量都放在一个段中。
在链接脚本中指定了.u_boot_cmd段的起始地址和结束地址,又已知每个struct cmd_tbl_s结构体占用内存空间的大小,这样就很方便地遍历所有的struct cmd_tbl_s结构体。这种巧妙的方式充分利用了链接器的功能特点,避免了花费大量的精力,去维护和更新命令结构体表。
cmdtp = find_cmd(argv[0]);
if (cmdtp == NULL) {
printf("Unknown command '%s' - try 'help'n", argv[0]);
return 1;
}
cmd_process函数首先调用find_cmd函数根据传入的参数,在.u_boot_cmd段区域查找命令,如果没有找到对应的命令,打印出提示信息并返回。
如果找到则返回命令结构体 cmdtp,再检查传入参数的合法性,最后通过cmd_call函数调用命令响应函数(cmdtp->cmd)(cmdtp, flag, argc, argv)。
全部0条评论
快来发表一下你的评论吧 !