文/關志華
U-Boot是一款通用型的引導程序,具有良好的兼容性與靈活性,支持PowerPC、X86和ARM等常用系列的處理器。
如需利用PowerPC處理器與Linux系統(tǒng)進行相關設備與產品的開發(fā),必須對U-Boot進行分析與了解。本文以MPC8306為例,對U-Boot的架構與啟動流程進行詳細分析,MPC8306為Freescale在2010年推出的PowerQUICCⅡPro處理器,具有極高的的性價比與系統(tǒng)穩(wěn)定性,適合應用于工業(yè)及軍事設備,具體的系統(tǒng)架構如圖1所示。
如需進行MPC8306的U-Boot移植,必須對其系統(tǒng)架構有一定了解,主要目錄介紹如下:
(1)Arch:存放不同型號CPU的庫文件。其中,start.S是非常重要的一個文件,貫穿了U-Boot啟動的整個流程,主要負責設置系統(tǒng)堆棧以及相關工作方式。
(2)Board:板級配置相關文件。
(3)Common:通用類型的代碼文件。
(4)Include:存放頭文件的文件夾。子目錄 include/configs下與目標板相關的配置頭文件是移植過程中經常要修改的文件,可配置目標板的各項參數(shù)(如波特率、引導啟動參數(shù)等)。
MPC8306的U-Boot啟動流程主要分為兩個階段:Stage 1與Stage2。Stage1中,以Start.s文件為基本流程,代碼主要由匯編語言組成,也會調用一些C語言;Stage 2主要由C 語言組成,以board.c文件為基本流程,負責完成板級系統(tǒng)的初始化。具體啟動流程如圖2所示。

圖1:MPC8306的系統(tǒng)架構

圖2:MPC8306的U-Boot啟動流程
硬件復位完成后,CPU開始讀取系統(tǒng)復位向量對應的偏移地址為0x100處的第一條指令,這條指令位于U-Boot中Start.S文件的_Start處。_Start為整個U-Boot的全局入口。
當程序運行到Start.S的bl init_e300_core分支語句時,程序跳轉到init_e300_core函數(shù)中,這個函數(shù)主要進行e300內核的初始化,為系統(tǒng)創(chuàng)建一個干凈可靠的初始環(huán)境。
內核初始化完成后,需要對啟動Rom的絕對地址進行重映射,通過Start.S中的map_flash_by_law1函數(shù)和remap_flash_by_law0函數(shù)可以完成。
初識化PowerPC內部cache需要通過操作BAT以及TLB來實現(xiàn),利用Start.S中的setup_bats將IBAT0~7以及DBAT0~7初始化,并禁用TLB。
enable_addr_trans、dcache_enable和lock_ram_in_cache函數(shù)負責使能地址翻譯與D-Cache,lock_ram_in_cache負責鎖定,然后建立堆棧。
堆棧建立完成后,流程跳轉到cpu_init.c文件的cpu_init_f()函數(shù)。該函數(shù)主要負責CPU 寄存器的初始化,尤其是初始化Local Access Windows的值和片選BRx,ORx的值。
執(zhí)行完CPU寄存器的初始化后,程序返回到Start.S中,并通過分支語句“bl board_init_f”跳轉到board.c中的C函數(shù)board_init_f()中,為全局變量結構體gd分配內存空間(在global_data.h中可以定義gd_t結構體),并運行初始化序列init_sequence,初始化序列init_sequence主要負責板級硬件相關函數(shù)的初始化。
board_init_f()函數(shù)之前,U-Boot代碼一直在Nor-Flash中運行。內存初始化完成以后,程序返回start.S,然后調用relocate_code()函數(shù)完成從Flash到RAM的代碼復制,記錄目前執(zhí)行代碼的偏移,并跳轉到RAM中相應的位置執(zhí)行。最后還需設置RAM中的堆棧,并跳轉到的Stage2。
Stage2的入口點為Start.S的分支語句“bl board_init_r”,由此語句跳轉到board.c文件的board_init_r()函數(shù)中,并在RAM中運行。該函數(shù)主要負責高速緩存器和本階段相關外設的初始化。主要的子函數(shù)如下所示:
mem_malloc_init():內存分配初始化;
cpu_init_r ():初始化CPU的高等級部分,比如QE;
flash_init():初始化Nor Flash,使之支持寫入、擦除功能;
env_relocate ():環(huán)境變量功能指針從ROM到bd結構體的搬移;
stdio_init ():標準化I/O初始化;
console_init_r():再次初始化控制臺串口;
main_loop():主循環(huán)函數(shù)。
初始化完成后,程序自動跳轉到主循環(huán)main_loop()函數(shù),檢查環(huán)境變量中是否定義bootdelay的值,如果已定義就把值讀出來,該環(huán)境變量值定義了進入U-Boot的等待時間。如果在此時間內沒有按鍵,從串口查詢不到按鍵輸入,則執(zhí)行設置的缺省命令。若有按鍵輸入則進入命令循環(huán),顯示命令行模式的交互界面,接受用戶從串口輸入的命令。在該界面下,每從串行口讀入一個命令行,則調用common/main.c中的run_command()函數(shù)完成對命令行的解析,發(fā)現(xiàn)相符就以命令行中的參數(shù)調用相應的函數(shù)。
本文結合MPC8306的芯片手冊與U-Boot源代碼詳細分析了U-Boot的啟動流程,并對其中各源碼文件與重要函數(shù)的意義進行說明。為U-Boot在MPC8306相關產品板的移植提供了理論基礎,能夠有效縮短項目的開發(fā)時間。