中北大學(xué) 姚文俊 裴煥斗
隨著計(jì)算機(jī)與通信技術(shù)的飛速發(fā)展,尤其是互聯(lián)網(wǎng)的迅速普及,嵌入式的應(yīng)用越來越廣泛,嵌入式系統(tǒng)的微型化和專業(yè)化成為發(fā)展的新趨勢(shì)。而在所有嵌入式系統(tǒng)中又由于嵌入式Linux具有源代碼開放、易于移植、資源豐富、免費(fèi)等優(yōu)點(diǎn)而被廣泛使用,并且將越來越流行。而在嵌入式硬件平臺(tái)中又以ARM的應(yīng)用最為廣泛,其中Atmel公司的AT91SAM9263是一款性能優(yōu)越、功能強(qiáng)大的ARM9處理器,且在工業(yè)控制上應(yīng)用廣泛。
嵌入式的開發(fā)過程包括硬件和軟件兩方面的開發(fā),而其中軟件開發(fā)又可以分為四個(gè)部分,即引導(dǎo)加載程序、Linux內(nèi)核、文件系統(tǒng)和用戶應(yīng)用程序,而引導(dǎo)加載程序即啟動(dòng)代碼是整個(gè)開發(fā)的第一步,也是非常關(guān)鍵的一步,會(huì)直接影響到后面幾步的開發(fā)效率和系統(tǒng)的整體性能。所以對(duì)系統(tǒng)啟動(dòng)過程的了解和熟悉,是編寫好高效啟動(dòng)代碼的前提,也會(huì)為后續(xù)的開發(fā)提高效率。
系統(tǒng)上電后,CPU首先會(huì)根據(jù)BMS引腳上的電平情況來選擇啟動(dòng)存儲(chǔ)器,如果BMS為1,選擇啟動(dòng)的存儲(chǔ)器是內(nèi)部的ROM,如果BMS為O,選擇啟動(dòng)的存儲(chǔ)器是連接于外部總線接口片選O處的存儲(chǔ)器,本文以從內(nèi)部ROM啟動(dòng)為例來說明啟動(dòng)過程(BMS=1)。在選擇為內(nèi)部ROM啟動(dòng)后,系統(tǒng)會(huì)先運(yùn)行一段固化在ROM中的boot代碼,它會(huì)初始化處理器和一些必要的外設(shè)比如:調(diào)試部件串行端口(DBGU)和USB設(shè)備端口,然后依次檢測(cè)SD卡、nandflash、dataflash等存儲(chǔ)器的OxO地址處有沒有符合bootstrap規(guī)范的啟動(dòng)程序,如果有則執(zhí)行bootstrap代碼,如果沒有有效的bootstrap,則會(huì)接著執(zhí)行SAM-BA,它會(huì)等待USB設(shè)備或DBUG串行端口上的事件發(fā)生。
當(dāng)系統(tǒng)執(zhí)行到檢測(cè)合法的bootstrap存儲(chǔ)位置時(shí)(以dataFlash啟動(dòng)為例)ARM芯片會(huì)讀取與SPIO端口相連的dataflash的八個(gè)中斷向量,看是否符合一定的規(guī)則,如果合適則將dataflash中所存儲(chǔ)的啟動(dòng)代碼下載到SRAM,然后經(jīng)存儲(chǔ)器的remap后,SRAM從映射前的Ox3OOOOO地址被映射到了OxO地址,從而bootstrap的代碼已經(jīng)出現(xiàn)在OxO的SRAM空間中,然后程序從此處開始執(zhí)行去尋找一個(gè)有效的應(yīng)用程序,此應(yīng)用程序可以是跑裸機(jī)程序時(shí)的應(yīng)用程序代碼,也可以是一個(gè)二級(jí)的bootloader(本文是u-boot)。圖2為存儲(chǔ)器重映射圖,
圖2 存儲(chǔ)器重映射
嵌入式系統(tǒng)的bootloader是系統(tǒng)上電后運(yùn)行的第一個(gè)程序。它的作用如同PC機(jī)中的BIOS,是在操作系統(tǒng)運(yùn)行之前的一段小程序。通過這段小程序系統(tǒng)可以初始化硬件設(shè)備,將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適的狀態(tài),為調(diào)用操作系統(tǒng)做好準(zhǔn)備。Bootloader的啟動(dòng)過程根據(jù)處理器的不同和具體的功用一般可以分為兩種,一種是先運(yùn)行小型的bootstrap來完成低級(jí)別的初始化,然后再調(diào)用如Uboot,RedBOOT等功能強(qiáng)大的引導(dǎo)程序進(jìn)行全面的初始化、設(shè)置操作系統(tǒng)內(nèi)核的加載地址和運(yùn)行參數(shù)等等,這類的處理器以Atmel公司AT91SAM926x為代表。另外一種是直接使用Uboot等引導(dǎo)程序兩步合成一步完成引導(dǎo)任務(wù),這類處理器如samsung公司的s3c24xx系列等。Atmel公司的AT91SAM9263的bootloader采用第一種擁有兩級(jí)的boot,分別是第一級(jí)的bootstrap和第二級(jí)的u-boot或者RedBOOT等等。所以系統(tǒng)上電后會(huì)首先運(yùn)行bootstrap,然后引導(dǎo)u-boot,最后再把控制權(quán)交給u-boot,這樣做的目的是可以提供更多更復(fù)雜的功能,而且具有更好的可移植性,提高開發(fā)效率。
圖3 bootstrap工程組織結(jié)構(gòu)圖
圖4 uboot整體工作流程
Bootstrap被應(yīng)用于AT91SAM9263微處理器的第一級(jí)啟動(dòng)代碼,它的代碼包括匯編和C語言兩部分,主要工作就是一些硬件的初始化和將uboot的內(nèi)容拷貝到外部的內(nèi)存中,然后再跳轉(zhuǎn)到存儲(chǔ)uboot的內(nèi)存地址執(zhí)行uboot。對(duì)AT91SAM9263的bootstrap來說,編譯完成后由于受到內(nèi)部SRAM的大小限制代碼長度必須小于4KB,然后燒寫到dataflash中的OxO處。因此整個(gè)程序也比較短小,組織結(jié)構(gòu)也比較清晰。圖3為bootstrap工程組織結(jié)構(gòu)圖,
從圖3可看出bootstrap結(jié)構(gòu)清晰明了,其中crtO_gnu.s是系統(tǒng)的入口程序,完成的功能和uboot中cpu/arm926ejs下的start.s類似,主要執(zhí)行設(shè)置ARM中斷向量,將bootstrap代碼從dataflash搬移到SRAM中,然后設(shè)置時(shí)鐘,初始化數(shù)據(jù)段,bss段,最后跳轉(zhuǎn)到main.c執(zhí)行。
crt_gnu.s程序在系統(tǒng)啟動(dòng)時(shí)首先被執(zhí)行。其中reset是程序入口點(diǎn),程序?qū)拇颂庨_始執(zhí)行,依次執(zhí)行ARM中斷向量設(shè)置,時(shí)鐘頻率設(shè)置,初始化數(shù)據(jù)段,bss段,最后跳轉(zhuǎn)到main.c執(zhí)行。在main.c函數(shù)中將執(zhí)行硬件初始化(hw_init()),再從dataflash里面加載代碼(load_df()),然后執(zhí)行所加載的代碼程序,最后通過return JUMP_ADDR返回到crt_gnu.s函數(shù)繼續(xù)執(zhí)行。其中bx rO語句就是跳轉(zhuǎn)到main函數(shù)后返回的地址。下面的代碼是bootstrap兩個(gè)重要跳轉(zhuǎn)語句,
最后程序跳轉(zhuǎn)到Ox23FOOOOO處在sdram中繼續(xù)運(yùn)行uboot程序代碼。
以u(píng)boot作為系統(tǒng)的第二級(jí)啟動(dòng)程序,而uboot的啟動(dòng)又可分成stage1和stage2兩個(gè)階段。Stage1使用匯編語言編寫,與CPU的體系結(jié)構(gòu)密切相關(guān),通常執(zhí)行處理器和設(shè)備的初始化等。stage2使用C語言編寫,通常進(jìn)行的工作有外圍器件的初始化(如Flash器件、網(wǎng)絡(luò)設(shè)備等)、檢測(cè)內(nèi)存映射等,最后進(jìn)入命令循環(huán),等待接收串口發(fā)送來的uboot命令進(jìn)行相應(yīng)的操作。Stage1和stage2兩階段分別在cpu/arm926ejs/start.s和lib_arm/board.c文件中實(shí)現(xiàn)。圖4為uboot兩個(gè)階段工作的整體流程圖。
3.2.1 stage1代碼啟動(dòng)分析
當(dāng)系統(tǒng)啟動(dòng)過程中由bootstrap跳轉(zhuǎn)到uboot后,系統(tǒng)將由uboot控制引導(dǎo)啟動(dòng),且首先會(huì)進(jìn)入由匯編語言編寫的第一階段代碼cpu/arm926ejs/start.s文件中執(zhí)行,其入口標(biāo)記代碼為:
.globl _start
_start: b reset
程序首先會(huì)跳轉(zhuǎn)到reset函數(shù)去執(zhí)行,這個(gè)函數(shù)的主要任務(wù)是將CPU設(shè)為SVC32模式、關(guān)閉看門狗、屏蔽中斷和設(shè)置時(shí)鐘,最后跳轉(zhuǎn)到cpu_init_crit函數(shù)去執(zhí)行ARM處理器的初始化。cpu_init_crit函數(shù)主要的工作是刷新指令與數(shù)據(jù)緩沖,關(guān)閉MMU,再跳轉(zhuǎn)到lowlevel_init函數(shù)處執(zhí)行SDRAM的初始化。由于lowlevel_init函數(shù)的實(shí)現(xiàn)與具體的目標(biāo)板有關(guān),對(duì)于AT91SAM9263來說由于SDRAM的初始化已經(jīng)在bootstrap中執(zhí)行,所以此處不需要再執(zhí)行此函數(shù),程序會(huì)返回調(diào)用函數(shù)start.s繼續(xù)執(zhí)行。relocate是系統(tǒng)接下來執(zhí)行的函數(shù),它負(fù)責(zé)把uboot中stage2的代碼從dataflash存儲(chǔ)器拷貝到SDRAM中,程序標(biāo)號(hào)copy_loop:的代碼就是循環(huán)拷貝flash中的8個(gè)字節(jié)的數(shù)據(jù)到內(nèi)存SDRAM,直到stage2的程序復(fù)制完畢。最后程序通過ldr pc, _start_armboot語句將程序指針寄存器設(shè)置為start_armboot函數(shù)的地址,跳轉(zhuǎn)到stage2部分去執(zhí)行。
3.2.2 stage2代碼啟動(dòng)分析
當(dāng)程序跳轉(zhuǎn)到stage2部分后會(huì)首先進(jìn)入start_armboot函數(shù),它是一個(gè)C語言函數(shù),位于lib_arm/board.c文件中。這個(gè)階段的任務(wù)是進(jìn)一步進(jìn)行系統(tǒng)的初始化工作,包括dataflash、nandflash、串口、網(wǎng)卡等的初始化。在函數(shù)初始化配置完后,程序即進(jìn)入for死循環(huán)執(zhí)行main_loop函數(shù)。main_loop函數(shù)是一個(gè)與具體平臺(tái)無關(guān)的函數(shù),主要工作包括初始化啟動(dòng)次數(shù)限制機(jī)制、設(shè)置軟件版本號(hào)、打印啟動(dòng)信息、解析命令等。main_loop在初始化完畢后,會(huì)設(shè)置延時(shí)等待用以確定目標(biāo)板是進(jìn)入下載操作模式還是裝載鏡像文件啟動(dòng)內(nèi)核程序,此時(shí)程序會(huì)停在main_loop()函數(shù)的for死循環(huán)里不斷調(diào)用readline函數(shù),等待用戶命令的輸入,然后解析命令并執(zhí)行相應(yīng)的操作。
3.2.3 uboot命令引導(dǎo)linux Kernel的實(shí)現(xiàn)
Uboot中引導(dǎo)內(nèi)核最常用的方法是bootm命令,當(dāng)系統(tǒng)進(jìn)入裝載模式裝載鏡像文件來啟動(dòng)內(nèi)核程序時(shí),需要運(yùn)行bootm命令。對(duì)于AT91SAM9263則需運(yùn)行命令bootm Ox2OOO8OOO來進(jìn)入do_bootm_linux函數(shù)調(diào)用內(nèi)核啟動(dòng)函數(shù)。在啟動(dòng)函數(shù)中,下面兩條語句非常關(guān)鍵:
其中(1)是將內(nèi)核的入口地址Ox2OOO8 OOO賦給了thekernel,第二句是啟動(dòng)內(nèi)核時(shí)給內(nèi)核傳入?yún)?shù)的三個(gè)變量,分別用通用寄存器rO,r1,r2傳給內(nèi)核,其中RO=O,R1=機(jī)器類型ID,R2=啟動(dòng)參數(shù)數(shù)據(jù)結(jié)構(gòu)的首地址。這樣linux kernel就可以被正常引導(dǎo)啟動(dòng)了。
本文對(duì)基于AT91SAM9263的嵌入式Linux系統(tǒng)的啟動(dòng)過程進(jìn)行了比較詳細(xì)的分析,從系統(tǒng)上電到引導(dǎo)內(nèi)核的過程都結(jié)合代碼進(jìn)行了說明。在嵌入式產(chǎn)品的開發(fā)過程中,啟動(dòng)代碼的編寫是開發(fā)的第一步,起著非常重要的作用。尤其是在嵌入式的應(yīng)用越來越廣泛,競爭越來越激烈的今天,好的啟動(dòng)程序會(huì)增加產(chǎn)品的競爭力。
[1]AT91SAM9263 datasheet:93-103.
[2]張曉林,崔迎煒.嵌入式系統(tǒng)設(shè)計(jì)與實(shí)踐[M].北京:北京航空航天大學(xué)出版社,2006.
[3]韋東山編著.嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)[M].人民郵電出版社,2008:240-248.
[4]弓雷等編著.ARM嵌入式Linux系統(tǒng)開發(fā)詳解[M].清華大學(xué)出版社,2010.1:229-249.