U-BOOT启动流程之四

(5) main_loop()函数

main_loop函数中会有与用户进行交互,在默认情况下,会等待3,然后经过一系列步骤执行到run_command函数,run_command主要用来执行命令,

int run_command (const char *cmd, int flag)
{
cmd_tbl_t *cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE];/* working copy of cmd*/
char *token; /* start of token in cmdbuf */
char *sep; /* end of token (separator) in cmdbuf */
char finaltoken[CONFIG_SYS_CBSIZE];
char *str = cmdbuf;
char *argv[CONFIG_SYS_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 */
}

/*命令字符串的长度应该小于256*/
if (strlen(cmd) >= CONFIG_SYS_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) {

/*以为分号为退出条件,去执行相应的命令,同时支持可以同时执行多条命令。例如nand read 0x32000000 0x80000 0x580000;bootm 0x32000000,分执行分号以前的命令,再去执行bootm命令。*/
/*
* Find separator, or string end
* Allow simple escape of ';' by writing "\;"
*/
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 */
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1; /* no command at all */
continue;
}

/* Look up command in command table */
/*查找命令在__u_boot_cmd_start - __u_boot_cmd_end段的位置,编译后的地址为0x33fa24ac到0x33fa295c*/
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) {
cmd_usage(cmdtp);
rc = -1;
continue;
}

#if defined(CONFIG_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

/* 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 -1; /* if stopped then not repeatable */
}
	return rc ? rc : repeatable;
}

其中命令格式,在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}
typedef struct cmd_tbl_s      cmd_tbl_t;
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     CONFIG_SYS_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
};

 

代码启动过程中,一般会用到bootm这个命令,它对应的函数是do_bootmcmd_bootm.c文件中有bootm的命令定义格式

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
ulong iflag;
ulong load_end = 0;
int ret;
boot_os_fn *boot_fn;

/* relocate boot function table */
/*查找boot_os数组中的元素个数*/
if (!relocated) {
int i;
for (i = 0; i < ARRAY_SIZE(boot_os); i++)
if (boot_os[i] != NULL)
boot_os[i] += gd->reloc_off;
relocated = 1;
}

/* determine if we have a sub command */
/*没有用到子命令*/
if (argc > 1) {
char *endp;
simple_strtoul(argv[1], &endp, 16);
/* endp pointing to NULL means that argv[1] was just a
* valid number, pass it along to the normal bootm processing
*
* If endp is ':' or '#' assume a FIT identifier so pass
* along for normal processing.
*
* Right now we assume the first arg should never be '-'
*/
if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
return do_bootm_subcommand(cmdtp, flag, argc, argv);
}
/*bootm_start函数用来读出uImage文件的前64个字节的系统,对全局变量image进行初始化。*/
if (bootm_start(cmdtp, flag, argc, argv))
return 1;
/*
* We have reached the point of no return: we are going to
* overwrite all exception vector code, so we cannot easily
* recover from any failures any more...
*/
iflag = disable_interrupts();

#if defined(CONFIG_CMD_USB)
/*
* turn off USB to prevent the host controller from writing to the
* SDRAM while Linux is booting. This could happen (at least for OHCI
* controller), because the HCCA (Host Controller Communication Area)
* lies within the SDRAM and the host controller writes continously to
* this area (as busmaster!). The HccaFrameNumber is for example
* updated every 1 ms within the HCCA structure in SDRAM! For more
* details see the OpenHCI specification.
*/
usb_stop();
#endif

#ifdef CONFIG_AMIGAONEG3SE
/*
* We've possible left the caches enabled during
* bios emulation, so turn them off again
*/
icache_disable();
dcache_disable();
#endif

/*load linux镜像文件,并对其解压。*/
ret = bootm_load_os(images.os, &load_end, 1);

if (ret < 0) {
if (ret == BOOTM_ERR_RESET)
do_reset (cmdtp, flag, argc, argv);
if (ret == BOOTM_ERR_OVERLAP) {
if (images.legacy_hdr_valid) {
if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
puts ("WARNING: legacy format multi component "
"image overwritten\n");
} else {
puts ("ERROR: new format image overwritten - "
"must RESET the board to recover\n");
show_boot_progress (-113);
do_reset (cmdtp, flag, argc, argv);
}
}
if (ret == BOOTM_ERR_UNIMPLEMENTED) {
if (iflag)
enable_interrupts();
show_boot_progress (-7);
return 1;
}
}

lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
if (images.os.type == IH_TYPE_STANDALONE) {
if (iflag)
enable_interrupts();
/* This may return when 'autostart' is 'no' */
bootm_start_standalone(iflag, argc, argv);
return 0;
}
show_boot_progress (8);

#ifdef CONFIG_SILENT_CONSOLE
if (images.os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif

/*根据镜像文件的类型,使用不同的load函数,这里使用的是do_bootm_linux函数,因为在使用mkimage工具生成uImage的时候,-O的参数为linux,所以这里会使用这个函数。*/
boot_fn = boot_os[images.os.os];
if (boot_fn == NULL) {
if (iflag)
enable_interrupts();
printf ("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images.os.os), images.os.os);
show_boot_progress (-8);
return 1;
}
boot_fn(0, argc, argv, &images);

show_boot_progress (-9);
#ifdef DEBUG
puts ("\n## Control returned to monitor - resetting...\n");
#endif
do_reset (cmdtp, flag, argc, argv);
return 1;
}


下面是do_bootm_linux函数

01 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
02 {
03       bd_t *bd = gd->bd;
04       char *s;
05       int    machid = bd->bi_arch_number;
06       void (*theKernel)(int zero, int arch, uint params);
07 
08 #ifdef CONFIG_CMDLINE_TAG
09       char *commandline = getenv ("bootargs");
10 #endif
11 
12       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
13              return 1;
14 
15       theKernel = (void (*)(int, int, uint))images->ep;
16 
17       s = getenv ("machid");
18       if (s) {
19              machid = simple_strtoul (s, NULL, 16);
20              printf ("Using machid 0x%x from environment\n", machid);
21       }
22 
23       show_boot_progress (15);
24 
25       debug ("## Transferring control to Linux (at address %08lx) ...\n",
26              (ulong) theKernel);
27 
28 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
             ……………………………..
35       setup_start_tag (bd);
……………..
42 #ifdef CONFIG_SETUP_MEMORY_TAGS
43       setup_memory_tags (bd);
44 #endif
……………………….
55       setup_end_tag (bd);
56 #endif
57 
58       /* we assume that the kernel is in place */
59       printf ("\nStarting kernel ...\n\n");
60    ……………………………………
68       cleanup_before_linux ();
69       theKernel (0, machid, bd->bi_boot_params);
70       /* does not return */
71       return 1;
72 }

8行获得commandline参数

17行得到机器的ID

35行在内核的参数开始处设置一个ATAG_CORE标记

40-42行设置一个ATAG_MEM标记,该标记包含内存起始地址,内存大小

55行设置一个ATAG_NONE标记,表示标记列表结束

68行这个函数禁止中断和使cache失效功能.

69theKernel调用内核,整个boot的工作也就做完了


参考资料

<<嵌入式linux应用开发完全手册>>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值