uboot系列之-----命令的處理過程(源碼)

uboot運行到第二個階段後,會進入到main_loop函數中,該函數有一個作用就是處理用戶所輸入的命令,下面詳細分析命令處理的流程:

一、命令的結構及定義

uboot裏面,命令的創建是通過宏定義U_BOOT_CMD來實現的,該宏定義在文件include/command.h文件中,

        

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

 

從以上宏定義可以看出,通過U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)定義出來的命令,展開後的結果就是:

cmd_tbl_t  __u_boot_cmd_##name Struct_Section = {#name,maxargs, rep, cmd, usage, help}

對於以上的語句,重點講述以下三點:

1、  cmd_tbl_t 是命令格式的數據結構,它定義在include/command.h

struct cmd_tbl_s {

        char            *name;                /* 命令的名稱*/

        int              maxargs;    /* 該命令所能附帶的參數個數的最大值*/

        int              repeatable;         /* 命令是否可重複*/

        int              (*cmd)(struct cmd_tbl_s *, int,int, char * const []);/*命令所對應的函數指針*/

        char            *usage;               /* 短幫助信息*/

        char            *help;                  /* 長幫助信息*/

};

 

2、##name是指直接用U_BOOT_CMD裏面的name參數替換,#name表示將U_BOOT_CMD裏面的name參數加上雙引號(“”),然後替換      

3Struct_Section是個宏定義,定義在common/command.h

#define  struct_section __attribute__((unused,section(".u_boot_cmd")))

它表示將該處的內容放入u_boot_cmd段(具體u_boot_cmd段的信息可以參看u-boot.lds連接文件)

 

例如,定義瞭如下命令 U_BOOT_CMD(command,1,0,fun,”short help”,”long help”)

將其按照上述宏展開後得到如下結論:

         cmd_tbl_t  __u_boot_cmd_command  __attribute__((unused.section(".u_boot_cmd")))={"command",1,0,fun,"short help‘,"long help"’}

並且該”command”命令已經加入到.u_boot_cmd段裏面了

 

 

二、處理控制檯的輸入命令

在將命令的處理之前,先看幾個重要的數據結構:

1struct p_context {

        struct  child_prog *child;

       struct  pipe  *list_head;

       struct  pipe  *pipe;

       reserved_style  w;

       int  old_flag;

     structp_context * stack;

      int type;

        

};

該數據結構變量是一個命令索引,關鍵的就是其中的兩個成員,struct pipe *list_headstruct pipe *pipe;

再來看數據結構struct  pipe

Struct pipe{

        int num_progs;

        struct  child_progs;

       struct  pipe  *next;

       pipe_style  followup;

       reserved_style  r_mode;

};

該數據結構用來存儲用戶的輸入命令的,命令存儲在成員變量struct child_prog* progs裏面,其中的next用來指向下一個struct  pipe數據結構變量(當一次輸入多個命令時用到)

struct child_prog {

        char **argv;

        int  argc;

        struct  pipe* group;

        int  sp;

       int  type;

};

該數據結構中的char ** argv就是存放命令的地方,argc表示該命令含有的參數的個數

總的來說,他們的關係是:p_context的head_list成員變量指向第一個pipe結構變量(用來存儲第一條命令),第一個pipe結構的next指向下一個pipe結構(用來存儲下一條命令)

1)  當用戶輸入的命令爲command1時,

p_context.head_list->progs->argc= 1

p_context.head_list->progs->argv[0]=command1

2)  當用戶輸入的命令爲command1  command2時

p_context.head_list->progs->argc= 2

p_context.head_list->progs->argv[0]=command1

p_context.head_list->progs->argv[1]=command2

3)      當用戶輸入的命令爲command1  command2;  command3 command4(;表示前後輸入的是兩條命令)

p_context.head_list->progs->argc= 2

p_context.head_list->progs->argv[0]=command1

p_context.head_list->progs->argv[1]=command2

p_context.head_list->next->progs->argc= 2

p_context.head_list->next->progs->argv[0]=command3

p_context.head_list->next->progs->argv[1]=command4

 

當用戶的命令按照以上的方式存儲之後,就進入到parse_stream_outer函數:

int parse_stream_outer(struct in_str *inp, int flag)(common/hush.c)

 

       ......

            code = run_list(ctx.list_head);

      ......

  

Run_list(ctx.list_head)就是處理命令的入口函數,其中ctxp_context結構變量,裏面存儲了用戶所輸入的命令,真正將處理落到實處的函數是

static int run_pipe_real(struct pipe *pi)(common/hush.c)

 

              ......

                  if((cmdtp = find_cmd(child->argv[i])) == NULL)

              .......

                 

         其中find_cmd函數的參數child->argv[i]通常情況下是child->argv[0],即認爲整個命令的第一部分(第一個空格之前的字符)作爲命令名稱,其他的作爲參數。它的作用就是到.u_boot_cmd段裏面尋找child->argv[0],如果沒找到,就返回NULL,並提示無效的命令;如果找到了,就將該命令以cmd_tbl_t結構變量的形式返回,繼續往下執行

static int run_pipe_real(struct pipe *pi)(common/hush.c)

              .....

                    if((child->argc-i) > cmdtp->maxargs)

                                       return cmd_usage(cmdtp);

             ......

                  rcode = (cmdtp->cmd)(cmdtp,flag,child->argc-i,&child->argv[i]);

             ......

                 

     如果發現輸入的參數個數大於命令裏面所定義的最大參數個數,就輸出該命令的usage信息並退出,否則執行該命令的函數指針所指向的函數,它就是命令所需要執行的操作了。

 

### main_loop: bootcmd="run setargs_mmc boot_normal"

 

#if defined(CONFIG_CMD_RUN)
U_BOOT_CMD_COMPLETE(
 run, CONFIG_SYS_MAXARGS, 1, do_run,
 "run commands in an environment variable",
 "var [...]\n"
 "    - run the commands in the environment variable(s) 'var'",
 var_complete
);

#endif

 

int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
 int i;

 if (argc < 2)
  return cmd_usage(cmdtp);

 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)
   return 1;
#else
  if (parse_string_outer(arg,
      FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
   return 1;
#endif
 }
 return 0;
}

 

 

 

 

發佈了4 篇原創文章 · 獲贊 7 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章