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移植。。。。