一、uboot命令定义分析
1.1、.u_boot_cmd段
相信很多人在初次接触uboot都会找不到uboot命令表的定义在哪里,这是因为uboot命令表的起始地址定义在了链接脚本中,而uboot命令表的内容是使用section关键词指定变量到uboot命令表地址的。
在u-boot.lds文件中有如下一段代码:
__u_boot_cmd_start = .;//.表示当前地址
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
- 这段代码的意思是__u_boot_cmd_start这个变量的地址是为当前地址,我们不需要关注这个地址是多少;
- .u_boot_cmd : { *(.u_boot_cmd) }声明了一个名为u_boot_cmd的的代码段,我们可以在c代码中使用section关键词指定变量或者函数到这个段所在的地址中;
- __u_boot_cmd_end指定了u_boot_cmd段的结束地址,这个地址由系统自动计算;
1.2、U_BOOT_CMD宏定义
接下来我们看下U_BOOT_CMD的定义:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,NULL)
#define U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = \
U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp)
#define Struct_Section __attribute__((unused, section(".u_boot_cmd"), \
aligned(4)))
#define U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \
{#name, maxargs, rep, cmd, usage, _CMD_HELP(help) _CMD_COMPLETE(comp)}
将上述宏定义结合到一起得到如下关于U_BOOT_CMD的定义:
#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, _CMD_HELP(help) _CMD_COMPLETE(comp)}
##表示字符串连接符,在这个宏定义中,我们使用__attribute__关键词将__u_boot_cmd_##name变量指定到了.u_boot_cmd所在的段中。这样我们就可以通过__u_boot_cmd_start这个地址来访问U_BOOT_CMD定义的变量。
1.3、cmd_tbl_t结构体
你可以把uboot的命令理解成一张表,每个表格中记录了表的名称等信息。我们在查找表的时候可以根据表的名称来找到表所在的位置,然后访问表的每一个成员。
struct cmd_tbl_s {
char *name; /* 命令名称 */
int maxargs; /* 命令的最大参数个数 */
int repeatable; /* 是否允许重复 */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);/*命令的回调函数*/
char *usage; /* 使用信息 (short) */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* 帮助信息 (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s cmd_tbl_t;
1.4、使用section指定代码段和定义全局数组的区别
u-boot.lds中定义的数据都是放在flash中的,也就是说uboot中的命令表示直接存储在flash中的,并不占用ram或者说内存空间。如果我们将命令表定义在全局数组中,那么它就会占用大量的内存空间,而不会占用flash空间。
二、uboot入口函数分析
enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
int *repeatable)
{
enum command_ret_t rc = CMD_RET_SUCCESS;
cmd_tbl_t *cmdtp;
/* Look up command in command table */
cmdtp = find_cmd(argv[0]);
if (cmdtp == NULL) {
printf("Unknown command '%s' - try 'help'\n", argv[0]);
return 1;
}
...//省略部分代码
}
find_cmd函数用来查找对应的命令:
cmd_tbl_t *find_cmd (const char *cmd)
{
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
}