Uboot命令U_BOOT_CMD

转载: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。

原文地址:https://www.cnblogs.com/Caden-liu8888/p/7692046.html