解析run_command
1.argc = parse_line (finaltoken, argv) //解析命令的参数有几个
2.cmdtp = find_cmd(argv[0] //获取命令的结构体
3.(cmdtp->cmd) (cmdtp, flag, argc, argv) //执行命令的实现函数
在分析之前先说一个命令的结构体
1.结构体cmd_tbl_t *cmdtp;
定义如下:typedef struct cmd_tbl_s cmd_tbl_t;
struct cmd_tbl_s {
char *name; /* Command Name 命令的名字*/
int maxargs; /* maximum number of arguments 命令的最大参数的个数*/
int repeatable; /* autorepeat allowed? 命令是否可以重复,比如执行过一个命令后,再按下Enter重复之前的命令*/
/* Implementation function 命令的实现函数*/
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage; /* Usage message (short) 命令的使用方法*/
#ifdef CFG_LONGHELP
char *help; /* Help message (long) 命令的详细使用方法*/
#endif
};
重要的函数;
cmdtp = find_cmd(argv[0])//这个函数通过argv[0]也即命令的名字来找到cmd_tbl_s的结构体。
如果没有找到输入命令的结构体,则会打印错误输出信息:
Unknown command '%s' - try 'help'
下面看下函数find_cmd是如何处理的:
for (cmdtp = &__u_boot_cmd_start;
cmdtp != &__u_boot_cmd_end;
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) {
if (len == strlen (cmdtp->name))
return cmdtp; /* full match */
cmdtp_temp = cmdtp; /* abbreviated command ? */
n_found++;
}
}
它是在__u_boot_cmd_start与__u_boot_cmd_end段之间一一的和cmd name进行比对,如果匹配上,则返回该命令的cmdtp结构体。
其中__u_boot_cmd_start与__u_boot_cmd_end的定义是在链接脚本u-boot.lds中定义:
__u_boot_cmd_start = .;
. u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
这两个段之间放的就是uboot的命令,.u_boot_cmd段
定义如下:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
这句话的意思是Struct_Section的宏定以为一个属性,这个属性转换为 .u_boot_cmd段
下面就看看Struct_Section被哪些cmd使用到了。
经过source insight搜索,发现Struct_Section 在另一个宏U_BOOT_CMD中使用到了,
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
可以想象U_BOOT_CMD就是uboot命令的宏.继续使用si搜索U_BOOT_CMD,发现这个宏在很多的文件中使用,选择一个cmd_bootm.c发现:
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
"\ta third argument is required which is the address of the of the\n"
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
"\tuse a '-' for the second argument. If you do not pass a third\n"
"\ta bd_info struct will be passed instead\n"
#endif
);
将其展开:
cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd")))=
{bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
"\ta third argument is required which is the address of the of the\n"
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
"\tuse a '-' for the second argument. If you do not pass a third\n"
"\ta bd_info struct will be passed instead\n"
#endif}
可以看到定义了一个类型为cmd_tbl_t的__u_boot_cmd_bootm,属性强制设为.u_boot_cmd段,这也就解释了为什么uboot命令存放在__u_boot_cmd_start 与__u_boot_cmd_end 之间的原因了。
下面自己添加一个命令的实例cmd_hello.c:
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>
int do_hello(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
printf("Hello World\n");
return 0;
}
U_BOOT_CMD(
hello, CFG_MAXARGS, 1, do_hello,
"hello - hello for test\n",
"Hello long test........\n"
);
修改Makefile,在COBJS = 后面加上cmd_hello.o重新编译即可.