BL2的最后通过汇编调用了board_init_r函数,此时进入BL3的阶段,此时的主要工作:

这一阶段涉及的文件及任务如下

arch/arm/lib/board.c
           1. board_init_r()是进入定制板目录的入口
common/main.c
           2. main_loop()中关闭中断,执行命令以及加载引导内核

下面分析一下board_init_r函数:

  1. /*
  2. ************************************************************************
  3. *
  4. * This is the next part if the initialization sequence: we are now
  5. * running from RAM and have a "normal" C environment, i. e. global
  6. * data can be written, BSS has been cleared, the stack size in not
  7. * that critical any more, etc.
  8. *
  9. ************************************************************************
  10. */
  11. void board_init_r(gd_t *id, ulong dest_addr)
  12. {
  13. ...
  14. bd_t *bd;
  15. ...
  16. gd = id;
  17. bd = gd->bd;
  18.  
  19. gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
  20.  
  21. monitor_flash_len = _end_ofs;
  22.  
  23. ...
  24. debug("monitor flash len: %08lX\n", monitor_flash_len);
  25. board_init(); /* Setup chipselects */

上述代码的作用是对gd和bd进行赋值,其中monitor_flash_len为整个U-Boot的长度。

  1. malloc_start = dest_addr - TOTAL_MALLOC_LEN - sizeof(struct spare_boot_head_t);
  2. ...
  3. /* The Malloc area is immediately below the monitor copy in DRAM */
  4. mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);

对SDRAM中的malloc空间进行清零初始化。

  1. #if !defined(CONFIG_SYS_NO_FLASH)
  2. puts("Flash: ");
  3.  
  4. flash_size = flash_init();
  5. if (flash_size > ) {
  6. # ifdef CONFIG_SYS_FLASH_CHECKSUM
  7. print_size(flash_size, "");
  8. /*
  9. * Compute and print flash CRC if flashchecksum is set to 'y'
  10. *
  11. * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
  12. */
  13. s = getenv("flashchecksum");
  14. if (s && (*s == 'y')) {
  15. printf(" CRC: %08X", crc32(,
  16. (const unsigned char *) CONFIG_SYS_FLASH_BASE,
  17. flash_size));
  18. }
  19. putc('\n');
  20. # else /* !CONFIG_SYS_FLASH_CHECKSUM */
  21. print_size(flash_size, "\n");
  22. # endif /* CONFIG_SYS_FLASH_CHECKSUM */
  23. } else {
  24. puts(failed);
  25. hang();
  26. }
  27. #endif

上述代码的作用是计算FLASH的大小,并把它通过串口显示在控制台上。由于没有定义CONFIG_SYS_FLASH_CHECKSUM,所以没有执行CRC的校验和。其中flash_init函数是在drivers/mtd目录下的cfi_flash.c文件内(因为include/configs/smdk2410.h中定义了CONFIG_FLASH_CFI_DRIVER)。

  1. /* set up exceptions */
  2. interrupt_init();
  3. /* enable exceptions */
  4. enable_interrupts();

interrupt_init函数是建立IRQ中断堆栈,enable_interrupts函数是使能IRQ中断,它们都是在arch/arm/lib目录下的interrupts.c文件中定义的。

  1. ...
  2. /* initialize environment */
  3. env_relocate();

初始化环境变量,由于gd->env_valid等于0,所以在这里设置的是缺省环境变量。env_relocate函数是在common目录下的env_common.c文件中定义的。

  1. #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
  2. arm_pci_init();
  3. #endif

初始化PCI。

  1. /* IP Address */
  2. gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
  3. stdio_init(); /* get the devices list going. */
  4. jumptable_init();
  5. #if defined(CONFIG_API)
  6. /* Initialize API */
  7. api_init();
  8. #endif
  9.  
  10. console_init_r(); /* fully init console as a device */

上面代码的作用分别对应:

设置IP地址。

初始化各类外设,如IIC、LCD、键盘、USB等,当然只有在定义了这些外设的前提下,才对这些外设进行初始化。该函数是在common目录下的stdio.c文件中定义的。

初始化跳转表gd->jt,该跳转表是一个函数指针数组,它定义了U-Boot中基本的常用函数库。该函数是在common目录下的exports.c文件中定义的。

初始化API。

初始化控制台,即标准输入、标准输出和标准错误,在这里都是串口。该函数是在common目录下的console.c文件中定义的。

  1. /* Initialize from environment */
  2. s = getenv("loadaddr");
  3. if (s != NULL)
  4. load_addr = simple_strtoul(s, NULL, );

从环境变量中获取loadaddr参数,得到需要加载的地址。

  1. #if defined(CONFIG_CMD_NET)
  2. s = getenv("bootfile");
  3. if (s != NULL)
  4. copy_filename(BootFile, s, sizeof(BootFile));
  5. #endif

从环境变量中获取bootfile参数,得到通过TFTP加载的镜像文件名。

  1. #if defined(CONFIG_CMD_NET)
  2. #if defined(CONFIG_NET_MULTI)
  3. puts("Net: ");
  4. #endif
  5. eth_initialize(gd->bd);
  6. #if defined(CONFIG_RESET_PHY_R)
  7. debug("Reset Ethernet PHY\n");
  8. reset_phy();
  9. #endif
  10. #endif

初始化以太网,其中eth_initialize函数是在net目录下的eth.c文件中定义的。

  1. ...
  2.    /* main_loop() can return to retry autoboot, if so just run it again. */
  3. for (;;)
  4. {
  5. main_loop();
  6. }
  7. hang();
  8. /* NOTREACHED - no way out of command loop except booting */
  9. }

board_init_r函数的最后就是执行一个死循环,调用main_loop函数。该函数是在common目录下的main.c文件内定义的。

总结:

3.接下来分析main_loop函数:

  1. void main_loop (void)
  2. {
  3. #ifndef CONFIG_SYS_HUSH_PARSER
  4. static char lastcommand[CONFIG_SYS_CBSIZE] = { , };
  5. int len;
  6. int rc = ;
  7. int flag;
  8. #endif

声明一些hush参数。关于hush后面会讲到。

  1. #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
  2. char *s;
  3. int bootdelay;
  4. #endif

声明启动延时需要的参数。

  1. #ifdef CONFIG_SYS_HUSH_PARSER
  2. u_boot_hush_start ();
  3. #endif

初始化hush功能。稍后再说。

  1. #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
  2. s = getenv ("bootdelay");
  3. bootdelay = s ? (int)simple_strtol(s, NULL, ) : CONFIG_BOOTDELAY;
  4.  
  5. debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
  6.  
  7. # ifdef CONFIG_BOOT_RETRY_TIME
  8. init_cmd_timeout ();
  9. # endif /* CONFIG_BOOT_RETRY_TIME */
  10.  
  11. #ifdef CONFIG_POST
  12. if (gd->flags & GD_FLG_POSTFAIL) {
  13. s = getenv("failbootcmd");
  14. }
  15. else
  16. #endif /* CONFIG_POST */
  17. #ifdef CONFIG_BOOTCOUNT_LIMIT
  18. if (bootlimit && (bootcount > bootlimit)) {
  19. printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
  20. (unsigned)bootlimit);
  21. s = getenv ("altbootcmd");
  22. }
  23. else
  24. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  25. s = getenv ("bootcmd");
  26.  
  27. debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
  28.  
  29. if (bootdelay >= && s && !abortboot (bootdelay)) {
  30. # ifdef CONFIG_AUTOBOOT_KEYED
  31. int prev = disable_ctrlc(); /* disable Control C checking */
  32. # endif
  33.  
  34. # ifndef CONFIG_SYS_HUSH_PARSER
  35. run_command (s, );
  36. # else
  37. parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  38. FLAG_EXIT_FROM_LOOP);
  39. # endif
  40.  
  41. # ifdef CONFIG_AUTOBOOT_KEYED
  42. disable_ctrlc(prev); /* restore Control C checking */
  43. # endif
  44. }
  45.  
  46. # ifdef CONFIG_MENUKEY
  47. if (menukey == CONFIG_MENUKEY) {
  48. s = getenv("menucmd");
  49. if (s) {
  50. # ifndef CONFIG_SYS_HUSH_PARSER
  51. run_command(s, );
  52. # else
  53. parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  54. FLAG_EXIT_FROM_LOOP);
  55. # endif
  56. }
  57. }
  58. #endif /* CONFIG_MENUKEY */
  59. #endif /* CONFIG_BOOTDELAY */

第2行和第3行的含义是从环境变量中获取bootdelay参数,得到自动启动缺省镜像文件的延时(单位是秒)。

其中bootdelay的作用是:uboot正常启动后,会调用main_loop(void)函数,进入main_loop()之后,如果在规定的时间(CONFIG_BOOTDELAY)内,没有检查到任何按键事件的发生,就会去加载OS,并启动系统。

第8行的含义是初始化命令行超时机制。

第25行的含义是从环境变量中获取bootcmd参数,得到在启动延时过程中自动执行的命令。当我们得到了bootcmd参数,bootdelay参数也是大于等于0,并且在启动延时过程中没有按下任意键时,执行第37行的parse_string_outer函数,该函数的作用是解释bootcmd参数

并执行,它是在common目录下的hush.c文件内定义的。

  1. /*
  2. 2 * Main Loop for Monitor Command Processing
  3. 3 */
  4. #ifdef CONFIG_SYS_HUSH_PARSER
  5. parse_file_outer();
  6. /* This point is never reached */
  7. for (;;);
  8. #else
  9. for (;;) {
  10. #ifdef CONFIG_BOOT_RETRY_TIME
  11. if (rc >= ) {
  12. /* Saw enough of a valid command to
  13. 13 * restart the timeout.
  14. 14 */
  15. reset_cmd_timeout();
  16. }
  17. #endif
  18. len = readline (CONFIG_SYS_PROMPT);
  19.  
  20. flag = ; /* assume no special flags for now */
  21. if (len > )
  22. strcpy (lastcommand, console_buffer);
  23. else if (len == )
  24. flag |= CMD_FLAG_REPEAT;
  25. #ifdef CONFIG_BOOT_RETRY_TIME
  26. else if (len == -) {
  27. /* -2 means timed out, retry autoboot
  28. 28 */
  29. puts ("\nTimed out waiting for command\n");
  30. # ifdef CONFIG_RESET_TO_RETRY
  31. /* Reinit board to run initialization code again */
  32. do_reset (NULL, , , NULL);
  33. # else
  34. return; /* retry autoboot */
  35. # endif
  36. }
  37. #endif
  38.  
  39. if (len == -)
  40. puts ("<INTERRUPT>\n");
  41. else
  42. rc = run_command (lastcommand, flag);
  43.  
  44. if (rc <= ) {
  45. /* invalid command or not repeatable, forget it */
  46. lastcommand[] = ;
  47. }
  48. }
  49. #endif /*CONFIG_SYS_HUSH_PARSER*/
  50. }

由于在include/configs/smdk2410.h文件中定义了CONFIG_SYS_HUSH_PARSER,所以上面的代码仅仅执行的是第5行至第7行的内容。第5行的parse_file_outer函数是在common目录下的hush.c文件中定义的,它的含义是依次读取命令序列中的命令并执行之,其中在该

函数还调用了parse_stream_outer函数,这个函数体内有一个do-while循环,只有发生语法错误的时候才会跳出该循环,因此一般情况下永远也不会执行上面代码中的第7行内容,而是始终在那个do-while循环体内。

上面说到过如果在CONFIG_BOOTDELAY时间内,用户按下键盘上的任意一个按键,uboot就会进入与用户交互的状态。如果用户在配置文件中定义了CONFIG_SYS_HUSH_PARSER,就会通过parse_file_outer(),去接收并解析用户命令,否则进入一个for(;;)循环,

通过 readline (CONFIG_SYS_PROMPT)接收用户命令,然后调用run_command(cmd,flag)去解析并执行命令。

当在配置文件中定义了CONFIG_SYS_HUSH_PARSER,main_loop会调用parse_file_outer(),进入hush中。其中parse_file_outer()在u-boot\common\hush.c下。

  1. #ifndef __U_BOOT__
  2. static int parse_file_outer(FILE *f)
  3. #else
  4. int parse_file_outer(void)
  5. #endif
  6. {
  7. int rcode;
  8. struct in_str input;
  9. #ifndef __U_BOOT__
  10. setup_file_in_str(&input, f);
  11. #else
  12. setup_file_in_str(&input);
  13. #endif
  14. rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
  15. return rcode;
  16. }
  1. /* most recursion does not come through here, the exeception is
  2. * from builtin_source() */
  3. int parse_stream_outer(struct in_str *inp, int flag)
  4. {
  5.  
  6. struct p_context ctx;
  7. o_string temp=NULL_O_STRING;
  8. int rcode;
  9. #ifdef __U_BOOT__
  10. int code = ;
  11. #endif
  12. do {
  13. ctx.type = flag;
  14. initialize_context(&ctx);
  15. update_ifs_map();
  16. if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", );
  17. inp->promptmode=;
  18. rcode = parse_stream(&temp, &ctx, inp, '\n');
  19. #ifdef __U_BOOT__
  20. if (rcode == ) flag_repeat = ;
  21. #endif
  22. if (rcode != && ctx.old_flag != ) {
  23. syntax();
  24. #ifdef __U_BOOT__
  25. flag_repeat = ;
  26. #endif
  27. }
  28. if (rcode != && ctx.old_flag == ) {
  29. done_word(&temp, &ctx);
  30. done_pipe(&ctx,PIPE_SEQ);
  31. #ifndef __U_BOOT__
  32. run_list(ctx.list_head);
  33. #else
  34. code = run_list(ctx.list_head);
  35. if (code == -) { /* exit */
  36. b_free(&temp);
  37. code = ;
  38. /* XXX hackish way to not allow exit from main loop */
  39. if (inp->peek == file_peek) {
  40. printf("exit not allowed from main input shell.\n");
  41. continue;
  42. }
  43. break;
  44. }
  45. if (code == -)
  46. flag_repeat = ;
  47. #endif
  48. } else {
  49. if (ctx.old_flag != ) {
  50. free(ctx.stack);
  51. b_reset(&temp);
  52. }
  53. #ifdef __U_BOOT__
  54. if (inp->__promptme == ) printf("<INTERRUPT>\n");
  55. inp->__promptme = ;
  56. #endif
  57. temp.nonnull = ;
  58. temp.quote = ;
  59. inp->p = NULL;
  60. free_pipe_list(ctx.list_head,);
  61. }
  62. b_free(&temp);
  63. } while (rcode != - && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
  64. #ifndef __U_BOOT__
  65. return ;
  66. #else
  67. return (code != ) ? : ;
  68. #endif /* __U_BOOT__ */
  69. }

hush是uboot中命令接收和解析的工具,与uboot原始的命令解析方法相比,该工具更加智能。

这里会在run_list中调用到hush中的run_pipe_real(struct pipe *pi),在该函数中经过一些列解析,最终会调用到对应的命令执行函数。

  1. /* run_pipe_real() starts all the jobs, but doesn't wait for anything
  2. * to finish. See checkjobs().
  3. *
  4. * return code is normally -1, when the caller has to wait for children
  5. * to finish to determine the exit status of the pipe. If the pipe
  6. * is a simple builtin command, however, the action is done by the
  7. * time run_pipe_real returns, and the exit code is provided as the
  8. * return value.
  9. *
  10. * The input of the pipe is always stdin, the output is always
  11. * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
  12. * because it tries to avoid running the command substitution in
  13. * subshell, when that is in fact necessary. The subshell process
  14. * now has its stdout directed to the input of the appropriate pipe,
  15. * so this routine is noticeably simpler.
  16. */
  17. static int run_pipe_real(struct pipe *pi)
  18. {
  19. int i;
  20. #ifndef __U_BOOT__
  21. int nextin, nextout;
  22. int pipefds[]; /* pipefds[0] is for reading */
  23. struct child_prog *child;
  24. struct built_in_command *x;
  25. char *p;
  26. # if __GNUC__
  27. /* Avoid longjmp clobbering */
  28. (void) &i;
  29. (void) &nextin;
  30. (void) &nextout;
  31. (void) &child;
  32. # endif
  33. #else
  34. int nextin;
  35. int flag = do_repeat ? CMD_FLAG_REPEAT : ;
  36. struct child_prog *child;
  37. cmd_tbl_t *cmdtp;
  38. char *p;
  39. # if __GNUC__
  40. /* Avoid longjmp clobbering */
  41. (void) &i;
  42. (void) &nextin;
  43. (void) &child;
  44. # endif
  45. #endif /* __U_BOOT__ */
  46.  
  47. nextin = ;
  48. #ifndef __U_BOOT__
  49. pi->pgrp = -;
  50. #endif
  51.  
  52. /* Check if this is a simple builtin (not part of a pipe).
  53. * Builtins within pipes have to fork anyway, and are handled in
  54. * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
  55. */
  56. if (pi->num_progs == ) child = & (pi->progs[]);
  57. #ifndef __U_BOOT__
  58. if (pi->num_progs == && child->group && child->subshell == ) {
  59. int squirrel[] = {-, -, -};
  60. int rcode;
  61. debug_printf("non-subshell grouping\n");
  62. setup_redirects(child, squirrel);
  63. /* XXX could we merge code with following builtin case,
  64. * by creating a pseudo builtin that calls run_list_real? */
  65. rcode = run_list_real(child->group);
  66. restore_redirects(squirrel);
  67. #else
  68. if (pi->num_progs == && child->group) {
  69. int rcode;
  70. debug_printf("non-subshell grouping\n");
  71. rcode = run_list_real(child->group);
  72. #endif
  73. return rcode;
  74. } else if (pi->num_progs == && pi->progs[].argv != NULL) {
  75. for (i=; is_assignment(child->argv[i]); i++) { /* nothing */ }
  76. if (i!= && child->argv[i]==NULL) {
  77. /* assignments, but no command: set the local environment */
  78. for (i=; child->argv[i]!=NULL; i++) {
  79.  
  80. /* Ok, this case is tricky. We have to decide if this is a
  81. * local variable, or an already exported variable. If it is
  82. * already exported, we have to export the new value. If it is
  83. * not exported, we need only set this as a local variable.
  84. * This junk is all to decide whether or not to export this
  85. * variable. */
  86. int export_me=;
  87. char *name, *value;
  88. name = xstrdup(child->argv[i]);
  89. debug_printf("Local environment set: %s\n", name);
  90. value = strchr(name, '=');
  91. if (value)
  92. *value=;
  93. #ifndef __U_BOOT__
  94. if ( get_local_var(name)) {
  95. export_me=;
  96. }
  97. #endif
  98. free(name);
  99. p = insert_var_value(child->argv[i]);
  100. set_local_var(p, export_me);
  101. if (p != child->argv[i]) free(p);
  102. }
  103. return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
  104. }
  105. for (i = ; is_assignment(child->argv[i]); i++) {
  106. p = insert_var_value(child->argv[i]);
  107. #ifndef __U_BOOT__
  108. putenv(strdup(p));
  109. #else
  110. set_local_var(p, );
  111. #endif
  112. if (p != child->argv[i]) {
  113. child->sp--;
  114. free(p);
  115. }
  116. }
  117. if (child->sp) {
  118. char * str = NULL;
  119.  
  120. str = make_string((child->argv + i));
  121. parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
  122. free(str);
  123. return last_return_code;
  124. }
  125. #ifndef __U_BOOT__
  126. for (x = bltins; x->cmd; x++) {
  127. if (strcmp(child->argv[i], x->cmd) == ) {
  128. int squirrel[] = {-, -, -};
  129. int rcode;
  130. if (x->function == builtin_exec && child->argv[i+]==NULL) {
  131. debug_printf("magic exec\n");
  132. setup_redirects(child,NULL);
  133. return EXIT_SUCCESS;
  134. }
  135. debug_printf("builtin inline %s\n", child->argv[]);
  136. /* XXX setup_redirects acts on file descriptors, not FILEs.
  137. * This is perfect for work that comes after exec().
  138. * Is it really safe for inline use? Experimentally,
  139. * things seem to work with glibc. */
  140. setup_redirects(child, squirrel);
  141. #else
  142. /* check ";", because ,example , argv consist from
  143. * "help;flinfo" must not execute
  144. */
  145. if (strchr(child->argv[i], ';')) {
  146. printf ("Unknown command '%s' - try 'help' or use 'run' command\n",
  147. child->argv[i]);
  148. return -;
  149. }
  150. /* Look up command in command table */
  151.  
  152. if ((cmdtp = find_cmd(child->argv[i])) == NULL) {
  153. printf ("Unknown command '%s' - try 'help'\n", child->argv[i]);
  154. return -; /* give up after bad command */
  155. } else {
  156. int rcode;
  157. #if defined(CONFIG_CMD_BOOTD)
  158. /* avoid "bootd" recursion */
  159. if (cmdtp->cmd == do_bootd) {
  160. if (flag & CMD_FLAG_BOOTD) {
  161. printf ("'bootd' recursion detected\n");
  162. return -;
  163. }
  164. else
  165. flag |= CMD_FLAG_BOOTD;
  166. }
  167. #endif
  168. /* found - check max args */
  169. if ((child->argc - i) > cmdtp->maxargs)
  170. return cmd_usage(cmdtp);
  171. #endif
  172. child->argv+=i; /* XXX horrible hack */
  173. #ifndef __U_BOOT__
  174. rcode = x->function(child);
  175. #else
  176. /* OK - call function to do the command */
  177.  
  178. rcode = (cmdtp->cmd)
  179. (cmdtp, flag,child->argc-i,&child->argv[i]);
  180. if ( !cmdtp->repeatable )
  181. flag_repeat = ;
  182.  
  183. #endif
  184. child->argv-=i; /* XXX restore hack so free() can work right */
  185. #ifndef __U_BOOT__
  186.  
  187. restore_redirects(squirrel);
  188. #endif
  189.  
  190. return rcode;
  191. }
  192. }
  193. #ifndef __U_BOOT__
  194. }
  195.  
  196. for (i = ; i < pi->num_progs; i++) {
  197. child = & (pi->progs[i]);
  198.  
  199. /* pipes are inserted between pairs of commands */
  200. if ((i + ) < pi->num_progs) {
  201. if (pipe(pipefds)<) perror_msg_and_die("pipe");
  202. nextout = pipefds[];
  203. } else {
  204. nextout=;
  205. pipefds[] = -;
  206. }
  207.  
  208. /* XXX test for failed fork()? */
  209. if (!(child->pid = fork())) {
  210. /* Set the handling for job control signals back to the default. */
  211. signal(SIGINT, SIG_DFL);
  212. signal(SIGQUIT, SIG_DFL);
  213. signal(SIGTERM, SIG_DFL);
  214. signal(SIGTSTP, SIG_DFL);
  215. signal(SIGTTIN, SIG_DFL);
  216. signal(SIGTTOU, SIG_DFL);
  217. signal(SIGCHLD, SIG_DFL);
  218.  
  219. close_all();
  220.  
  221. if (nextin != ) {
  222. dup2(nextin, );
  223. close(nextin);
  224. }
  225. if (nextout != ) {
  226. dup2(nextout, );
  227. close(nextout);
  228. }
  229. if (pipefds[]!=-) {
  230. close(pipefds[]); /* opposite end of our output pipe */
  231. }
  232.  
  233. /* Like bash, explicit redirects override pipes,
  234. * and the pipe fd is available for dup'ing. */
  235. setup_redirects(child,NULL);
  236.  
  237. if (interactive && pi->followup!=PIPE_BG) {
  238. /* If we (the child) win the race, put ourselves in the process
  239. * group whose leader is the first process in this pipe. */
  240. if (pi->pgrp < ) {
  241. pi->pgrp = getpid();
  242. }
  243. if (setpgid(, pi->pgrp) == ) {
  244. tcsetpgrp(, pi->pgrp);
  245. }
  246. }
  247.  
  248. pseudo_exec(child);
  249. }
  250.  
  251. /* put our child in the process group whose leader is the
  252. first process in this pipe */
  253. if (pi->pgrp < ) {
  254. pi->pgrp = child->pid;
  255. }
  256. /* Don't check for errors. The child may be dead already,
  257. * in which case setpgid returns error code EACCES. */
  258. setpgid(child->pid, pi->pgrp);
  259.  
  260. if (nextin != )
  261. close(nextin);
  262. if (nextout != )
  263. close(nextout);
  264.  
  265. /* If there isn't another process, nextin is garbage
  266. but it doesn't matter */
  267. nextin = pipefds[];
  268. }
  269. #endif
  270. return -;
  271. }

上面关键是这段:

  1. /* OK - call function to do the command */
  2.  
  3. rcode = (cmdtp->cmd)
  4. (cmdtp, flag,child->argc-i,&child->argv[i]);
  5. if ( !cmdtp->repeatable )
  6. flag_repeat = ;

通过这段代码调用对应的命令执行函数。cmd_tbl_t的结构如下:

  1. struct cmd_tbl_s {
  2. char *name; /* Command Name */
  3. int maxargs; /* maximum number of arguments */
  4. int repeatable; /* autorepeat allowed? */
  5. /* Implementation function */
  6. int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
  7. char *usage; /* Usage message (short) */
  8. #ifdef CONFIG_SYS_LONGHELP
  9. char *help; /* Help message (long) */
  10. #endif
  11. #ifdef CONFIG_AUTO_COMPLETE
  12. /* do auto completion on the arguments */
  13. int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
  14. #endif
  15. };
  16.  
  17. typedef struct cmd_tbl_s cmd_tbl_t;

对于uboot支持的每一个命令,是通过U_BOOT_CMD宏定义的,他定义了该命令对应的名称name,支持的最大参数rep,重复次数,实现函数cmd,以及输入help命令时,显示的帮助信息usage。

在执行函数cmd中,第一个参数对应该命令结构本身的指针,第二个参数对应flag标记,第三个参数对应参数数目,第四个参数是指针数组,里面存储的是对应参数的指针。

uboot学习之BL3的流程的更多相关文章

  1. u-boot bootz 加载kernel 流程分析

    u-boot 加载 kernel 的流程分析. image重要结构体头文件 // include/image.h * * Legacy and FIT format headers used by d ...

  2. app开发学习需要经历哪些流程

    app开发学习需要经历哪些流程?如何零基础入门app开发?以下是知乎热心开发者的经验总结,对学习app开发有很好的参考意义   1.如果没有编程基础的,学习基础知识的过程肯定是必须的.2.有了一些基础 ...

  3. [笔记] 基于nvidia/cuda的深度学习基础镜像构建流程 V0.2

    之前的[笔记] 基于nvidia/cuda的深度学习基础镜像构建流程已经Out了,以这篇为准. 基于NVidia官方的nvidia/cuda image,构建适用于Deep Learning的基础im ...

  4. uboot学习之uboot.bin的运行流程

    上篇博客:http://www.cnblogs.com/yeqluofwupheng/p/7347925.html 讲到uboot-spl的工作流程,接下来简述一下uboot.bin的工作流程,这对应 ...

  5. uboot学习之uboot-spl的程序流程分析

    uboot-spl的程序流程主要包含下面的几个函数: _start->reset->save_boot_params->cpu_init_crit->lowlevel_init ...

  6. uboot学习之uboot启动流程简述

    一.uboot启动分为了三个阶段BL0.BL1.BL2:BL0表示上电后运行ROM中固化的一段程序,其中ROM中的程序是厂家写进去的,所以具体功能可能根据厂家芯片而有所不同.功能如下: 初始化系统时钟 ...

  7. 第二天-uboot学习

    源码阅读方法1.源码目录结构2.配置(支持当前使用的硬件)3.编译(Makefile)4.启动流程 工具使用1.在同一文件查找 shitf+8 N n进行上下查找 2.在工程目录中 ctags ubo ...

  8. uboot学习第一天

    Windows操作系统BIOS(设置) Windows系统 文件系统 驱动程序 应用程序 linux操作系统bootloader(引导系统) kernel(内核) 文件系统 驱动程序 应用程序 交叉编 ...

  9. 1.ok6410移植bootloader,移植u-boot,学习u-boot命令

    ok6410移植u-boot 既然是移植u-boot当然首先需要u-boot源码,这里的u-boot代码是由国嵌提供的. 一.配置编译u-boot A. 解压 u-boot 压缩文件 B. 进入解压生 ...

随机推荐

  1. nessus安装

    1.安装注册 (1)从https://www.tenable.com/products/nessus/select-your-operating-system上下载对应操作系统版本的nessus,结果 ...

  2. spring-boot-plus V1.2.2 发布,5 Minutes Finish CRUD

    更新日志 CHANGELOG [V1.2.2-RELEASE] 2019.08.26

  3. 开发APP必须知道的API集合,来源http://www.cnblogs.com/wikiki/p/7232388.html

    笔记 OneNote - OneNote支持获取,复制,创建,更新,导入与导出笔记,支持为笔记添加多媒体内容,管理权限等.提供SDK和Demo. 为知笔记 - 为知笔记Windows客户端开放了大量的 ...

  4. 【解决】TLS/SSLError问题导致无法使用pip或conda安装软件包

    Copy these files from the ./Library/bin to ./DLLs/ :libcrypto-1_1-x64.*libssl-1_1-x64.* 解决 欢迎关注↓↓↓ 头 ...

  5. MySQL数据库之单表查询中关键字的执行顺序

    目录 MySQL数据库之单表查询中关键字的执行顺序 1 语法顺序 2 执行顺序 3 关键字使用语法 MySQL数据库之单表查询中关键字的执行顺序 1 语法顺序 select distinct from ...

  6. MSIL实用指南-生成for语句

    for语句格式是这样的for(<初始化语句>;<条件语句>;<自增减语句>) <循环体> 它可以转换为while语句 if(<条件语句>){ ...

  7. Mobx-React : 当前适合React的状态管理工具

    MobX 简单.可扩展的状态管理        MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商所赞助的.    安装 安装: npm install mobx ...

  8. Oracle - View

    Oracle View的创建 Create Or Replace View ViewName As Select * From Tables/View Where 条件;

  9. POJ - 3436 ACM Computer Factory 网络流

    POJ-3436:http://poj.org/problem?id=3436 题意 组配计算机,每个机器的能力为x,只能处理一定条件的计算机,能输出特定的计算机配置.进去的要求有1,进来的计算机这个 ...

  10. hdu 5887 Herbs Gathering (dfs+剪枝 or 超大01背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5887 题解:这题一看像是背包但是显然背包容量太大了所以可以考虑用dfs+剪枝,贪心得到的不 ...