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即可