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 */
)