(1)啓動加載模式:這種模式也稱爲“自主”模式。也就是Bootloader從目標機上的某個固態存儲設備上將操作系統加載到RAM中運行,整個過程並沒有用戶的介入,這種模式是在嵌入式產品發佈裏的通用模式。
(2) 下載模式:在這種模式下,目標機上的Bootloader將通過串口連接或網絡連接等通信手段從主機下載文件,例如:下載內核映像和根文件系統映像等。從 主機下載的文件 通常首先被Bootloader保存到目標機的RAM中,然後再被Bootloader寫到目標上的Flash類的固態存儲設備中,Bootloader 的這種模式是在在開發時使用的工作於這種模式的Bootloader通常都 會向它的終端用戶提供一個簡單的命令行接口。
在嵌入式Linux系統中從軟件的角度通常可以分爲4個層次:
(1)引導加載程序,包括固化在固件中的boot代碼(可選)和Bootloader兩大部分。
有些CPU在運行Bootloader之前運行一段固化的程序 ,比如x86結構的CPU就是先運行BIOS中的固件,然後才運行硬盤的第一個分區中的BootLoader。在大多數的嵌入式系統中並沒有固件,Bootloader是上電後第一個執行的程序。
(2)Linux內核
嵌入式定製的內核以及啓動參數,啓動參數可以是Bootloader傳遞給內核的,也可以是內核默認的。
(3)文件系統
包括根文件系統和建立於Flash內存設備之上的文件系統。裏面包括了Linux系統能夠運行所必要的應用程序和庫文件等。比如可以給用戶提供操作Linux的控制shell程序。
(4)用戶應用程序
特定於用戶的應用程序,它們也存儲在文件系統中,有時在用戶應用程序和內核層之間可以還會包括一個嵌入式圖形用戶界面。
2. Bootloader啓動的兩個階段
從固態存儲設備上啓動的Bootloader大多都是兩階段的啓動過程,第一階段使用匯編來實現。它完成一些依賴於CPU體系結構的初始化,並調用第二階段的代碼,第二階段則通常使用C語言來實現,這樣可以實現更復雜的功能,而且代碼會有更好的可讀性和可移植性。
(1) Bootloader第一階段的功能
1)硬件設備初始化
2)爲加載Bootloader的第二階段準備RAM空間。
3)複製Bootloader的第二階段代碼到RAM空間中。
4)設置好棧
5)跳轉到第二階段代碼的C入口點。
在第一階段進行的硬件初始化一般包括:關閉WATCHDOG,關中斷,設置 CPU的速度和時鐘頻率RAM初始化等。這些不都是必需的。
(2)Bootloader第二階段的功能
1)初始化本階段要使用的硬件設備
2)檢測系統內存映射
3)將內核映像和根文件系映象從Flash望到RAM空間中
4)爲內核設置啓動參數
5)調用內核
將內核存放在適當的位置後,直接跳到它的入口點即可調用內核,調用內核之前,下列條件要滿足
(1)CPU寄存器的設置
R0=0.
R1=機器類型ID;對於ARM結構的CPU,其機器類型ID在linux/arch/arm/tools/mach-types
R2=啓動參數標記列表在RAM中起始基地址
(2)CPU工作模式
必須禁止中斷(IRQs和FIQs)
CPU必須爲SVC模式
(3)Cach和MMU的設置
MMU必須關閉
指令Cach可以打開也可以關閉
數據Cach必須關閉
U-boot.bin:二進制可執行文件,它就是可以直接燒入ROM,NORFlash的文件
u-Boot:ELF格式的可執行文件,
U-Boot.srec:Motorla S-Record格式的可執行文件
對於S3C2410的開發板,執行”make smdk2410_config“."make all"後生成的U-Boot.bin可以燒入NOR Flash中運行,啓動後可以看到串口輸出一些信息後進行控制界面。
|
這是在根目錄下的MAKEFILE文件中的兩個語句,其中的MKCONFIG就是根目錄下的mkconfi文件。$(@:_config=)的結 果就是將”smdk2410_config“中的_config去掉,結果爲“smdk2410”.所以“make smdk2410_config”實際上就是執行如下命令:
|
|
(1)確定開發板名稱BOARD_NAME,相關代碼如下:
|
|
(2)創建到平臺開發板相關折頭文件的鏈接
|
|
|
|
|
APPEND維持原值"NO",所以config.h被重新建立,也就是執行echo "#include <configs/$1.h>" >>config.h
#include <configs/smdk2410.h>
總之,當你執行make smdk2410_config ,實際的作用就是執行./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0,它將產生如下的
幾種作用
(1) 開發板的名稱 BOARD_NAME等於 $1
(2)創建到平臺,開發板相關的頭文件的鏈接,如下所示
ln -s asm-$2 asm
ln -s arch-$6 asm-S2/arch
ln - s proc-armv asmn-$2/proc 如果$2不是arm的話,此行沒有
(3)創建頂層Makefile包含的incldue /config.mk,如下所示
ARCH = $2
CPU = $3
BOARD = $4
VENDOR = $ $5 爲空,或者NULL的話,些行沒有
SOC = $6
(4) 創建開發板相關的頭文件include/config.h,如下 所示
#include <config.h/$1.h>
從上面執行完命令後的結果,可以看出來,如果要在board目錄下新建一個開發板<board_name>的目錄,則在 include/configs 目錄下也要建立一個文件<board_name>.h,裏面存放的就是開發板<board_name>的配置信息。
3.U-Boot的編譯,連接過程
|
第 一行中包含的config.mk文件,就是在第一開始配置過程中製作出來的include/conifg.mk文件,我們在一開始配置U-boot時執行 過mkconfig。mini2440 時生成的文件,其中定義了ARCH,CPU,BOARD,SOC等。4個變量的值爲arm,arm920t,smdk2410,s3c24x0.我們在執 行mkconfig。mini2440時,其實執行的是如下的命令:
|
|
繼續分析MAKEFIle文件:
|
|
|
|
總結一下U-Boot的編譯流程:
(1)首先編譯cpu/$(CPU)/start.s,對於不同的CPU,還可能編譯cpu/$(CPU)下面的其他文件。
(2)然後,對於平臺開發板相關的每個目錄,每個通用目錄都使用它們各自的MAKEFILE生成相應和庫。
(3)將1,2步驟生成的.o.a文件按照$(BOARDDIR)/config.mk 文件中指定的代碼段起始地址。$(obj)u-boot.lds 連接腳本進行連接。
(4)第3步得到的是ELF格式的U-Boot,後面MAKEFILE還會將它轉換爲二進制格式 S-Record格式。
(1)硬件設備初始化
依次完成如下設置:將CPU的工作模式設爲管理模式(SVC),關閉WATCHDOG,設置FCLK,HCLK,PCLK的比例,關閉MMU,CACHE。代碼在cpu/arm920t/start.S中,
(2)爲加載Bootloader的第二階段代碼準備RAM空間。
所謂準備RAM空間,就是初始化內存芯片,使它可用,對於S3C24x0,通過在Start.S中調用lowlevel_init函數來設置存儲控制器,使得外接
|
這裏將整個U-Boot代碼都複製到SDRAM中,這在cpu/arm920t/start.s中實現
|
(4)設置好棧
|
在跳轉之前,還要清除BSS段(初始值0,無初始值的全局變量,靜態變量放在BSS段。
|
|
第二階段從lib_arm/borad.c中的start_armboot函數開始,程序的流程如下 :
board_init 函數設置MPLL,改變系統時鐘,它是開發板相關函數。board\samsung\smdk2410/smdk2410.c中實現。串口的初始化函數主 要是serial_init,它設置UART控制器,是CPU相關的函數,在cpu/arm920t/s3c24x0/serial.c中實現。
|
(3) 爲內核設置啓動參數
在start_armboot()函數的最後,調用main_loop()函數,進行一個無限循環,該函數在common/main.c文件中定義。
|
|
|
|
|
|
image是bootm_headers結構體的指針,可以在inlcude/image.h文件中看到這個結構體的定義如下:
|
|
要知道哪個地址是啓動內核,哪個地址啓動文件系統,要分析common/cmd_bootm.c中的函數 do_bootm,因爲引導kernel就是bootm這條命令的工作,do_bootm是命令bootm的執行函數現在我們來分析一下 common/cmd_bootm.c中的函數do_bootm,這是bootm命令的處理函數.do_bootm()函數中的很多功能都是分成了函數的 形式,而在以前的版本中沒有這麼有結構層次,這裏我們也只是分析對引導Linux內核有作用的部分,因爲這是一個在common文件夾下的文件,也就意味 着,在引導別的操作系統時也會用到這個函數,而不單單是Linux操作系統.
|
|
uboot源代碼的tools/目錄下有mkimage工具,這個工具可以用來製作不壓縮或者壓縮的多種可啓動映象文件。
mkimage在製作映象文件的時候,是在原來的可執行映象文件的前面加上一個0x40字節的頭,記錄參數所指定的信息,這樣uboot才能識別這個映象 是針對哪個CPU體系結構的,哪個OS的,哪種類型,加載內存中的哪個位置, 入口點在內存的那個位置以及映象名是什麼?到這裏整個U-Boot是如何啓動Linux內核的,基本上也就清楚了,特別是如何向Linux內核傳送的參 數。
|