- 論壇徽章:
- 0
|
u-boot 啟動流程一 (mips) - [
uboot
]
版權(quán)聲明
:轉(zhuǎn)載時請以超鏈接形式標明文章原始出處和作者信息及
本聲明
http://redboot.blogbus.com/logs/34852847.html
本來老早就應該寫這篇文章。不過,家里有事,剛來了個小寶寶。呵呵,真是忙的不行。不過,小家伙也真是可愛。現(xiàn)在終于有點空,把它整理一下,寫出來。
u-boot的啟動過程比較簡單,大致做下面的工作:
1 cpu初始化
2 時鐘,串口,內(nèi)存(ddr ram)初始化
3 內(nèi)存劃分,分配棧,數(shù)據(jù),配置參數(shù),以及u-boot代碼在內(nèi)存中的位置。
4 對u-boot代碼做relocate
5 初始化 malloc,flash,pci 以及外設(比如,網(wǎng)口)
6 進入命令行或者直接啟動Linux kernel
基本上,這就是u-boot的啟動要做的事情,我也曾經(jīng)大致看過arm的啟動代碼,也是類似。
不過,這里以mips作為例子進行介紹。
啟動涉及到幾個文件: start.S, cache.S, lowlevel_init.S 和 board.c 前三個都是匯編代碼。
程
序從start.S的_start開始執(zhí)行。首先,初始化中斷向量,寄存器清零,大致包括32個通用寄存器reg0-reg31和協(xié)處理器的一些寄存
器:CP0_WATCHLO, CP0_WATCHHI, CP0_CAUSE, CP0_COUNT, CP0_COMPARE等等。
之后,配置寄存器CP0_STATUS,設置所使用的協(xié)處理器,中斷以及cpu運行級別(核心級)。
配置gp寄存器,把GOT段的地址賦給gp寄存器。(gp寄存器的用處會在后面relocate code的部分詳細解釋)
這時,開始執(zhí)行l(wèi)owlevel_init.S的lowlevel_init,主要目的是工作頻率配置,比如cpu的主頻,總線(AHB),DDR工作頻率等。
然
后,調(diào)用cache.S的mips_cache_reset對cache進行初始化。接著調(diào)用cache.S的mips_cache_lock。這個調(diào)用
的目的,起初讓我不解,后來才知道。這時ddr
ram并沒有配置好,而如果直接調(diào)用c語言的函數(shù)必須完成棧的設置,而棧必定要在ram中。所以,只有先把一部分cache拿來當ram用。做法就是把一
部分cache配置為棧的地址,鎖定。這樣,當讀寫棧的內(nèi)存空間時,只會訪問cache,而不會訪問真的ram地址了。
這時,配置棧的地址,進行調(diào)用函數(shù)board_init_f(board.c)
進入函數(shù)board_init_f后,首先做一系列初始化:
timer_init 時鐘初始化
env_init 環(huán)境變量初始化(取得環(huán)境變量存放的地址)
init_baudrate 串口速率
serial_init 串口初始化
console_init_f 配置控制臺
display_banner 顯示u-boot啟動信息,版本號等
checkboard 執(zhí)行board相關(guān)的操作。
init_func_ram 初始化內(nèi)存,配置ddr controller
這一系列工作完成后,串口和內(nèi)存都已經(jīng)可以用了。然后,就要把內(nèi)存進行劃分,
在內(nèi)存的最后一部分,留出u-boot代碼大小的空間,準備把u-boot代碼從flash搬移到這里
然后,是堆的空間,malloc的內(nèi)存就來自于這里。緊接著放兩個全局數(shù)據(jù)結(jié)構(gòu)bd_info global_data和環(huán)境變量boot_params。最后,是棧的空間。
內(nèi)存劃分好,就準備進行relocate code了。關(guān)于relocate code和其他啟動過程
下次
再介紹。
u-boot 啟動流程二(mips) - [
uboot
]
版權(quán)聲明
:轉(zhuǎn)載時請以超鏈接形式標明文章原始出處和作者信息及
本聲明
http://redboot.blogbus.com/logs/34859828.html
上次
講到,內(nèi)存劃分好,準備進行relocate code。
relocate code的意思是這樣的。通常u-boot的執(zhí)行代碼肯定是在flash上(當調(diào)試的時候也可以放在ram上)。當啟動起來以后,要把它從flash上搬移到ram里運行。這個工作就叫做relocate code。
但是,問題在于,flash上的地址和ram上的地址是不同的。當我們把代碼從flash上搬移到ram上以后,當執(zhí)行函數(shù)跳轉(zhuǎn)時,代碼里的函數(shù)地址還是flash上的地址,所以一跳就跳回去了。
這怎么辦呢?
在u-boot里面用的是PIC(position-independent code)的方式解決這個問題。
簡
單介紹一下其原理。當你用PIC方式時,在用gcc編譯時需加上 -fpic的選項。編譯器會為你的可執(zhí)行代碼建立一個GOT(global
offset
table)的段。一個地址在GOT表中有一項,里面存放地址的信息,而在使用這個地址時,只要根據(jù)這個地址的編號(也可以叫做偏移量offset)找到
表中相應的項目,就可以取得那個地址了。
而如果位置發(fā)生變化,只要對GOT表中的地址進行修改就可以了。
我們可以通過反匯編,看一個簡單的函數(shù)調(diào)用例子:
lw t9,1088(gp)
jalr t9
這里,gp存放的就是GOT表的起始地址,而1088就是要調(diào)用函數(shù)的offset,也就是說GOT表的那個位置存放著它的地址。lw t9,1088(gp) 把函數(shù)地址放入t9, 然后調(diào)用就可以了。
知道了PIC的原理,解釋u-boot relocate code的方法就簡單了。
簡單的說就把u-boot的執(zhí)行代碼直接從flash里copy到ram的相應區(qū)域。
然后,把GOT表中的地址都加上一個偏移量,這個偏移量就是flash里的地址與ram里的地址的差。
還有其他一些工作比如:設置新的棧指針,從flash代碼里跳轉(zhuǎn)到ram代碼里 等等。
之后,就進入board.c的board_init_r函數(shù),在這個函數(shù)里初始化 malloc,flash,pci 以及外設(比如,網(wǎng)口),最后進入命令行或者直接啟動Linux kernel。
這樣,u-boot的啟動工作就完成了。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/28889/showart_1849205.html |
|