4.2 u-boot源码分析 --- 启动第二阶段
接着我们来看start_armboot, 从这开始应该属于bootloader的第2个阶段了,这个阶段的代码主要用c完成。
lib_arm/board.c:
void start_armboot (void)
{
//该宏定义在include/asm-arm/Global_data.h
// #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
DECLARE_GLOBAL_DATA_PTR;
ulong size;
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 */
//定位到RAM中的bdinfo区域中的sizeof(gd_t)处用来存放gd_t信息,详见上面的图,
//即r8中的值就是指向这个区域。
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
//定位到RAM中的bdinfo区域中的相关地址处用来存放bd_t信息,详见上面的图
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start; //代码中RO+RW的长度
//依次执行初始化函数表中的每个函数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();//执行失败就down机,实际上就是一个死循环。
}
}
/* configure available FLASH banks */
size = flash_init (); //flash初始化
display_flash_config (size); //显示flash大小
//如果启用CONFIG_VFD,则在RAM中bss_end之后的整页处为VFD留下相应memory,smdk2410未定义
#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);
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
//如果启用CONFIG_LCD,则在RAM中bss_end之后的整页处为LCD留下相应memory,smdk2410未定义
#ifdef CONFIG_LCD
# 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);
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_LCD */
/* armboot_start is defined in the board-specific linker script */
//为malloc功能初始化好相关信息
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
//如果开启了CFG_CMD_NAND命令后,则初始化nand.
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND */
#endif
//smdk2410没定义这个宏
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate (); //初始化环境变量
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
/* IP Address */
//从上面初始化好的环境变量中去获取IP地址
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
//从上面初始化好的环境变量中获取MAC地址
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
uchar tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
}
//设备初始化
devices_init (); /* get the devices list going. */
//跳转表
jumptable_init ();
//控制台
console_init_r (); /* fully init console as a device */
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
//打开中断,记得吗, 中断是在bootloader第1阶段关掉的
enable_interrupts ();
/* Perform network card initialisation if necessary */
//网卡初始化
#ifdef CONFIG_DRIVER_CS8900
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
if (getenv ("ethaddr")) {
smc_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
//获取启动文件
#if (CONFIG_COMMANDS & CFG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
//根据命令的配置情况初始化网络
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
puts ("Net: ");
eth_initialize(gd->bd);
#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 */
}
值得一说的是宏 DECLARE_GLOBAL_DATA_PTR
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
它定义了一个寄存器变量gd,用r8来保存gd的值。以后的函数中还会用这个宏来定义gd变量,
而此时的gd默认就是指向的是同一块内存地址(因为r8没变)
此时RAM中bdinfo区域的存储空间如下分布:
gd_t 和 bd_t 中存放着随后会用到的相关信息如环境变量,跳转表等。