《uboot源码解析(三)命令行解析》

1.命令行解析

以help命令为例(~/comand/command.c)

U_BOOT_CMD(
    help,    CFG_MAXARGS,    1,    do_help,
     "help    - print online help\n",
     "[command ...]\n"
     "    - show help information (for 'command')\n"
     "'help' prints online help for the monitor commands.\n\n"
     "Without arguments, it prints a short usage message for all commands.\n\n"
     "To get detailed help information for specific commands you can type\n"
  "'help' with one or more command names as arguments.\n"
);

  U_BOOT_CMD里面对help命令进行了各种的描述,

#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}

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
};

  #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}

  扩展开:

  cmd_tbl_t __u_boot_cmd_help __attribute__ ((unused,section (".u_boot_cmd"))) ={

  "help",

  CFG_MAXARGS,

  1,

  do_help,

  "help    - print online help\n",

  “后面剩下的一大段”

  }

  而cmd_tbl_t是一个描述命令的结构体,所以*name = “help”,maxargs = MAXARGS, repeatable = 1,int  (*cmd)(struct cmd_tbl_s *, int, int, char *[]);是一个函数指针,就是int (*do_help)(struct cmd_tbl_s *, int, int, char *[]);

  从上面可以看到,定义了一个结构体 cmd_tbl_t 类型的__u_boot_cmd_help,而且它的属性是:__attribute__ ((unused,section (".u_boot_cmd")))。意思是:将来链接时将这个结构体放在 uboot 的“.u_boot_cmd”段,这个段专门用来存放含有 Uboot 的命令的结构体。

u-boot.lds (~/board/smdk2410/u-boot.lds)

/*指定输出可执行文件是elf格式,32ARM指令,小端*/ OUTPUT_FORMAT(
"elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/

/*指定输出可执行文件的平台为ARM*/ OUTPUT_ARCH(arm)

/*指定输出可执行文件的起始代码段为_start*/ ENTRY(_start) SECTIONS {
   /*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成*/ .
= 0x00000000;/*;0x0位置开始*/ . = ALIGN(4);/*代码以4字节对齐*/ .text: {
    /*代码的第一个代码部分*/   cpu
/arm920t/start.o (.text) *(.text) }

.
= ALIGN(4); .rodata : { *(.rodata) } /*指定只读数据段*/ . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .got : { *(.got) }/*指定got, got段是uboot自定义的一个段, 非标准段*/ . = .; __u_boot_cmd_start = .; /*__u_boot_cmd_start赋值为当前位置, 即起始位置*/ .u_boot_cmd : { *(.u_boot_cmd) } /*指定u_boot_cmd, uboot把所有的uboot命令放在该段.*/ __u_boot_cmd_end = .;/*__u_boot_cmd_end赋值为当前位置,即结束位置*/ . = ALIGN(4); __bss_start = .; /*__bss_start赋值为当前位置,bss段的开始位置*/ .bss : { *(.bss) } _end = .;/*_end赋值为当前位置,bss段的结束位置*/ }

  同 时 ,在 .u_boot_cmd 的 开 头 和 结 尾 各 有 一 个 标 志 __u_boot_cmd_start 和__u_boot_cmd_end ,以便于在程序中访问这个段。.u_boot_cmd在find_cmd函数中使用到

  

find_cmd(~/command/command.c)
/*
************************************************************************** * find command table entry for a command */ 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 */ }

在command.h中定义
extern cmd_tbl_t  __u_boot_cmd_start;
extern cmd_tbl_t  __u_boot_cmd_end;  

  由于__u_boot_cmd_start和__u_boot_cmd_end都被声明为cmd_tbl_t类型,所以&__u_boot_cmd_start就是“.u_boot_cmd”段的第一个成员地址。通过for对.u_boot_cmd进行遍历,如果找到对应就return这个命令的结构体指针cmdtp。后续就可以用这个cmdtp去获取这个结构体里面的其他数据,包括调用相应的函数指针去执行相对应的操作。

  

命令行解析函数: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;

#ifdef DEBUG_PARSER
    printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
    puts (cmd ? cmd : "NULL");    /* use puts - string may be loooong */
    puts ("\"\n");
#endif

    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);

    /* Process separators and check for invalid
     * repeatable commands
     */

#ifdef DEBUG_PARSER
    printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
    while (*str) {

        /*
         * Find separator, or string end
         * Allow simple escape of ';' by writing "\;"
         */
     //将多命令拆解(比如:printenv ;saveenv) 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 */ #ifdef DEBUG_PARSER printf ("token: \"%s\"\n", token); #endif /* find macros in this token and replace them */
    //处理字符串中的转义字符 process_macros (token, finaltoken); /* Extract arguments */
    //解析命令(比如md.w 0这个字符串就会解析成argv[0]="md.w" argv=[1]="0") if ((argc = parse_line (finaltoken, argv)) == 0) { rc = -1; /* no command at all */ continue; } /* Look up command in command table */
    //根据argv[0],然后进行对比。找出相对应的命令,执行相对应得函数 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) { #ifdef DEBUG_PARSER printf ("[%s]\n", finaltoken); #endif 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; }

 

posted @ 2019-08-27 20:28  一个不知道干嘛的小萌新  阅读(1037)  评论(0编辑  收藏  举报