文/關(guān)志華
U-Boot是一款通用型的引導(dǎo)程序,具有良好的兼容性與靈活性,支持PowerPC、X86和ARM等常用系列的處理器。
如需利用PowerPC處理器與Linux系統(tǒng)進(jìn)行相關(guān)設(shè)備與產(chǎn)品的開發(fā),必須對U-Boot進(jìn)行分析與了解。本文以MPC8306為例,對U-Boot的架構(gòu)與啟動(dòng)流程進(jìn)行詳細(xì)分析,MPC8306為Freescale在2010年推出的PowerQUICCⅡPro處理器,具有極高的的性價(jià)比與系統(tǒng)穩(wěn)定性,適合應(yīng)用于工業(yè)及軍事設(shè)備,具體的系統(tǒng)架構(gòu)如圖1所示。
如需進(jìn)行MPC8306的U-Boot移植,必須對其系統(tǒng)架構(gòu)有一定了解,主要目錄介紹如下:
(1)Arch:存放不同型號CPU的庫文件。其中,start.S是非常重要的一個(gè)文件,貫穿了U-Boot啟動(dòng)的整個(gè)流程,主要負(fù)責(zé)設(shè)置系統(tǒng)堆棧以及相關(guān)工作方式。
(2)Board:板級配置相關(guān)文件。
(3)Common:通用類型的代碼文件。
(4)Include:存放頭文件的文件夾。子目錄 include/configs下與目標(biāo)板相關(guān)的配置頭文件是移植過程中經(jīng)常要修改的文件,可配置目標(biāo)板的各項(xiàng)參數(shù)(如波特率、引導(dǎo)啟動(dòng)參數(shù)等)。
MPC8306的U-Boot啟動(dòng)流程主要分為兩個(gè)階段:Stage 1與Stage2。Stage1中,以Start.s文件為基本流程,代碼主要由匯編語言組成,也會(huì)調(diào)用一些C語言;Stage 2主要由C 語言組成,以board.c文件為基本流程,負(fù)責(zé)完成板級系統(tǒng)的初始化。具體啟動(dòng)流程如圖2所示。
圖1:MPC8306的系統(tǒng)架構(gòu)
圖2:MPC8306的U-Boot啟動(dòng)流程
硬件復(fù)位完成后,CPU開始讀取系統(tǒng)復(fù)位向量對應(yīng)的偏移地址為0x100處的第一條指令,這條指令位于U-Boot中Start.S文件的_Start處。_Start為整個(gè)U-Boot的全局入口。
當(dāng)程序運(yùn)行到Start.S的bl init_e300_core分支語句時(shí),程序跳轉(zhuǎn)到init_e300_core函數(shù)中,這個(gè)函數(shù)主要進(jìn)行e300內(nèi)核的初始化,為系統(tǒng)創(chuàng)建一個(gè)干凈可靠的初始環(huán)境。
內(nèi)核初始化完成后,需要對啟動(dòng)Rom的絕對地址進(jìn)行重映射,通過Start.S中的map_flash_by_law1函數(shù)和remap_flash_by_law0函數(shù)可以完成。
初識化PowerPC內(nèi)部cache需要通過操作BAT以及TLB來實(shí)現(xiàn),利用Start.S中的setup_bats將IBAT0~7以及DBAT0~7初始化,并禁用TLB。
enable_addr_trans、dcache_enable和lock_ram_in_cache函數(shù)負(fù)責(zé)使能地址翻譯與D-Cache,lock_ram_in_cache負(fù)責(zé)鎖定,然后建立堆棧。
堆棧建立完成后,流程跳轉(zhuǎn)到cpu_init.c文件的cpu_init_f()函數(shù)。該函數(shù)主要負(fù)責(zé)CPU 寄存器的初始化,尤其是初始化Local Access Windows的值和片選BRx,ORx的值。
執(zhí)行完CPU寄存器的初始化后,程序返回到Start.S中,并通過分支語句“bl board_init_f”跳轉(zhuǎn)到board.c中的C函數(shù)board_init_f()中,為全局變量結(jié)構(gòu)體gd分配內(nèi)存空間(在global_data.h中可以定義gd_t結(jié)構(gòu)體),并運(yùn)行初始化序列init_sequence,初始化序列init_sequence主要負(fù)責(zé)板級硬件相關(guān)函數(shù)的初始化。
board_init_f()函數(shù)之前,U-Boot代碼一直在Nor-Flash中運(yùn)行。內(nèi)存初始化完成以后,程序返回start.S,然后調(diào)用relocate_code()函數(shù)完成從Flash到RAM的代碼復(fù)制,記錄目前執(zhí)行代碼的偏移,并跳轉(zhuǎn)到RAM中相應(yīng)的位置執(zhí)行。最后還需設(shè)置RAM中的堆棧,并跳轉(zhuǎn)到的Stage2。
Stage2的入口點(diǎn)為Start.S的分支語句“bl board_init_r”,由此語句跳轉(zhuǎn)到board.c文件的board_init_r()函數(shù)中,并在RAM中運(yùn)行。該函數(shù)主要負(fù)責(zé)高速緩存器和本階段相關(guān)外設(shè)的初始化。主要的子函數(shù)如下所示:
mem_malloc_init():內(nèi)存分配初始化;
cpu_init_r ():初始化CPU的高等級部分,比如QE;
flash_init():初始化Nor Flash,使之支持寫入、擦除功能;
env_relocate ():環(huán)境變量功能指針從ROM到bd結(jié)構(gòu)體的搬移;
stdio_init ():標(biāo)準(zhǔn)化I/O初始化;
console_init_r():再次初始化控制臺串口;
main_loop():主循環(huán)函數(shù)。
初始化完成后,程序自動(dòng)跳轉(zhuǎn)到主循環(huán)main_loop()函數(shù),檢查環(huán)境變量中是否定義bootdelay的值,如果已定義就把值讀出來,該環(huán)境變量值定義了進(jìn)入U(xiǎn)-Boot的等待時(shí)間。如果在此時(shí)間內(nèi)沒有按鍵,從串口查詢不到按鍵輸入,則執(zhí)行設(shè)置的缺省命令。若有按鍵輸入則進(jìn)入命令循環(huán),顯示命令行模式的交互界面,接受用戶從串口輸入的命令。在該界面下,每從串行口讀入一個(gè)命令行,則調(diào)用common/main.c中的run_command()函數(shù)完成對命令行的解析,發(fā)現(xiàn)相符就以命令行中的參數(shù)調(diào)用相應(yīng)的函數(shù)。
本文結(jié)合MPC8306的芯片手冊與U-Boot源代碼詳細(xì)分析了U-Boot的啟動(dòng)流程,并對其中各源碼文件與重要函數(shù)的意義進(jìn)行說明。為U-Boot在MPC8306相關(guān)產(chǎn)品板的移植提供了理論基礎(chǔ),能夠有效縮短項(xiàng)目的開發(fā)時(shí)間。