U-Boot,全稱Universal Boot Loader,是遵循GPL條款的開放源碼項目,是從FADSROM、8xxROM、PPCBOOT逐步發展演化而來的。其源碼目錄、編譯形式與Linux內核很相似,事實上,不少U-Boot源碼就是相應的Linux內核源程序的簡化,尤其是一些設備的驅動程序,這從U-Boot源碼的註釋中能體現這一點。但是U-Boot不僅僅支持嵌入式Linux系統的引導,當前,它還支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系統。其目前要支持的目標操作系統是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS。這是U-Boot中Universal的一層含義,另外一層含義則是U-Boot除了支持PowerPC系列的處理器外,還能支持MIPS、 x86、ARM、NIOS、XScale等諸多常用系列的處理器。這兩個特點正是U-Boot項目的開發目標,即支持儘可能多的嵌入式處理器和嵌入式操作系統。
就目前來看,U-Boot對PowerPC系列處理器支持最爲豐富,對Linux的支持最完善。其它系列的處理器和操作系統基本是在2002年11 月PPCBOOT改名爲U-Boot後逐步擴充的。從PPCBOOT向U-Boot的順利過渡,很大程度上歸功於U-Boot的維護人德國DENX軟件工程中心Wolfgang Denk[以下簡稱W.D]本人精湛專業水平和持着不懈的努力。當前,U-Boot項目正在他的領軍之下,衆多有志於開放源碼BOOT LOADER移植工作的嵌入式開發人員正如火如荼地將各個不同系列嵌入式處理器的移植工作不斷展開和深入,以支持更多的嵌入式操作系統的裝載與引導。
選擇U-Boot的理由如下:
1、開放源碼;
2、支持多種嵌入式操作系統內核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;
3、支持多個處理器系列,如PowerPC、ARM、x86、MIPS、XScale;
4、較高的可靠性和穩定性;
5、較高的可靠性和穩定性;
6、高度靈活的功能設置,適合U-Boot調試、操作系統不同引導要求、產品發佈等;
7、豐富的設備驅動源碼,如串口、以太網、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、鍵盤等;
8、較爲豐富的開發調試文檔與強大的網絡技術支持;
本文將從整體架構出發,儘自己的理解分析u-boot源碼及其啓動原理,之後再介紹下移植u-boot時的一些技巧,最後將以敘述移植的實例的方式來闡述其使用方法。
二、程序架構
要使用u-boot,首先需要搞清楚它的程序架構,要實現啓動開發板需要修改哪些文件,下面列舉了uboot的主要目錄結構:
- board:目標板相關文件,主要包含SDRAM、Flash的驅動;
- common:獨立於處理器體系結構的通用代碼,如內存大小探測與故障檢測等,它實現了u-boot的所有命令,其中內置了一個shell腳本解釋器(hush.c,a prototype bourne shell grammar parser),busybox中也使用了它;
- cpu:與處理器相關的文件,如mpc8xx子目錄下有串口、網口、LCD驅動及中斷初始化等文件。其中cpu.c負責初始化CPU、設置指令cache和數據cache等,interrupt.c負責設置系統的各種中斷和異常,如快速中斷、開關中斷、時鐘中斷、軟件中斷、預取中止和未定義指令等,start.S負責u-boot啓動時執行的第一個文件,它主要設置系統堆棧和工作方式,爲跳轉到C程序入口點做準備;
- driver:通用設備驅動,如CFI Flash驅動(目前對INTEL Flash支持較好)
- doc:U-Boot的說明文檔;
- examples:可在U-Boot下運行的示例程序,如hello_world.c、timer.c;
- include:U-Boot頭文件,注意:configs子目錄下與目標板相關的配置頭文件是移植過程中經常要修改的文件;
- lib_xxx:處理器體系相關的文件,如lib_ppc, lib_arm目錄分別包含與PowerPC、ARM體系結構相關的文件,lib_generic爲通用的庫函數實現;
- net:與網絡功能相關的文件目錄,如bootp、nfs、sntp、tftp;
- post:上電自檢文件目錄,目前仍有待於進一步完善;
- rtc:RTC驅動程序;
- tools:用於創建U-Boot S-RECORD和BIN鏡像文件的工具;
-fs:文件系統程序,包括ext2、Jffs2等;
-disk:硬盤接口程序。
在board目錄下的每個子平臺目錄內,都有一個連接腳本文件u-boot.lds,從中可以找到u-boot的函數入口。另外,該目錄下還有一個config.mk文件,用於設置TEXT_BASE的地址,該地址就是希望運行的地址、鏈接地址。
u-boot 是一個層次式結構,要讓它跑起來,應當至少提供串口驅動(UART Driver)、以太網驅動(Ethernet Driver)、Flash 驅動(Flash 驅動)以及USB 驅動(USB Driver)。目前,通過USB 口下載程序顯得不是十分必要,所以暫時沒有移植USB 驅動。驅動層之上是u-boot 的應用,command 通過串口提供人機界面。
三、代碼分析
本文的代碼分析主要針對freescale的PowerPC芯片mpc83系列,從u-boot啓動的過程來分析其源代碼,目前大多數的bootloader都分爲了Stage1和Stage2兩個部分啓動,依賴於CPU體系結構的代碼常放在Stage1且常用彙編語言實現,在u-boot中功能代碼集中在cpu/mpc83xx/start.S中,它包括從系統上電後在基地址開始執行的部分,它運行在flash中,包括對cpu寄存器的初始化和將Stage2的代碼拷貝到SDRAM中的代碼。而Stage2則用於實現複雜的應用,用C也有更好的可讀性和移植性,主要功能代碼集中在lib_ppc/board.c中,通過指定一系列的初始化函數表,實現對系統的初始化工作。一般情況下,u-boot編譯後的程序不超過100k,且Stage1的代碼編譯後的大小一般不超過10k,。
以下內容屬轉載,雖是ARM,但PowerPC與之類似:
*************************************************************************
*/
注:ARM微處理器支持字節(8位)、半字(16位)、字(32位)3種數據類型
@向量跳轉表,每條佔四個字節(一個字),地址範圍爲0x0000 0000~@0x0000 0020
@ARM體系結構規定在上電覆位後的起始位置,必須有8條連續的跳
@轉指令,通過硬件實現。他們就是異常向量表。ARM在上電覆位後,@是從0x00000000開始啓動的,其實如果bootloader存在,在執行
@下面第一條指令後,就無條件跳轉到start_code,下面一部分並沒@執行。設置異常向量表的作用是識別bootloader。以後系統每當有@異常出現,則CPU會根據異常號,從內存的0x00000000處開始查表@做相應的處理
/******************************************************
;當一個異常出現以後,ARM會自動執行以下幾個步驟:
;1.把下一條指令的地址放到連接寄存器LR(通常是R14).---保存位置
;2.將相應的CPSR(當前程序狀態寄存器)複製到SPSR(備份的程序狀態寄存器)中---保存CPSR
;3.根據異常類型,強制設置CPSR的運行模式位
;4.強制PC(程序計數器)從相關異常向量地址取出下一條指令執行,從而跳轉到相應的異常處理程序中
*****************************************************************************/
首先來看下Stage1的過程,系統主要實現了一下的功能:
1、指定入口函數
一個可執行的鏡像必須要有且只有一個全局入口,通常情況下,這個入口函數是放在ROM的起始位置,而它是由處理器中斷復位向量來決定的,代碼如下:
. = EXC_OFF_SYS_RESET
.globl _start
_start: /* time t 0 */
li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH*/
nop
b boot_cold
. = EXC_OFF_SYS_RESET + 0x10
.globl _start_warm
_start_warm:
li r21, BOOTFLAG_WARM /* Software reboot */
b boot_warm
需要注意的是,我們必須自己告訴編譯器這個入口,而這個工作就是修改鏈接腳本文件(lds)。由上可見,函數執行開始後,一個立即讀取指令後就是一個跳轉語句。一般情況下(上電、復位等),程序都會執行boot_cold,通過調用系統復位中斷從System reset偏移向量0x100來獲取指令,每個中斷向量有256個字節的空間。另外,與start.s文件在一起的也有一個config.mk文件,該文件用於定義編譯選項。通過鏈接地址TEXT_BASE和運行地址.start的不同決定是否要複製代碼。
2、設置異常向量(Exception Vector)
異常向量表也可稱爲中斷向量表,在mpc83xx中,它是以0x100的偏移量連續分佈的,基地址的值取決於MSR[IP],當它爲0是,基地址爲0x00000000,爲1時,基地址爲0xfff00000。該值是由啓動方式決定的。源碼如下:
/*
* Vector Table
*/
.globl _start_of_vectors
_start_of_vectors:
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
/* Data Storage exception. */
STD_EXCEPTION(0x300, DataStorage, UnknownException)
/* Instruction Storage exception. */
STD_EXCEPTION(0x400, InstStorage, UnknownException)
/* External Interrupt exception. */
#ifndef FIXME
STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
#endif
/* Alignment exception. */
. = 0x600
Alignment:
EXCEPTION_PROLOG(SRR0, SRR1)
mfspr r4,DAR
stw r4,_DAR(r21)
mfspr r5,DSISR
stw r5,_DSISR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */
lwz r6,GOT(transfer_to_handler)
mtlr r6
blrl
.L_Alignment:
.long AlignmentException - _start + EXC_OFF_SYS_RESET
.long int_return - _start + EXC_OFF_SYS_RESET
….
這裏的代碼太長了,就沒再粘貼,有興趣的可以下載源碼看一下,上面的只包括了機器校驗、數據存儲異常、指令存儲異常等異常處理函數,由上也可以看到其連續存儲的特性。