一、uboot的命令体系基础
1、uboot命令体系的实现在uboot/common/cmd_xxx.c中,有若干个.c文件,还包括common.c和main.c文件,
2、每一个命令对应着一个函数,但是也不是完全对应的:
- 一个函数对应着一个命令或者多个命令,
- 找到命令对应的函数,对应着关系;
- 以argc和argv的方式,进行传参;
二、uboot的命令解析和执行过程分析
1、从main-lopp说起
(1)main_loop函数,在board.c中的start_armboot函数中,是uboot进入命令行的函数。这个函数的主要作用就是获取从命令输入的命令,然后解析命令(命令是否存在,命令参数是否正确),执行命令。
2、run_command函数
(1)函数的功能:用来执行从命令行传递进来的参数
(2)parse_line()把传递的命令进行分割,例如输入的命令为“md 0x30000000 10”,通过这个函数把这个字符串解析成argv[0] = md,argv[1] = 0x30000000,argv[2] = 10。
(3)find_cmd()函数是查找命令,是否在uboot的命令集中,如果找到则返回这个命令所对应的结构体指针,没有找到则返回NULL。
(4)如果找到,find_cmd函数则会返回一个命令结构体,通过命令结构体中的函数指针,执行相应的的命令函数。
三、uboot如何处理命令集
1、可能的管理方式
在uboot拥有很多的命令,那么uboot怎么管理这些命令,通过什么方式呢?
(1)数组的方式,通过建立一个命令结构体的数组来管理命令集。
(2)通过链表的方式来管理命令集。
(3)第三种方式?
2、uboot管理命令集的方式,既不是数组也不是链表。
命令结构体,uboot通过一个命令结构体来管理命令,一个命令结构体变量对应着一个命令,类似于高级语言中的类和对象的关系。结构体类型就是类,变量就是对象。
struct cmd_tbl_s {
char *name; //命令的名字
int maxargs; //命令所带的最大参数个数
int repeatable; //是否可重复,也就是enter键,重复上一个指令。
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); //命令函数
char *usage; //命令的短帮助
#ifdef CFG_LONGHELP
char *help; //命令的长帮助
#endif
#ifdef CONFIG_AUTO_COMPLETE //自动补全功能
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s cmd_tbl_t;
所以常见一个命令,就需要实例化这么一个对象即可。
3、uboot实现命令管理的思路,即uboot的命令集在哪,怎么找?
给命令结构体的对象添加特定的段属性(用户自定义段),链接的时候将带有该段属性的内容链接在一起排列,所以各个命令之间是连续排列的,类似与数组的在内存中的存储方式,但是顺序不同于数组那么固定,每个位置的命令都是不能够确定的。
uboot重定位的时候,将该段整体加载到DDR中,加载到DDR中的uboot镜像中,带有特定段属性的这一段就是命令结构体集合。
段起始地址和结束地址,在链接脚本中都用指定,这样我们就可以得到命令结合的起始地址和结束地址了。便于我们访问命令集。
四、uboot如何实现命令集
1、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}
总的来说,这个宏就是定义了一个cmd_tbl_t 结构体类型的变量,变量的名字,以及给这个结构体变量赋值。
这里以version命令为代表解释:
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"))) =
{
"version",
1,
1,
do_version,
"version - print monitor version\n",
NULL,
};
- ##name就替换成了version
- #name这个#的作用,就是将version变成了字符串"version"。
- Struct_Section是__attribute__ ((unused,section (".u_boot_cmd"))),也就是在这里指定段属性,表示是一个命令,在链接的时候都放在一起。
五、如何添加自己的命令,在command.c中添加
1、创建命令对应的宏
U_BOOT_CMD(
mycmd, 1, 1, do_mycmd,
"mycmd - mycmd usage\n",
"mycmd help\n"
);
2、创建命令处理函数
int
do_mycmd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
printf("this is mycmd");
return 0;
}
其实就是按照原有的命令实现方式,进行移植就可以了。
总结:可见uboot这种处理命令集的方式,我们添加或者删除一个命令都非常的方面,只需要建立一个结构体对象,和创建一个对应的命令函数即可,其他的完全不用顾虑。不用像使用数组那样担心越界,不用向使用链表那样麻烦,我很欣赏这种方式,感觉很好。第一次见到这样的实现方式。