转载自:http://blog.csdn.net/toraloo/article/details/7821000
run_command()分析:
- int run_command (const char *cmd, int flag)
- {
- cmd_tbl_t *cmdtp;
- char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
- char *token; /* start of token in cmdbuf */
- char *sep; /* end of token (separator) in cmdbuf */
- char finaltoken[CFG_CBSIZE];
- char *str = cmdbuf;
- char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
- int argc, inquotes;
- int repeatable = 1;
- int rc = 0;
- clear_ctrlc(); /* forget any previous Control C */
- if (!cmd || !*cmd) {
- return -1; /* empty command */
- }
- if (strlen(cmd) >= CFG_CBSIZE) {
- puts ("## Command too long!\n");
- return -1;
- }
- strcpy (cmdbuf, cmd);
- while (*str) {
- /*
- * Find separator, or string end
- * Allow simple escape of ';' by writing "\;"
- */
- for (inquotes = 0, sep = str; *sep; sep++) {
- if ((*sep=='\'') &&
- (*(sep-1) != '\\'))
- inquotes=!inquotes;
- if (!inquotes &&
- (*sep == ';') && /* separator */
- ( sep != str) && /* past string start */
- (*(sep-1) != '\\')) /* and NOT escaped */
- break;
- }
- /*
- * Limit the token to data between separators
- */
- token = str;
- if (*sep) {
- str = sep + 1; /* start of command for next pass */
- *sep = '\0';
- }
- else
- str = sep; /* no more commands for next pass */
- /* find macros in this token and replace them */
- process_macros (token, finaltoken);
- /* Extract arguments */
- if ((argc = parse_line (finaltoken, argv)) == 0) {
- rc = -1; /* no command at all */
- continue;
- }
- /* Look up command in command table */
- if ((cmdtp = find_cmd(argv[0])) == NULL) {
- printf ("Unknown command '%s' - try 'help'\n", argv[0]);
- rc = -1; /* give up after bad command */
- continue;
- }
- /* found - check max args */
- if (argc > cmdtp->maxargs) {
- printf ("Usage:\n%s\n", cmdtp->usage);
- rc = -1;
- continue;
- }
- #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
- if (flag & CMD_FLAG_BOOTD) {
- puts ("'bootd' recursion detected\n");
- rc = -1;
- continue;
- } else {
- flag |= CMD_FLAG_BOOTD;
- }
- }
- #endif /* CFG_CMD_BOOTD */
- /* OK - call function to do the command */
- if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
- rc = -1;
- }
- repeatable &= cmdtp->repeatable;
- /* Did the user stop this? */
- if (had_ctrlc ())
- return 0; /* if stopped then not repeatable */
- }
- return rc ? rc : repeatable;
- }
上述代码为删减后的run_command()函数代码并不是很难,且代码中有着较为详细的注释。其中应注意如下两句代码:
- if ((cmdtp = find_cmd(argv[0])) == NULL) /* 在u_boot_com数据段下查询是否有这个指令 */
- if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) /* 调用实现该指令的函数 */
下面进行find_cmd()函数的分析,这函数相对较为简短;
- cmd_tbl_t *find_cmd (const char *cmd)
- {
- cmd_tbl_t *cmdtp;
- cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*Init value */
- const char *p;
- int len;
- int n_found = 0;
- /*
- * Some commands allow length modifiers (like "cp.b");
- * compare command name only until first dot.
- */
- len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - 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++;
- }
- }
- if (n_found == 1) { /* exactly one match */
- return cmdtp_temp;
- }
- return NULL; /* not found or ambiguous command */
- }
重点留意如下代码:
1、cmd_tbl_t结构体:
- 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 CFG_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
- };
- typedef struct cmd_tbl_s cmd_tbl_t;
2、查询u_boot_cmd数据段的for循环寻找合适的指令
- for (cmdtp = &__u_boot_cmd_start;
- cmdtp != &__u_boot_cmd_end;
- cmdtp++)
要查询此数据段那则次数据段必须建立一组命令表,通过如下步骤建立这个表:
一、添加结构体定义
- U_BOOT_CMD(
- menu, 3, 0, do_menu,
- "menu - display a menu, to select the items to do something\n",
- " - display a menu, to select the items to do something"
- );
二、此命令的实现函数
- int do_menu (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
- {
- menu_shell();
- return 0;
- }
其中上面循环中使用到的__u_boot_cmd_start与__u_boot_cmd_end均定义在u_boot.lds连接脚本中;
- cmdtp = &__u_boot_cmd_start; /* u_boot_cmd数据段的__u_boot_cmd_start地址的内容取出存放至cmdtp中 */
此时进行.u_boot_cmd数据段查询的如下代码:
- #define Struct_Section __attribute__ ((unused,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}
例如增加一个toraloo命令,则上述宏可展开为:
- cmd_tbl_t __u_boot_cmd_toraloo Struct_Section = {“toraloo”, 3, 1, do_toraloo, “string 1”, “string 2”};
toraloo命令可仿照menu命令编写如:
- U_BOOT_CMD(
- toraloo 3, 1, do_toraloo,
- "toraloo - I am toraloo,HAHAHA.......\n",
- " TORALOO is toraloo,ToraLoo is toraloo"
- );
- int do_menu (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
- {
- int i;
- printf(“this is a test! %d\n”,argc);
- for(i=0; i<argc; i++)
- {
- printf(“argv[%d] = %s\n”,i,argv[i]);
- }
- return 0;
- }
再此文件中添加部分头文件,在对/command/makefile下增加cmd_toraloo.o的编译项重新再编译一次u-boot,再将其下载即可看见toraloo这个命令了。
U-boot下的内核启动命令:bootm
输入bootm运行时相当于运行了bootcmd,其将会调度do_bootm()完成命令的功能在do_bootm(...)中再调度do_bootm_linux(....)完成内的内核启动前的设定与硬件参数的设定(如SDRAM地址大小等信息...)最终通过如下两句话实现内核的启动:
- theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
- theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
(PS:还有注意一下关于镜像文件头结构体:
- typedef struct image_header {
- uint32_t ih_magic; /* Image Header Magic Number */
- uint32_t ih_hcrc; /* Image Header CRC Checksum */
- uint32_t ih_time; /* Image Creation Timestamp */
- uint32_t ih_size; /* Image Data Size */
- uint32_t ih_load; /* Data Load Address */
- uint32_t ih_ep; /* Entry Point Address */
- uint32_t ih_dcrc; /* Image Data CRC Checksum */
- uint8_t ih_os; /* Operating System */
- uint8_t ih_arch; /* CPU architecture */
- uint8_t ih_type; /* Image Type */
- uint8_t ih_comp; /* Compression Type */
- uint8_t ih_name[IH_NMLEN]; /* Image Name */
- } image_header_t;
- 这种留意如下三个参数:
- uint32_t ih_size; /* Image Data Size */
- uint32_t ih_load; /* Data Load Address */
- uint32_t ih_ep; /* Entry Point Address */
)