命令体系基本概述:
- uboot启动后进入命令行模式,即可输入命令
- uboot会进行命令接收,命令解析,命令执行操作
- uboot的命令体系实现代码在uboot/common/cmd_xx.c中(command.c 和main.c也和命令相关)
- 每个命令都对应一个函数
- 有些命令支持传参(和main参数传参差不多),使用argc&argv传递,比如" print ipaddr "会以argc(2),argv(argv[0] = print,argv[1] = ipaddr)传递给命令函数
命令体系解析:
main_loop函数:
在uboot启动第二阶段结束后,会进入main_loop函数进行死循环
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
main_loop函数执行一次,就是一个获取,解析,执行命令的过程(main_loop应该是一个阻塞式函数)
run_command函数:
在main_loop函数里解析之后用run_command函数执行命令
- 调用parse_line函数将命令分解,比如" print ipaddr "分成argv[0] = print,argv[1] = ipaddr
- 然后调用find_cmd(argv[0])函数去uboot的命令集合当中搜索有没有argv[0]这个命令,找到后find_cmd函数返回函数指针
- 执行命令
命令的可能管理方式:
- 数组(结构体数组,每个结构体中存放命令的各种信息),最简单的实现方式,但是增减不便
- 链表,链表的每个节点data段放一个结构体存放命令信息,但是占空间大,算法稍麻烦
- uboot使用另一种方式,
(1)使用结构体保存命令的各种信息
(2)命令结构体全部放在用户自定义段(给命令附加特殊的段属性,就像.bss段,.data段),链接时将带有该段属性的内容链接在一起排列
(3)uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组
(4)段的起始和结束地址决定了命令集的范围(在链接脚本u-boot.lds里面定义),如下图:
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
具体分析:
命令结构体cmd_tbl_t:
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
定义了命令的具体信息:
- name 名称
- maxargs 可接收的最大参数个数
- repeatable 是否可重复执行,重复执行是uboot命令行的一种工作机制,就是直接按回车则执行上一条执行的命令
- cmd,函数指针,指向这个命令的具体实施函数
- usage:命令的短帮助信息。对命令的简单描述
- help:命令的长帮助信息。细节的帮助信息
- complete:函数指针,指向这个命令的自动补全的函数
总结:uboot的命令体系在工作时,一个命令对应一个cmd_tbl_t结构体的一个实例,然后uboot支持多少个命令,就需要多少个结构体实例。uboot的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。
分析一个命令:
version命令,执行结果如下:
执行后打印uboot版本信息。
下面是命令的执行函数和相关宏:
int
do_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
extern char version_string[];
printf ("\n%s\n", version_string);
return 0;
}
U_BOOT_CMD(
version, 1, 1, do_version,
"version - print monitor version\n",
NULL
);
U_BOOT_CMD宏分析:
每个命令函数都带有一个U_BOOT_CMD宏,该宏定义如下:
#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}
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
- ##name是指将传进来的name参数替换##name
- Struct_Section 宏是附加链接属性用的
version命令的U_BOOT_CMD
U_BOOT_CMD(
version, 1, 1, do_version,
"version - print monitor version\n",
NULL
);
展开后变成
cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}