中北大學 姚文俊 裴煥斗
隨著計算機與通信技術的飛速發展,尤其是互聯網的迅速普及,嵌入式的應用越來越廣泛,嵌入式系統的微型化和專業化成為發展的新趨勢。而在所有嵌入式系統中又由于嵌入式Linux具有源代碼開放、易于移植、資源豐富、免費等優點而被廣泛使用,并且將越來越流行。而在嵌入式硬件平臺中又以ARM的應用最為廣泛,其中Atmel公司的AT91SAM9263是一款性能優越、功能強大的ARM9處理器,且在工業控制上應用廣泛。
嵌入式的開發過程包括硬件和軟件兩方面的開發,而其中軟件開發又可以分為四個部分,即引導加載程序、Linux內核、文件系統和用戶應用程序,而引導加載程序即啟動代碼是整個開發的第一步,也是非常關鍵的一步,會直接影響到后面幾步的開發效率和系統的整體性能。所以對系統啟動過程的了解和熟悉,是編寫好高效啟動代碼的前提,也會為后續的開發提高效率。
系統上電后,CPU首先會根據BMS引腳上的電平情況來選擇啟動存儲器,如果BMS為1,選擇啟動的存儲器是內部的ROM,如果BMS為O,選擇啟動的存儲器是連接于外部總線接口片選O處的存儲器,本文以從內部ROM啟動為例來說明啟動過程(BMS=1)。在選擇為內部ROM啟動后,系統會先運行一段固化在ROM中的boot代碼,它會初始化處理器和一些必要的外設比如:調試部件串行端口(DBGU)和USB設備端口,然后依次檢測SD卡、nandflash、dataflash等存儲器的OxO地址處有沒有符合bootstrap規范的啟動程序,如果有則執行bootstrap代碼,如果沒有有效的bootstrap,則會接著執行SAM-BA,它會等待USB設備或DBUG串行端口上的事件發生。
當系統執行到檢測合法的bootstrap存儲位置時(以dataFlash啟動為例)ARM芯片會讀取與SPIO端口相連的dataflash的八個中斷向量,看是否符合一定的規則,如果合適則將dataflash中所存儲的啟動代碼下載到SRAM,然后經存儲器的remap后,SRAM從映射前的Ox3OOOOO地址被映射到了OxO地址,從而bootstrap的代碼已經出現在OxO的SRAM空間中,然后程序從此處開始執行去尋找一個有效的應用程序,此應用程序可以是跑裸機程序時的應用程序代碼,也可以是一個二級的bootloader(本文是u-boot)。圖2為存儲器重映射圖,

圖2 存儲器重映射
嵌入式系統的bootloader是系統上電后運行的第一個程序。它的作用如同PC機中的BIOS,是在操作系統運行之前的一段小程序。通過這段小程序系統可以初始化硬件設備,將系統的軟硬件環境帶到一個合適的狀態,為調用操作系統做好準備。Bootloader的啟動過程根據處理器的不同和具體的功用一般可以分為兩種,一種是先運行小型的bootstrap來完成低級別的初始化,然后再調用如Uboot,RedBOOT等功能強大的引導程序進行全面的初始化、設置操作系統內核的加載地址和運行參數等等,這類的處理器以Atmel公司AT91SAM926x為代表。另外一種是直接使用Uboot等引導程序兩步合成一步完成引導任務,這類處理器如samsung公司的s3c24xx系列等。Atmel公司的AT91SAM9263的bootloader采用第一種擁有兩級的boot,分別是第一級的bootstrap和第二級的u-boot或者RedBOOT等等。所以系統上電后會首先運行bootstrap,然后引導u-boot,最后再把控制權交給u-boot,這樣做的目的是可以提供更多更復雜的功能,而且具有更好的可移植性,提高開發效率。

圖3 bootstrap工程組織結構圖

圖4 uboot整體工作流程
Bootstrap被應用于AT91SAM9263微處理器的第一級啟動代碼,它的代碼包括匯編和C語言兩部分,主要工作就是一些硬件的初始化和將uboot的內容拷貝到外部的內存中,然后再跳轉到存儲uboot的內存地址執行uboot。對AT91SAM9263的bootstrap來說,編譯完成后由于受到內部SRAM的大小限制代碼長度必須小于4KB,然后燒寫到dataflash中的OxO處。因此整個程序也比較短小,組織結構也比較清晰。圖3為bootstrap工程組織結構圖,
從圖3可看出bootstrap結構清晰明了,其中crtO_gnu.s是系統的入口程序,完成的功能和uboot中cpu/arm926ejs下的start.s類似,主要執行設置ARM中斷向量,將bootstrap代碼從dataflash搬移到SRAM中,然后設置時鐘,初始化數據段,bss段,最后跳轉到main.c執行。
crt_gnu.s程序在系統啟動時首先被執行。其中reset是程序入口點,程序將從此處開始執行,依次執行ARM中斷向量設置,時鐘頻率設置,初始化數據段,bss段,最后跳轉到main.c執行。在main.c函數中將執行硬件初始化(hw_init()),再從dataflash里面加載代碼(load_df()),然后執行所加載的代碼程序,最后通過return JUMP_ADDR返回到crt_gnu.s函數繼續執行。其中bx rO語句就是跳轉到main函數后返回的地址。下面的代碼是bootstrap兩個重要跳轉語句,

最后程序跳轉到Ox23FOOOOO處在sdram中繼續運行uboot程序代碼。
以uboot作為系統的第二級啟動程序,而uboot的啟動又可分成stage1和stage2兩個階段。Stage1使用匯編語言編寫,與CPU的體系結構密切相關,通常執行處理器和設備的初始化等。stage2使用C語言編寫,通常進行的工作有外圍器件的初始化(如Flash器件、網絡設備等)、檢測內存映射等,最后進入命令循環,等待接收串口發送來的uboot命令進行相應的操作。Stage1和stage2兩階段分別在cpu/arm926ejs/start.s和lib_arm/board.c文件中實現。圖4為uboot兩個階段工作的整體流程圖。
3.2.1 stage1代碼啟動分析
當系統啟動過程中由bootstrap跳轉到uboot后,系統將由uboot控制引導啟動,且首先會進入由匯編語言編寫的第一階段代碼cpu/arm926ejs/start.s文件中執行,其入口標記代碼為:
.globl _start
_start: b reset
程序首先會跳轉到reset函數去執行,這個函數的主要任務是將CPU設為SVC32模式、關閉看門狗、屏蔽中斷和設置時鐘,最后跳轉到cpu_init_crit函數去執行ARM處理器的初始化。cpu_init_crit函數主要的工作是刷新指令與數據緩沖,關閉MMU,再跳轉到lowlevel_init函數處執行SDRAM的初始化。由于lowlevel_init函數的實現與具體的目標板有關,對于AT91SAM9263來說由于SDRAM的初始化已經在bootstrap中執行,所以此處不需要再執行此函數,程序會返回調用函數start.s繼續執行。relocate是系統接下來執行的函數,它負責把uboot中stage2的代碼從dataflash存儲器拷貝到SDRAM中,程序標號copy_loop:的代碼就是循環拷貝flash中的8個字節的數據到內存SDRAM,直到stage2的程序復制完畢。最后程序通過ldr pc, _start_armboot語句將程序指針寄存器設置為start_armboot函數的地址,跳轉到stage2部分去執行。
3.2.2 stage2代碼啟動分析
當程序跳轉到stage2部分后會首先進入start_armboot函數,它是一個C語言函數,位于lib_arm/board.c文件中。這個階段的任務是進一步進行系統的初始化工作,包括dataflash、nandflash、串口、網卡等的初始化。在函數初始化配置完后,程序即進入for死循環執行main_loop函數。main_loop函數是一個與具體平臺無關的函數,主要工作包括初始化啟動次數限制機制、設置軟件版本號、打印啟動信息、解析命令等。main_loop在初始化完畢后,會設置延時等待用以確定目標板是進入下載操作模式還是裝載鏡像文件啟動內核程序,此時程序會停在main_loop()函數的for死循環里不斷調用readline函數,等待用戶命令的輸入,然后解析命令并執行相應的操作。
3.2.3 uboot命令引導linux Kernel的實現
Uboot中引導內核最常用的方法是bootm命令,當系統進入裝載模式裝載鏡像文件來啟動內核程序時,需要運行bootm命令。對于AT91SAM9263則需運行命令bootm Ox2OOO8OOO來進入do_bootm_linux函數調用內核啟動函數。在啟動函數中,下面兩條語句非常關鍵:

其中(1)是將內核的入口地址Ox2OOO8 OOO賦給了thekernel,第二句是啟動內核時給內核傳入參數的三個變量,分別用通用寄存器rO,r1,r2傳給內核,其中RO=O,R1=機器類型ID,R2=啟動參數數據結構的首地址。這樣linux kernel就可以被正常引導啟動了。
本文對基于AT91SAM9263的嵌入式Linux系統的啟動過程進行了比較詳細的分析,從系統上電到引導內核的過程都結合代碼進行了說明。在嵌入式產品的開發過程中,啟動代碼的編寫是開發的第一步,起著非常重要的作用。尤其是在嵌入式的應用越來越廣泛,競爭越來越激烈的今天,好的啟動程序會增加產品的競爭力。
[1]AT91SAM9263 datasheet:93-103.
[2]張曉林,崔迎煒.嵌入式系統設計與實踐[M].北京:北京航空航天大學出版社,2006.
[3]韋東山編著.嵌入式Linux應用開發完全手冊[M].人民郵電出版社,2008:240-248.
[4]弓雷等編著.ARM嵌入式Linux系統開發詳解[M].清華大學出版社,2010.1:229-249.