您的位置:首页 > 其它

uboot系列之-----命令的处理过程(源码)

2014-05-23 14:01 369 查看
在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参数加上双引号(“”),然后替换      

3、Struct_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段里面了

 

 

二、处理控制台的输入命令

在将命令的处理之前,先看几个重要的数据结构:

1、struct 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_head和struct 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)就是处理命令的入口函数,其中ctx是p_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;

}

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: