ARM啓動過程之Uboot兩個階段具體工作(以S5PV210爲例)

1,S5PV210的啓動過程

(1)iROM:iROM(價格最貴)在0地址處,與CPU總線式連接,上電就會執行,和norflash類似。210啓動時會首先執行內部的固件代碼,三星公司出廠前內置的代碼段,稱爲BL0。BL0部分包括對SD卡、Nandflash等SOC內部硬件進行初始化並判斷系統啓動方式,找到外部用來啓動系統的存儲器,並將存儲器中的啓動代碼(Bootloader)拷貝到SRAM中。

註釋:不論是arm的何種處理器,其都是從0x00地址處開始執行程序。IROM上電能直接執行是因爲不需要進行初始化,總線式訪問,而SD卡之類的需要通過時序實現,需要初始化才能使用。BL0空間有限,所以做最重要的事,進行必要的初始化,不然無法使用SD卡等設備。

(2)Boot device:用來存放啓動代碼、內核、文件系統的外設存儲器,例如Nandflash、SD卡、SPIflash等(價格低、時序訪問,需要初始化)。iROM部分的固件代碼會自動判斷從哪裏獲取啓動代碼,一般看不到固件代碼但是芯片手冊會告訴我們固件代碼所支持的外設存儲器,只需要將啓動代碼放在存儲器中,固件代碼會將他拷貝到SOC內部的SRAM中。

(3)SRAM:三星210芯片有96KB(價格貴、總線式訪問),固件代碼將Uboot中的前16KB拷貝到SRAM中運行,這16KB代碼叫BL1,BL1中要完成關看門狗、設置棧、開iCache、初始化DDR、從SD卡複製BL2到DDR中特定位置,跳轉執行BL2。如果BL2小於80KB則被拷貝到SRAM中運行,而實際Uboot至少大於280KB,所以BL1彙編代碼還要負責將(BL1+BL2)拷貝到DDR中運行(利用ldr pc, =main這種方式以遠跳轉從SRAM中運行的BL1跳轉到DDR中運行的BL2)。

註釋:三星210SRAM只有96KB,而其他廠商可能有300KB,不分BL1與BL2,一次讀取完Uboot,不經過第4步;或者讀取一部分,省略第3步,然後直接拷貝整個Uboot到DDR中運行,最後引導內核啓動,uboot結束並死掉。

(4)SDRAM:外部存儲器DDR,也就是運行內存,內核與應用程序申請內存資源的地方。需要初始化才能使用。

 

1.start.S引入,u-boot.lds中找到start.S入口
(1)在C語言中整個項目的入口就是main函數(這是C語言規定的),所以譬如說一個有10000個.c文件的項目,第一個要分析的文件就是包含了main函數的那個文件。
(2)在uboot中因爲有彙編階段參與,因此不能直接找main.c。整個程序的入口取決於鏈接腳本中ENTRY聲明的地方。ENTRY(_start)因此_start符號所在的文件就是整個程序的起始文件,_start所在處的代碼就是整個程序的起始代碼。

 

uboot的start.S第一階段做了哪些主要工作:

1、異常向量表的構建
(1)異常向量表是硬件決定的,軟件只是參照硬件的設計來實現它。
(2)異常向量表中每種異常都應該被處理,否則真遇到了這種異常就跑飛了。但是我們在uboot中並未非常細緻的處理各種異常。
(3)復位異常處的代碼是:b reset,因此在CPU復位後真正去執行的有效代碼是reset處的代碼,因此reset符號處纔是真正的有意義的代碼開始的地方。
2、設置SRAM中的棧並調用lowlevel_init
(1)284-286行第一次設置棧。這次設置棧是在SRAM中設置的,因爲當前整個代碼還在SRAM中運行,此時DDR還未被初始化還不能用。棧地址0xd0036000是自己指定的,指定的原則就是這塊空間只給棧用,不會被別人佔用。
(2)在調用函數前初始化棧,主要原因是在被調用的函數內還有再次調用函數,而BL只會將返回地址存儲到LR中,但是我們只有一個LR,所以在第二層調用函數前要先將LR入棧,否則函數返回時第一層的返回地址就丟了。
3、再次設置棧(DDR中的棧)linux中是滿減棧
(1)之前在調用lowlevel_init程序前設置過1次棧(start.S 284-287行),那時候因爲DDR尚未初始化,因此程序執行都是在SRAM中,所以在SRAM中分配了一部分內存作爲棧。本次因爲DDR已經被初始化了,因此要把棧挪移到DDR中,所以要重新設置棧,這是第二次(start.S 297-299行);這裏實際設置的棧的地址是33E00000,剛好在uboot的代碼段的下面緊挨着。

4、判斷當前地址以決定是否重定位
(1)再次用相同的代碼判斷運行地址是在SRAM中還是DDR中,不過本次判斷的目的不同(上次判斷是爲了決定是否要執行初始化時鐘和DDR的代碼)這次判斷是爲了決定是否進行uboot的relocate。
(2)冷啓動時當前情況是uboot的前一部分(16kb或者8kb)開機自動從SD卡加載到SRAM中正在運行,uboot的第二部分(其實第二部分是整個uboot)還躺在SD卡的某個扇區開頭的N個扇區中。此時uboot的第一階段已經即將結束了(第一階段該做的事基本做完了),結束之前要把第二部分加載到DDR中鏈接地址處(33e00000),這個加載過程就叫重定位。
(3)真正的重定位是通過調用movi_bl2_copy函數完成的,在uboot/cpu/s5pc11x/movi.c中。是一個C語言的函數
(4)copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,CFG_PHY_UBOOT_BASE, 0);
分析參數:2表示通道2;MOVI_BL2_POS是uboot的第二部分在SD卡中的開始扇區,這個扇區數字必須和燒錄uboot時燒錄的位置相同;MOVI_BL2_BLKCNT是uboot的長度佔用的扇區數;CFG_PHY_UBOOT_BASE是重定位時將uboot的第二部分複製到DDR中的起始地址(33E00000)

5、建立虛擬地址映射轉換表TTB

(1)MMU就是memory management unit,內存管理單元。MMU實際上是SOC中一個硬件單元,它的主要功能就是實現虛擬地址到物理地址的映射。

(2)TTB就是translation table base,轉換表基地址。首先要明白什麼是TT(translation table轉換表),TTB其實就是轉換表的基地址。
(3)轉換表是建立一套虛擬地址映射的關鍵。轉換表分2部分,表索引和表項。表索引對應虛擬地址,表項對應物理地址。一對錶索引和表項構成一個轉換表單元,能夠對一個內存塊進行虛擬地址轉換。(映射中基本規定中規定了內存映射和管理是以塊爲單位的,至於塊有多大,要看你的MMU的支持和你自己的選擇。在ARM中支持3種塊大小,細表1KB、粗表4KB、段1MB)。真正的轉換表就是由若干個轉換表單元構成的,每個單元負責1個內存塊,總體的轉換表負責整個內存空間(0-4G)的映射。
(4)整個建立虛擬地址映射的主要工作就是建立這張轉換表
(5)轉換表放置在內存中的,放置時要求起始地址在內存中要xx位對齊(多少兆字節對齊)。轉換表不需要軟件去幹涉使用,而是將基地址TTB設置到cp15的c2寄存器中,然後MMU工作時會自動去查轉換表。

6、ldr    pc, _start_armboot
(1)start_armboot是uboot/lib_arm/board.c中,這是一個C語言實現的函數。這個函數就是uboot的第二階段。這句代碼的作用就是將uboot第二階段執行的函數的地址傳給pc,實際上就是使用一個遠跳轉直接跳轉到DDR中的第二階段開始地址處。
(2)遠跳轉的含義就是這句話加載的地址和當前運行地址無關,而和鏈接地址有關。因此這個遠跳轉可以實現從SRAM中的第一階段跳轉到DDR中的第二階段。
(3)這裏這個遠跳轉就是uboot第一階段和第二階段的分界線。

uboot的start.S第二階段做了哪些主要工作:

(1)第二階段主要是對開發板級別的硬件、軟件數據結構進行初始化。
(2)
    init_sequence
        cpu_init    空的
        board_init    網卡、機器碼、內存傳參地址
            dm9000_pre_init            網卡
            gd->bd->bi_arch_number    機器碼
            gd->bd->bi_boot_params    內存傳參地址
        interrupt_init    定時器
        env_init
        init_baudrate    gd數據結構中波特率
        serial_init        空的
        console_init_f    空的
        display_banner    打印啓動信息
        print_cpuinfo    打印CPU時鐘設置信息
        checkboard        檢驗開發板名字
        dram_init        gd數據結構中DDR信息
        display_dram_config    打印DDR配置信息表
    mem_malloc_init        初始化uboot自己維護的堆管理器的內存
    mmc_initialize        inand/SD卡的SoC控制器和卡的初始化
    env_relocate        環境變量重定位
    gd->bd->bi_ip_addr    gd數據結構賦值
    gd->bd->bi_enetaddr    gd數據結構賦值
    devices_init        空的
    jumptable_init        不用關注的
    console_init_r        真正的控制檯初始化
    enable_interrupts    空的
    loadaddr、bootfile     環境變量讀出初始化全局變量
    board_late_init        空的
    eth_initialize        空的
    x210_preboot_init    LCD初始化和顯示logo
    check_menu_update_from_sd    檢查自動更新
    main_loop            主循環

啓動過程特徵總結
(1)第一階段爲彙編階段、第二階段爲C階段
(2)第一階段在SRAM中、第二階段在DRAM中
(3)第一階段注重SoC內部、第二階段注重SoC外部Board內部

最後通過uboot引導並加載內核,通過bootm命令在指定地址啓動內核,uboot在加載內核到指定地址時,可以通過內核源碼鏈接腳本或Makefile知道。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章