GT2440--U-Boot分析(四)

来源:互联网 发布:局域网多线程编程 编辑:程序博客网 时间:2024/04/29 22:26

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';}elsestr = 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 */}

重点留意如下代码:

1cmd_tbl_t结构体:

struct cmd_tbl_s {char*name;/* Command Name*/intmaxargs;/* maximum number of arguments*/intrepeatable;/* autorepeat allowed?*//* Implementation function*/int(*cmd)(struct cmd_tbl_s *, int, int, char *[]);char*usage;/* Usage message(short)*/#ifdefCFG_LONGHELPchar*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_scmd_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(toraloo3,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_tih_magic;/* Image Header Magic Number*/uint32_tih_hcrc;/* Image Header CRC Checksum*/uint32_tih_time;/* Image Creation Timestamp*/uint32_tih_size;/* Image Data Size*/uint32_tih_load;/* Data Load  Address*/uint32_tih_ep;/* Entry Point Address*/uint32_tih_dcrc;/* Image Data CRC Checksum*/uint8_tih_os;/* Operating System*/uint8_tih_arch;/* CPU architecture*/uint8_tih_type;/* Image Type*/uint8_tih_comp;/* Compression Type*/uint8_tih_name[IH_NMLEN];/* Image Name*/} image_header_t;这种留意如下三个参数:uint32_tih_size;/* Image Data Size*/uint32_tih_load;/* Data Load  Address*/uint32_tih_ep;/* Entry Point Address*/