今天研究了一下uboot中怎么用do_run()函数来执行定义好的一些命令,发现其实也挺简单的,关键是得把do_run函数的几个参数吃透,这几个参数都是由uboot commmod 的cmd_tbl_s结构体决定的,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}
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 *[]);
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 *argv[], char last_char, int maxv, char *cmdv[]);
#endif
}
对比两者后很容易就明白了怎样去定义一个uboot下的命令。
接下来看看do_run函数的定义(在../boot/common/main.c下):
#if defined(CONFIG_CMD_RUN)
int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
int i;
if (argc < 2) { //参数个数小于2则提示重新输入
cmd_usage(cmdtp);
return 1;
}
for (i=1; i<argc; ++i) {
char *arg;
if ((arg = getenv (argv[i])) == NULL) {
printf ("## Error: \"%s\" not defined\n", argv[i]);
return 1;
}
#ifndef CONFIG_SYS_HUSH_PARSER
if (run_command (arg, flag) == -1){ //调用run_command函数,先查找命令,然后执行命令
return 1;
}
#else
if (parse_string_outer(arg,
FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0){
return 1;
}
#endif
}
return 0;
}
其中第一个参数cmd_tbl_t * cmdtp为Command Table,即命令表参数,该结构体的定义在common.h下,一般设为NULL。
第二个参数int flag为Command Flag,用来标志命令来自哪里,跟它相关的有两个宏:
#define CMD_FLAG_REPEAT 0x0001 /* repeat last command */
#define CMD_FLAG_BOOTD 0x0002 /* command is from bootd */
它被传给run_command (const char *cmd, int flag),一般设为0,表示bootd,设为1则表示repeat(递归式)。
第三个int argc表示输入参数的个数,小于2则提示重新输入。第三个char *argv[]是输入命令字符的指针,用来传递定义好的指针数组。下面通过一个简单的例子来说明怎么使用do_run()函数,yaffs2ram的作用是实现从yaffs文件系统中拷贝logo.bmp到指定的RAM地址上:
int yaffs2ram(void)
{
char *argv[5]; //定义5个指针数组,用来存放各个字符命令的指针
char buf[100];
char *name_buf = "/logo/logo.bmp";
int ret;
if(!yaffs_file_exist(name_buf))//检查文件系统中是否存在logo.bmp
{
dprintf_line("%s NOT Exist!",name_buf);
return -1;
}
//把yrdm /logo/logo.bmp 0x8000_0000命令传给buf(loadaddr为环境变量)
sprintf(buf,"yrdm %s ${loadaddr}",name_buf);
setenv("upgradetemp", buf);//设置临时环境变量upgradetemp的值
argv[0] = "run";
argv[1] = "upgradetemp";
argv[2] = NULL;
ret = do_run(NULL, 0, 2, argv); //运行yrdm /logo/logo.bmp 0x8000_0000命令,把logo.bmp拷贝到0x8000_000地址上
if ( ret == 1)
{
printf("do_run error!")
return -1;
}
setenv("upgradetemp", NULL); //清空临时环境变量的值
return 0;
}
注:由于do_yrdm函数规定输入命令的个数必须为3(如下所示),所以我们加了一个argv[2] = NULL命令,该命令什么都不做。
U_BOOT_CMD(
yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"filename offset"
);