第二章第九节 U-Boot-2013.04启动分析(5)
board_init_r()函数同样是位于arch/arm/lib目录下的board.c文件中,并且是紧跟在board_init_f()函数后面。 board_init_r()函数的主要操作是:给标志位赋值、清空malloc空间、初始化NAND Flash、初始化外设(I2C、LCD、VIDEO、KEYBOARD、USB、JTAG等)、跳转表初始化、中断初始化和中断使能等。这里希望读者能触类旁通,完成这个函数的分析。 完成之前的操作,board_init_r()函数进入一个for循环,如下所示: /* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { main_loop(); } main_loop()函数位于/commom目录下的main.c文件中。如下: void main_loop (void) main_loop()函数既无入口参数也无返回值。Main_loop()函数的主要实现作用是: 1) HUSH的相关初始化 #ifndef CONFIG_SYS_HUSH_PARSER static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; int len; int rc = 1; int flag; #endif …… #ifdef CONFIG_SYS_HUSH_PARSER u_boot_hush_start (); #endif #if defined(CONFIG_HUSH_INIT_VAR) hush_init_var (); #endif 2) bootdelay的初始化 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; #endif 3) 启动次数 #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); 上面这行代码的作用是加载保存的启动次数。 bootcount++; 启动次数加1。 bootcount_store(bootcount); 更新启动次数。 sprintf (bcs_set, "%lu", bootcount); 将启动次数通过串口输出。 setenv ("bootcount", bcs_set); bcs = getenv ("bootlimit"); bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; #endif /* CONFIG_BOOTCOUNT_LIMIT */ 这段代码蕴含的东西较多。启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。 4) Modem功能 #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%dn", do_mdm_init); if (do_mdm_init) { char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */ if (str != NULL) free (str); mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ 如果系统中有Modem功能,打开其功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用 5) 设置U-Boot版本号 #ifdef CONFIG_VERSION_VARIABLE { setenv ("ver", version_string); /* set version variable */ } #endif /* CONFIG_VERSION_VARIABLE */ 打开动态版本支持功能后,u-boot在启动的时候会显示最新的版本号。 6) 启动tftp功能 #if defined(CONFIG_UPDATE_TFTP) update_tftp (0UL); #endif /* CONFIG_UPDATE_TFTP */ 7) 打印启动菜单 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%dnn", bootdelay); 在进入主循环之前,如果配置了启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。 #if defined(CONFIG_MENU_SHOW) bootdelay = menu_show(bootdelay); #endif 向终端打印出一个启动菜单。 # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout (); # endif /* CONFIG_BOOT_RETRY_TIME */ 初始化命令行超时机制。 #ifdef CONFIG_POST if (gd->flags & GD_FLG_POSTFAIL) { s = getenv("failbootcmd"); } else #endif /* CONFIG_POST */ #ifdef CONFIG_BOOTCOUNT_LIMIT if (bootlimit && (bootcount > bootlimit)) { printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.n", (unsigned)bootlimit); 检测是否超出启动次数限制。 s = getenv ("altbootcmd"); } else #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv ("bootcmd"); 获取启动命令参数。 main_loop()的主要作用即是U-Boot启动管理。 [url=]到此为止,我相信读者应该对U-Boot的启动原理有了大致的了解,在分析启动原理,笔者希望读者要有“刨根问底”的精神,不弄明白誓不罢休。[/url]
|