U-Boot启动执行完start.s 文件里的reset部分代码后,程序将跳转至函数start_armboot。函数start_armboot位于lib_arm/board.c文件中。函数start_armboot是U-Boot启动的第二个阶段,它将完成U-Boot启动的所有工作并最终进入main循环。
一、start_armboot执行流程
start_armboot()函数的执行流程大概如图1所示。
图1 start_armboot()函数的执行流程
U-Boot 的环境变量可以保存在 Nor Flash、NAND Flash、TF/SD、EEPROM 等设备中。U-Boot 在启动时会根据预先的设定在指定的设备的指定位置读取环境变量。如果环境变量不存在,U-Boot 则使用默认的环境。
U-Boot 的 start_armboot()函数在最后会执行 main_loop()函数。在 main_loop()函数中,会根据用户的响应而决定进入 U-Boot 命令行终端或根据 bootcmd 环境变量启动内核。
二、start_armboot源码分析
下面先贴出start_armboot的源码:
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN);
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
#ifdef CONFIG_GENERIC_MMC
puts ("MMC: ");
mmc_initialize (gd->bd);
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
//modified by luozhizhuo
getddr2_information();
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
stdio_init (); /* get the devices list going. */
jumptable_init ();
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
console_init_r (); /* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900
/* XXX: this needs to be moved to board init */
cs8900_get_enetaddr ();
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
#if defined(CONFIG_ENC28J60_ETH) && !defined(CONFIG_ETHADDR)
extern void enc_set_mac_addr (void);
enc_set_mac_addr ();
#endif /* CONFIG_ENC28J60_ETH && !CONFIG_ETHADDR*/
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_ANDROID_RECOVERY
check_recovery_mode();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
第11-19行:初始化全局数据结构体(gd_t结构体和bd_t结构体)。主要是为gd_t结构体和bd_t结构体分配内存并清零。第13行是GCC编译器的内存屏障指令。关于内存屏障指令可以参考博文https://blog.csdn.net/mtv_zmx/article/details/9836969。
第23-27行:调用通用初始化函数。init_sequence[]是init_fnc_t函数指针数组,这个数组包含了众多初始化函数,比如cpu_init,board_init等。
第30行:初始化malloc函数使用的堆区。
第34行:初始化flash并打印flash配置信息。
第37-64行:初始化LCD FrameBuffer。
第66-69行:初始化NAND Flash。
第71-73行:初始化One NAND Flash。
第75-78行:初始化DataFlash。
第80-83行:初始化MMC(TF/SD接口)。
第86行:初始化环境变量。
第89行:初始化控制器的LCD控制器。
第92-94行:初始化串行接口。
第101行:初始化io设备,比如i2c、键盘、usb等等。
第103行:初始化全局数据结构体的jt成员。jt成员存放了许多函数。
第105-108行:初始化API。
第110行:初始化控制台。
第112-119行:初始化其他杂项设备。
第122行:使能中断。
第124-152行:初始化网卡。
第164-166行:其他板级初始化。
第172-181行:网络初始化。
第183-185行:u-boot的主循环,基本就是执行用户的输入命令。