转载:http://blog.csdn.net/shengzhadon/article/details/52766263
U_BOOT_CMD是一个宏定义,具体功能是定义一个struct cmd_tbl_s的结构体变量,U_BOOT_CMD宏传递的参数是该结构体变量的成员变量。通过U_BOOT_CMD定义的变量会通过脚本链接到uboot指定的一个section中,然后可以通过find_cmd遍历这个section找到这个cmd,可以通过run_command(cmd, flag)函数执行具体命令。
uboot的命令都存放在uboot/common/目录下,可以在该目录下的Makefile中添加编译命令的选项。如,网络的编译选项如下:
obj-$(CONFIG_CMD_NET) += cmd_net.o
网络的具体命令是再uboot/common/cmd_net.c中定义的,如nfs命令
#if defined(CONFIG_CMD_NFS) static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { return netboot_common(NFS, cmdtp, argc, argv); } U_BOOT_CMD( nfs, 3, 0, do_nfs, "boot image via network using NFS protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" ); #endif
可以看出nfs命令是通过U_BOOT_CMD宏定义“注册“的,并关联上do_nfs(...)函数,执行具体功能。这里的U_BOOT_CMD是在uboot/include/command.h文件中定义的,如下:
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
U_BOOT_CMD_COMPLETE定义紧挨着,如下:
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) ll_entry_declare(cmd_tbl_t, _name, cmd) = U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp);
这里可以看出是一个赋值语句(其实“=”前面是定义一个变量,后面赋值)。“=”后面的宏定义紧挨着,如下:
#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) { #_name, _maxargs, _rep, _cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
注:这里的“#”,作用是将_name传递的值字符串化。_CMD_HELP和_CMD_COMPLETE就是取本身(具体宏定义在本文件command.h中)。
可以看出,这个宏定义的作用就是将U_BOOT_CMD传递的参数放在大括号内。
“=”前面的ll_entry_declare也是一个宏定义,具体在uboot/include/linker_lists.h中,如下
#define ll_entry_declare(_type, _name, _list) _type _u_boot_list_2_##_list##_2_##_name __aligned(4) __attribute__((unused, section(".u_boot_list_2_"#_list"_2_"#_name)))
注:这里的"##"表示连接作用。即##_list##表示用_list变量的值替换当前位置。
即通过_type传递变量类型,_name和_list传递组成变量名称的字符串,然后将该变量放在section中,section的名称也由_name和_list命令传递。这里的__aligned(4)是指定定义的变量4字节对其,__attribute是选择未使用的section,可以在理解原理时忽略掉。
这里的_type=cmd_tbl_t,后者的定义如下:
typedef struct cmd_tbl_s cmd_tbl_t;
即cmd_tbl_t就是cmd_tbl_s,定义如下:
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 * const []); char *usage; /* Usage message (short) */ #ifdef CONFIG_SYS_LONGHELP char *help; /* Help message (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 };
如前所述,U_BOOT_CMD的作用就是定义一个结构体变量(struct cmd_tbl_s),并将其存放再uboot的没有被占用的section中。展开就是:
struct cmd_tbl_s _u_boot_list_2_cmd_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _help, NULL };
注:该变量属性是4字节对齐(__aligned(4) ),存放在未被使用的section中,并将该section命名为【".u_boot_list_2_"#name】(__attribute__((unused, section(".u_boot_list_2_"#name))))。
举例:
命令nfs
U_BOOT_CMD( nfs, 3, 0, do_nfs, "boot image via network using NFS protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" );
即为:
struct cmd_tbl_s _u_boot_list_2_cmd_2_nfs = { "nfs", 3, 0, do_nfs, "boot image via network using NFS protocol", "[loadAddress] [[hostIPaddr:]bootfilename]", NULL };
将_u_boot_list_2_cmd_2_nfs变量4字节对齐存放在未被使用的uboot的section中,该section被命名为.u_boot_list_2_nfs。