Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析
uboot啟動流程分析如下:
第一階段:
a -- 設置cpu工作模式為SVC模式
b -- 關閉中斷,mmu,cache
v -- 關看門狗
d -- 初始化內存,串口
e -- 設置棧
f -- 代碼自搬移
g -- 清bss
h -- 跳c
第二階段
a -- 初始化外設,進入超循環
b -- 超循環處理用戶命令
可見, U-Boot 屬于兩階段的Bootloader
第一階段的文件:
arch/arm/cpu/armv7 /start.S? ? ? ? ? ? ? ? ? ? ? ?平臺相關,CPU工作模式設為SVC模式,關MMU,關icahce(CPU相關)
board/samsung/fs4412/lowlevel_init.S? ? ?開發板相關:關看門狗,內存初始化,時鐘初始化,串口初始化(board相關,初始化最基本設備)
第二階段的文件:
arch/arm/lib/crt0.S? ? ? ? ? ? ? ? ? ? ?_main 函數所在處,初始化SP,為C語言準備,代碼重定位,清BSS,設置R0 R1 R2 R8相應寄存器
arch/arm/lib/board.c? ? ? ? ? ? ? ? ? ?board_init_f 函數 ,填充GD結構體,初始化外設, main_loop()函數超循環
arch/arm/cpu/armv7 /start.S?代碼自搬移時會用到
針對uboot2013啟動流程圖如下:
下面是具體分析:
一、U-Boot 第一階段代碼分析
通常我們通過連接文件知曉程序入口點,入口查看?u-boot.lds
通過鏈接腳本可知入口為_start,位于arch/arm/cpu/armv7/start.o。
第一階段開始:
1、進入arch/arm/cpu/armv7/start.S
a -- 異常向量表設置
b -- 設置CPU處于SVC工作模式
d -- 協處理器 p15 的 c12 寄存器來重新定位
e、Bl ?cpu_init_cp15(使分支預測無效,數據)
關閉數據預取功能;
DSB:多核CPU對數據處理指令
ISB:流水線清空指令;
關閉MMU,使能I-cache
NOTE:
分支預測:在流水線里,會將后面的代碼優先加載到處理器中,由于是循環,會使后面加載的代碼無效,故出現了分支預測技術。(統計跳的次數來選擇裝載循環的代碼還是下面的代碼)。
f、Bl ?cpu_init_crit
2、跳到Low_level_init,位于board/samsung/fs4412/lowlevel_init.S
a、關閉看門狗
b、比較當前pc指針域TEXT_BASE的高8位是否一樣來判斷,當前代碼是否在內存中
c、對系統時鐘初始化
d、對內存初始化
e、對串口初始化
結束后返回 start.S
第一階段結束,總結如下:
1 前面總結過的部分,初始化異常向量表,設置svc模式
2 配置cp15,初始化mmu cache tlb
3 板級初始化,clk,memory,uart初始化
二、第二階段開始:
按"CTRL + ] ", 發現 _main 在兩處有定義:
這里我們選擇第一個Bl??_main?,跳轉到arch/arm/lib/crt0.S
1、初始c運行環境(看注釋就知道,初始化C運行環境,并調用board_init_f 函數)
功能:
初始化sp ,為支持C語言做準備;
保存128B 放GD結構體,存放全局信息,GD的地址存放在r8中;
跳轉到 board_init_f 函數,其在arch/arm/lib/board.c 處定義;
2、跳轉到arch/arm/lib/board.c
功能:
對全局信息GD結構體進行填充:
291行:mon_len 通過鏈接腳本可以知道存放的是uboot代碼大小;
294行:fdt_blob 存放設備數地址;
303行:循環執行init_fnc_t數組的函數,作硬件初始化;
a --?init_fnc_t數組的函數定義
? ? ?初始化硬件
b -- Dram_init初始化成功之后,剩余代碼將會對sdram空間進行規劃。
可以看到addr的值由CONFIG_SYS_SDRAM_BASE加上ram_size。也就是到了可用sdram的頂端。
e--繼續對gd結構體填充
如果icahe 與 dcache 是打開的,就留出 64K 的空間作為 tlb 空間,最后 addr 就是tlb 地址,4K對齊。
f --填充完成將信息拷貝到內存指定位置
2 -- 繼續回到 _main
按"CTRL + O"回到跳轉前的函數,即?arch/arm/lib/crt0.S
功能:
將 r8 指向新的 gd 地址;
代碼重定位;
?對lr 的操作為了讓返回時,返回的是重定位的here處
3 -- 代碼自搬移
代碼自搬移,防止與內核沖突,代碼位于arch/arm/cpu/armv7/start.S
循環將代碼搬移到指定高地址
這里只是將鏈接腳本中_image_copy_end到_start中的代碼,其它段還沒有操作。
在這里我們有疑惑就是將代碼重定位到高地址,那運行的地址不就和鏈接地址不一樣了,那運行可能不正常?這個疑惑就是.rel.dyn幫我們解決了,主要還是編譯器幫我們做的工作,在鏈接中有如下:【參考:http://blog.csdn.net/skyflying2012/article/details/37660265】
4 -- 重定位到高地址之后,再次回到 _main(arch/arm/lib/crt0.S)
? ? ? 此時回到的是剛才的重定位的 here 處
關 icache,保證數據從SDRAM中更新,更新異常向量表,因為代碼被重定位了;
清BBS;
調用board_init_r主要是對外設的初始化。
R0=gd
R1=RELOCADDR
5 -- Main_loop 函數進入超循環(arch/arm/lib/board.c)
Main_loop函數主要功能是處理環境變量,解析命令
install_auto_complete();??//安裝自動補全的函數,分析如下?。
getenv(bootcmd)
bootdelay(自啟動)
如果延時大于等于零,并且沒有在延時過程中接收到按鍵,則引導內核。
總結
以上是生活随笔為你收集整理的Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓活动(Activity)和碎片(Fr
- 下一篇: HiveQL(三):修改表ALTER T