uboot第三阶段启动内核等命令实现

uboot第三阶段启动内核等命令实现

  (2013-01-21 15:21:14)
标签: 

uboot

 

命令实现

 

启动内核

分类: arm

思路是命令是一个结构体,结构体中有name 和function,name表示command_name,function表示如何执行和处理这个command_name。具体的结构体形式是这样的:

struct cmd_tbl_s {
 char  *name;  
 int  maxargs; 
 int  repeatable; 这里指的是执行完命令之后如果再次摁下回车能不能自动执行。
     
 int  (*cmd)(struct cmd_tbl_s *, int, int, char *[]);这个是实现函数的函数指针
 char  *usage;  指的是短的帮助信息,例如输入help命令后,出现的所有命令的简单的介绍
#ifdef CFG_LONGHELP
 char  *help;  指的是长的帮助信息,例如输入help md就会显示出来md命令详细的信息。
#endif
#ifdef CONFIG_AUTO_COMPLETE
 
 int  (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};

下面分析run_command如何实现:

run_command函数是在command/main.c中

 

---------------------------run_command函数开始-------------------------------------

int run_command (const char *cmd, int flag)
{
 cmd_tbl_t *cmdtp;
 char cmdbuf[CFG_CBSIZE]; 
 char *token;   
 char *sep;   
 char finaltoken[CFG_CBSIZE];
 char *str = cmdbuf;
 char *argv[CFG_MAXARGS + 1]; 
 int argc, inquotes;
 int repeatable = 1;
 int rc = 0;

#ifdef DEBUG_PARSER
 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
 puts (cmd ? cmd : "NULL"); 
 puts ("\"\n");
#endif

 clear_ctrlc();  

 if (!cmd || !*cmd) {
  return -1; 
 }

 if (strlen(cmd) >= CFG_CBSIZE) {
  puts ("## Command too long!\n");
  return -1;
 }

 strcpy (cmdbuf, cmd);

 

#ifdef DEBUG_PARSER
 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
 while (*str) {这里实现把命令解析出来,一个一个提取出来

  
  for (inquotes = 0, sep = str; *sep; sep++) {
   if ((*sep=='\'') &&
       (*(sep-1) != '\\'))
    inquotes=!inquotes;

   if (!inquotes &&
       (*sep == ';') && 这里分号表示如果有两个命令的话用分号隔开,也就是说处理了输入多个命令的情况。
       ( sep != str) && 
       (*(sep-1) != '\\')) 
    break;
  }

  
  token = str;
  if (*sep) {
   str = sep + 1; 
   *sep = '\0';
  }
  else
   str = sep; 
#ifdef DEBUG_PARSER
  printf ("token: \"%s\"\n", token);
#endif

  
  process_macros (token, finaltoken);处理宏,例如当我们用网卡或者usb下载文件到内存中时候会临时生成一些环境变量或者宏,

  
  if ((argc = parse_line (finaltoken, argv)) == 0) {解析输入的命令文字,比如md.w 0,成为一个字符数组如argc[0]="md.w" argc[1]="0",英文是extract arguments,提取参数。
   rc = -1; 
   continue;
  }

  
  if ((cmdtp = find_cmd(argv[0])) == NULL) {这里是查找命令,一般argv[0]中存放的是命令,后面的几个是命令的参数,
   printf ("Unknown command '%s' - try 'help'\n", argv[0]);
   rc = -1; 
   continue;
  }

  
  if (argc > cmdtp->maxargs) {
   printf ("Usage:\n%s\n", cmdtp->usage);
   rc = -1;
   continue;
  }

#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
  
  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 

  
  if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
   rc = -1;
  }

  repeatable &= cmdtp->repeatable;

  
  if (had_ctrlc ())
   return 0; 
 }

 return rc ? rc : repeatable;
}

 

 

---------------------------run_command函数结束-------------------------------------

 

 

 

---------------------------find_cmd函数开始---------------------------------------

 * 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; 
 const char *p;
 int len;
 int n_found = 0;

 
 len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);

 for (cmdtp = &__u_boot_cmd_start;这两个参数在文件中是没有的,但是查看链接脚本有这样几句话_u_boot_cmd_start = .;

.u_boot_cmd:{ *(.u_boot_cmd) }

_u_boot_cmd_end = .;

是一个地址,这个循环实现从命令开始存放地址到结束地址遍历命令进行查找。所有的命令全都会被集中到u_boot_cmd这个区域里面来,具体的实现办法是:#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd"))),这句话,同理可以找到如何将所有文件的代码段放到.text的, 关键的是结构体cmd_tbl_t,也即cmd_table,t表示结构体,有这个属性attribute。

      cmdtp != &__u_boot_cmd_end;
      cmdtp++) {
  if (strncmp (cmd, cmdtp->name, len) == 0) {
   if (len == strlen (cmdtp->name))
    return cmdtp; 

   cmdtp_temp = cmdtp; 
   n_found++;
  }
 }
 if (n_found == 1) {   
  return cmdtp_temp;
 }

 return NULL; 
}

 

---------------------------find_cmd函数开始---------------------------------------

例如U_BOOT_CMD命令的定义

U_BOOT_CMD(
  bootm, CFG_MAXARGS, 1, do_bootm,
  "bootm   - boot application image from memory\n",
  "[addr [arg ...]]\n    - boot application image stored in memory\n"
  "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
  "\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
 "\tWhen booting a Linux kernel which requires a flat device-tree\n"
 "\ta third argument is required which is the address of the of the\n"
 "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
 "\tuse a '-' for the second argument. If you do not pass a third\n"
 "\ta bd_info struct will be passed instead\n"
#endif
);按照结构体中去拆开就是 bootm是name,最大参数个数,可以repeat,具体实现函数指针,简要帮助信息,详细帮助信息。

 

 

分析如何实现添加一个hello命令,然后输出helloworld。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值