0K6410学习之初学Uboot_stage2
唉,刚刚老同学们打电话来找我月底出去聚一聚,我发誓这是我第一次这么冷静,也就是不像以前一样,不经过考虑,就一口答应下来。因为,我觉得我有很多重要的事情要做,像我这种不准备考研的学生,我必须要抓住假期的时间给自己充电,老朋友们,不好意思,请原谅我这次善意的谎言,给我在校的学习时间不多了,请接受我这次偷偷的道歉。好吧,既然已经烧好一壶水了,那就开始我的uboot stage2的学习吧!!
当第一阶段的汇编部分执行完,跳到stage2时,开始执行c函数start_armboot,该函数就是整个u-boot的主函数。
1、开头首先声明一个全局指针变量DECLARE_GLOBAL_DATA_PTR;这个宏定义在头文件
include/asm-arm/global_data.h 中
#define DECLARE_GLOBAL_DATA_PTR register volatilegd_t *gd asm ("r8")
声明一个寄存器变量 gd 占用 r8。这个宏在所有需要引用全局数据指针gd_t *gd 的源
码中都有申明,这个申明也避免编译器把r8 分配给其它的变量. 所以 gd 就是 r8,这个指针变量不另外分配内存。
2、 /* Pointer is writable since weallocated 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、gd赋一个地址,进行地址分配。都说下面是张经典的uboot映射图,确实不错啊,它把整个Uboot启动过程中的内存分配描述的相当清楚的。
monitor_flash_len = _bss_start - _armboot_start; 按照上图可以知道,这是uboot的长度。
3、接下来是一个循环,对板子的信息以及相关函数进行初始化。
for (init_fnc_ptr = init_sequence;*init_fnc_ptr; ++init_fnc_ptr) {
if((*init_fnc_ptr)() != 0) {
hang();
}
}
4、/* 初始化堆空间 */
/* armboot_start is defined in theboard-specific linker script */
mem_malloc_init (_armboot_start -CONFIG_SYS_MALLOC_LEN,CONFIG_SYS_MALLOC_LEN);
/*配置flash*/
#ifndef CONFIG_SYS_NO_FLASH
/*configure available FLASH banks */
display_flash_config(flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
5、接下来是一系列的初始化,不一一分析,其实是我有些函数分析不来,指针指的我头晕。。
#ifdef CONFIG_VFD
# ifndefPAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always fullpages)
*/
/*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) {
# ifndefPAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always fullpages)
*/
/*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
/*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
/*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 (constu_int8_t *addr);
if(getenv ("ethaddr")) {
ucharenetaddr[6];
eth_getenv_enetaddr("ethaddr",enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined(CONFIG_DRIVER_LAN91C96)
/*XXX: this needs to be moved to board init */
if(getenv ("ethaddr")) {
ucharenetaddr[6];
eth_getenv_enetaddr("ethaddr",enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 ||CONFIG_DRIVER_LAN91C96 */
/*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_GENERIC_MMC
puts("MMC: ");
mmc_initialize(gd->bd);
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#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 */
}
6、还有一个初始化函数,配置一些信息。
nit_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup*/
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup*/
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) ||defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAMbanks */
#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
其中display_banner是串口上打印的第一条信息的内容,自己有兴趣可以进入这个函数,修改一下,会有意想不到的结果的。
最后整个 u-boot 的执行就进入main_loop()函数等待用户输入命令,解析并执行命令的死循环中。
关于uboot stage2里面的一些重要数据结构以及一些值得注意的地方那就等下次吧,stage2的分析暂时到这里。 待续,uboot移植。。。。