u-boot命令实现

u-boot-1.1.6

你是否想过在u-boot命令行的命令是怎么实现的呀?

首先,我们来想一想?

每条命令是不是有个名字呀?

每个名字是不是对应一个处理函数呀?

每天命令是不是对应一个帮助信息呀?

所以嘛 u-boot里面应该有个结构体,里面至少包括了命令的:名字,处理函数,帮助信息。下面就是在u-boot源码中命令结构体:

/common/command.h
struct cmd_tbl_s {
	char		*name;		//命令的名字
	int		maxargs;	//最大的参数
	int		repeatable;	//是否支持重复
	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;

再来想想,一个cmd_tbl_t结构体就代表一个命令呀,为了访问方便,我们是不是应该讲所有的cmd_tbl_t结构体有效的组织在一起呀?

方法1:使用数组,将所有的cmd_tbl_t结构体保存在一起

方法2:使用链表,将所有的cmd_tbl_t结构体保存在一起

方法3:u-boot采用了另外一种方法:将所有的cmd_tbl_t定义个段属性,这样这些变量定义后就会被编译器安排到一块儿了。

#define  Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))//定义的新段,段名为.u_boot_cmd

#ifdef  CFG_LONGHELP
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)  \ //定义u-boot命令的宏
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
#else	/* no long help info */
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
#endif	/* CFG_LONGHELP */

 u-boot命令都在commom/目录下,文件一般是cmd_xxx.c。现以nand命令为例

/cmd_nand.c

U_BOOT_CMD(
    nand,   5,  1,  do_nand,
    "nand    - legacy NAND sub-system\n",
    "info  - show available NAND devices\n"
    "nand device [dev] - show or set current device\n"
    "nand read[.jffs2[s]]  addr off size\n"
    "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
    "    at offset `off' to/from memory address `addr'\n"
    "nand erase [clean] [off size] - erase `size' bytes from\n"
    "    offset `off' (entire device if not specified)\n"
    "nand bad - show bad blocks\n"
    "nand read.oob addr off size - read out-of-band data\n"
    "nand write.oob addr off size - read out-of-band data\n"
);

按照上面的U_BOOT_CMD宏定义替换有:

cmd_tbl_t  __u_boot_cmd_nand  __attribute__ ((unused,section (".u_boot_cmd"))) = 
{ nand, 5, 1, do_nand, 
 "nand    - legacy NAND sub-system\n", 
 "info  - show available NAND devices\n"
 "nand device [dev] - show or set current device\n"
 "nand read[.jffs2[s]]  addr off size\n"
 "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
  "at offset `off' to/from memory address `addr'\n"
  "nand erase [clean] [off size] - erase `size' bytes from\n"
   "offset `off' (entire device if not specified)\n"
   "nand bad - show bad blocks\n"
   "nand read.oob addr off size - read out-of-band data\n"
   "nand write.oob addr off size - read out-of-band data\n"}

其实就是定义一个名叫__u_boot_cmd_nand的cmd_tbl_t类型变量,它的段为.u_boot_cmd,并用括号后面的内容初始化它。

命令的查找

/common/command.c

int run_command (const char *cmd, int flag)

           if ((argc = parse_line (finaltoken, argv)) == 0) {//解析命令cmd字符串
               rc = -1; /* no command at all */
               continue;
               }

           if ((cmdtp = find_cmd(argv[0])) == NULL) {//根据名字查找命令
               printf ("Unknown command '%s' - try 'help'\n", argv[0]);
               rc = -1; /* give up after bad command */
               continue;
               }

          if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {//执行找到的命令
               rc = -1;
              }

cmd_tbl_t *find_cmd (const char *cmd)

         for (cmdtp = &__u_boot_cmd_start;cmdtp != &__u_boot_cmd_end;cmdtp++) {//在.u_boot_cmd段查找命令
                 if (strncmp (cmd, cmdtp->name, len) == 0) {//如果两个命令的名字相同就返回
                         if (len == strlen (cmdtp->name))
                                 return cmdtp;
                 cmdtp_temp = cmdtp;
                 n_found++;
               }
       }

__u_boot_cmd_start,__u_boot_cmd_end指示了.u_boot_cmd段的地址范围,它在/board/xxxx/u-boot.lds中指定。

命令实现举例

首先在源码的common/目录下新建一个文件cmd_hello.c 其内容如下:

#include <common.h>
#include <command.h>

int do_hello(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
         printf(“hello world\n”);
         return 0;
 }
 U_BOOT_CMD(hello, CONFIG_SYS_MAXARGS, 1, do_hello, “usage info”,  “help info”);

然后修改common/目录下的Makefile   在COBJ中加入cmd_hello.o即可


你可能感兴趣的:(u-boot,U_BOOT_CMD)