u-boot分析之两阶段代码分析(三)
目錄
- u-boot(三)啟動(dòng)文件
- 1,概述
- 2,uboot第一階段代碼分析:
- 匯編
- 2,uboot第二階段代碼分析
- C:_start_armboot
- C:main_loop
u-boot(三)啟動(dòng)文件
?
1,概述
本書使用的uboot從nor flash啟動(dòng),下面以開發(fā)板100ask24x0的uboot為例。
uboot屬于兩階段的bootloader,第一階段的文件為cpu/arm920t/start.S和board/100ask24x0/lowlevel_init.S,前者是平臺(tái)相關(guān)的,后者是開發(fā)板相關(guān)的,主要是匯編實(shí)現(xiàn),主要完成一些依賴于cpu體系結(jié)構(gòu)的初始化,并調(diào)用第二階段的代碼;第二階段的文件從lib_arm/board.c開始,主要是c語言實(shí)現(xiàn),實(shí)現(xiàn)更復(fù)雜的功能。
2,uboot第一階段代碼分析:
(1)硬件設(shè)備初始化
將cpu設(shè)為svc模式,關(guān)閉watchdog,設(shè)置時(shí)鐘,關(guān)閉MMU,CACHE,代碼在cpu/arm920t/start.S中。
(2)為加載bootloader的第二階段代碼準(zhǔn)備RAM空間
初始化RAM空間,通過在調(diào)用start.S中調(diào)用lowlevel_init函數(shù)來設(shè)置存儲(chǔ)控制器,使得sdram可用,代碼在board/100ask24x0/lowlevel_init.S中。
(3)復(fù)制bootloader的第二階段代碼到RAM空間中
將整個(gè)uboot代碼(包括第一、第二階段)都復(fù)制到SDRAM中,在cpu/arm920t/start.S中實(shí)現(xiàn)。(注意:100ask24x0改為用c函數(shù)實(shí)現(xiàn)的)。
(4)設(shè)置好棧
棧的設(shè)置靈活性很大,只要讓sp指向一段沒有使用的內(nèi)存即可,下面分析可以看到內(nèi)存的使用情況。
(5)跳轉(zhuǎn)到第二階段代碼的C入口點(diǎn)
跳轉(zhuǎn)之前清除bss段(初始值為0、無初始值的全局變量,靜態(tài)變量放在bss段),c函數(shù)的運(yùn)行環(huán)境準(zhǔn)備好后,通過調(diào)用lib_arm/board.c中的start_armboot跳到c函數(shù)的入口點(diǎn),這是第二階段的入口點(diǎn)。
匯編:_start
cpu/arm920t/start.S
u-boot也是一個(gè)牛逼的單片機(jī)程序,所以也就需要:
程序?qū)嶋H的步驟是:
1.set the cpu to SVC32 mode 2.turn off the watchdog 3.mask all IRQs 4.clock_init board\100ask24x0\boot_init.c 5.cpu_init_crit do sys-critical inits only at reboot,not when booting from ram!判斷 是不是從內(nèi)部ram啟動(dòng)還是仿真直接燒寫到鏈接地址,如果不在正確的加載地址的話,執(zhí)行cpu_init_critcpu_init_crit執(zhí)行SDRAM初始化flush v4 I/D caches,disable MMU stuff and caches,lowlevel_init 這個(gè)會(huì)去初始化sdram,這個(gè)函數(shù)在lowlevel_init.S in your board directory也就是board\100ask24x0\lowlevel_init.S 6.Set up the stack 7.relocate CopyCode2Ram中自動(dòng)識(shí)別當(dāng)前是nor還是nand啟動(dòng),nand啟動(dòng)時(shí)自動(dòng)cp到內(nèi)部ram中運(yùn)行,所以可寫,CopyCode2Ram位于board\100ask24x0\boot_init.c 8.bss段清零 9.調(diào)用C函數(shù) _start_armboot堆棧設(shè)置如下
| ·=-CFG_MALLOC_LEN | malloc area |
| .=-CFG_GBL_DATA_SIZE | bdinfo |
| .=-CONFIG_STACKSIZE_IRQ | IRQ 的棧 |
| .=-CONFIG_STACKSIZE_FIQ | FRQ的棧 |
| .=-12 | leave 3 words for abort-stack |
| sp的初始位置 | ? |
內(nèi)存圖:
2,uboot第二階段代碼分析
(1)初始化本階段要使用到的硬件設(shè)備
(2)檢測(cè)系統(tǒng)內(nèi)存映射(memory map)?
(3)uboot命令的格式
(4)為內(nèi)核設(shè)置啟動(dòng)參數(shù)
第二階段從lib_arm/board.c中的start_armboot函數(shù)開始,程序流程如下:
C:_start_armboot
文件路徑:lib_arm\board.c,這里就是u-boot執(zhí)行C代碼的地方了.
- 分配了一個(gè)gd的結(jié)構(gòu)體內(nèi)存
- 執(zhí)行init_sequence數(shù)組里預(yù)先定義的一些初始化函數(shù)
board_init中設(shè)置了gd->bd->bi_arch_number = MACH_TYPE_S3C2440;,設(shè)置了一個(gè)參數(shù)gd->bd->bi_boot_params =? ? ? ? ? ? 0x30000100;這個(gè)就是啟動(dòng)內(nèi)核參數(shù)的地址
- flash_init、nand_init:flash/nand 初始化
- 堆棧初始化
- env_relocate:環(huán)境變量的設(shè)置存儲(chǔ)(環(huán)境變量來源有兩種:一種是代碼寫死(也就是默認(rèn)),一種在FLASH上保存,uboot啟動(dòng)后會(huì)檢查flash上是否有可用的環(huán)境變量,有就用flash上的,否則使用默認(rèn))
- main_loop:進(jìn)入主循環(huán)
代碼摘要
void start_armboot (void) { //-----/* Pointer is writable since we allocated a register for it */gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //----- //函數(shù)指針,初始化設(shè)備for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}} //---- flash初始化,識(shí)別 #ifndef CFG_NO_FLASH/* configure available FLASH banks */size = flash_init ();display_flash_config (size); #endif /* CFG_NO_FLASH */ ---- nand初始化 #if (CONFIG_COMMANDS & CFG_CMD_NAND)puts ("NAND: ");nand_init(); /* go init the NAND */ #endif //------//分配堆/* armboot_start is defined in the board-specific linker script */mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //-----//uboot的環(huán)境變量/* initialize environment */env_relocate (); //-----//經(jīng)過一系列的初始化/* main_loop() can return to retry autoboot, if so just run it again. */for (;;) {main_loop ();}init_fnc_t *init_sequence[] = {cpu_init, /* basic cpu dependent setup */board_init, /* basic board dependent setup */interrupt_init, /* set up exceptions */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 */ #endifdram_init, /* configure available RAM banks */display_dram_config,NULL, };int board_init (void) {---/* support both of S3C2410 and S3C2440, by www.100ask.net */if (isS3C2410){/* arch number of SMDK2410-Board */gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;}else{/* arch number of SMDK2440-Board */gd->bd->bi_arch_number = MACH_TYPE_S3C2440;}/* adress of boot parameters */gd->bd->bi_boot_params = 0x30000100;}C:main_loop
common/main.c
main_loop兩種選擇:
①在bootdelay減到零之前敲下任意鍵將進(jìn)入uboot控制界面(命令行模式),不過這里100ask24x0自定義一個(gè)menu命令,所以此時(shí)進(jìn)入的是自己實(shí)現(xiàn)的菜單模式,可輸入‘q’退出此模式轉(zhuǎn)而進(jìn)入命令行模式,readline (CFG_PROMPT)不斷接收串口傳過來的命令,run_command (lastcommand, flag)執(zhí)行這些命令 。
②若倒計(jì)時(shí)結(jié)束前沒有敲下任意鍵,將根據(jù)參數(shù)bootcmd來啟動(dòng)內(nèi)核,getenv ("bootcmd")獲得參數(shù)bootcmd值,可知bootcmd = read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,其中read.jffs2和bootm均為uboot命令,所以uboot核心是命令,要繼續(xù)分析uboot是如何將內(nèi)核從flash上搬到sdram并啟動(dòng)內(nèi)核,必須深入分析這些命令才能清楚。
內(nèi)核啟動(dòng)
這里實(shí)現(xiàn)了u-boot的倒計(jì)時(shí),有打印命令,獲取環(huán)境變量等,最關(guān)鍵的代碼是
s = getenv ("bootcmd"); if(倒計(jì)時(shí)結(jié)束) {printf("Booting Linux ...\n"); run_command (s, 0);}實(shí)際的環(huán)境變量是bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,讀取內(nèi)核,啟動(dòng)內(nèi)核
菜單處理(自定義實(shí)現(xiàn))
如果倒計(jì)時(shí)結(jié)束前輸入了空格,進(jìn)入命令模式run_command("menu", 0);
命令處理
轉(zhuǎn)載:https://www.cnblogs.com/zongzi10010/p/10023676.html
總結(jié)
以上是生活随笔為你收集整理的u-boot分析之两阶段代码分析(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u-boot分析之命令实现(四)
- 下一篇: s3c2440arm裸机编程之ADC触摸