轉自:http://blog.csdn.net/weiganyi/article/details/11561859
在我們的周圍,大量的嵌入式設備都是基於Linux系統來構建的,嵌入式Linux與主機Linux相比有着自己的一些特點,本文就嵌入式Linux系統的構成和啟動過程做一些總結。
一、嵌入式Linux系統構成
上圖是一個嵌入式Linux系統的典型結構,划分成了4個區:
1、Bootloader區存放的是Bootloader,它負責嵌入式系統最初的硬件初始化、驅動和內核加載。
2、參數區不是必須的,通常存放了一些系統參數,並且通常這個區是沒有文件系統,參數以原始數據的格式來存放。
3、內核鏡像區存放的Linux內核壓縮鏡像,它被解壓后運行於內存,作為嵌入式設備的Linux操作系統。
4、文件系統區存放經過壓縮的文件系統,它會被Linux內核解壓並掛載,並作為各種應用程序、文件的主要載體。
這4個區都以二進制數據的形式存放於嵌入式設備的Flash芯片上。
二、嵌入式Linux系統啟動過程
嵌入式設備從上電那一刻到應用程序正常運行,其間經歷過一系列漫長的過程,下面對主要的步驟進行闡述:
1、嵌入式設備上電后,CPU開始運行,通常CPU會從某一個固定的物理地址開始運行,這個物理地址一般是Flash芯片的起始物理地址。Flash芯片的最初一段通常存放的是Bootloader,於是CPU就會開始運行Bootloader的代碼。
2、我們知道CPU可以讀寫Flash上的數據,但是不能直接執行Flash上的指令,CPU通常只能執行內存中的指令,那么CPU剛開始運行時怎樣去執行Flash上的指令呢?這里分兩種情況,Flash芯片主要分為兩種,一種是Nor Flash,另一種是Nand Flash,Nor Flash具有可以直接在Flash芯片上執行指令的特點。如果嵌入式設備采用的是Nor Flash,那就比較簡單了,CPU可以直接運行在Nor Flash上的指令。如果采用的是Nand Flash呢,怎么辦?目前主要有兩種方法,一種方法是Flash控制器能夠把Nand Flash的前4k數據搬到4k的內部RAM中,並設置CPU從這個內部RAM的起始地址開始啟動執行。另一種方法是Flash控制器能夠把Nand Flash的前4k數據的地址映射到系統總線的某個地址上,並設定CPU從這個地址開始啟動執行。這兩種方法都是硬件來完成的。
3、Bootloader分為兩個部分,第一部分是匯編代碼且不做壓縮,第二部分是C代碼且有壓縮的。Bootloader開始執行時,第一部分匯編代碼先負責初始化CPU、PLL、DDR、Cache等硬件,讓CPU和內存能夠穩定運行,然后解壓第二部分的Image,並拷貝到到內存執行。第二部分C代碼完成串口、flash、網口等驅動的加載,並構建一個shell環境來接受用戶輸入。注意,在整個Bootloader運行其間CPU的MMU是沒有被初始化的,所有的地址訪問都是采用物理地址直接訪問的。
4、在完成Bootloader初始化后,根據代碼中設定的內核區物理地址,Bootloader會把內核區壓縮后的Linux鏡像拷貝到內存中並解壓。同時准備好內核的啟動參數,如:console=ttyS0,115200 root=31:2 mtdparts=ar7100-nor0:196608(boot),835236(kernel),-(rootfs),這里主要是把Bootloader里設置的MTD分區信息傳遞給內核,還有需要加載的根文件系統。最后跳轉到內核入口開始運行。
5、Linux內核代碼開始執行,會先進行內核各個子系統初始化,並完成對MMU的初始化。MMU是CPU中的一個單元,它跟操作系統一起配合完成從虛擬地址到物理地址的轉換。如果CPU帶有MMU單元,則CPU執行單元發出的內存地址將被MMU截獲,從CPU到MMU的地址稱為虛擬地址,而MMU將這個地址翻譯成另一個地址發到CPU芯片的外部地址引腳上,這個地址稱為物理地址。在這個過程中Linux內核會維護頁表結構,它保存着內核和進程的虛擬地址到物理地址的映射,而MMU則通過Linux內核頁表去完成地址翻譯和保護工作。
6、接下來Linux內核會掛載根文件系統,要掛載的根文件系統是通過內核啟動參數來獲取的。這里有一個問題,根文件系統通常表示為一個Linux文件系統下的某個MTD設備,但在加載根文件系統前Linux還沒有一個文件系統,那它怎樣通過訪問文件系統中的MTD設備來加載根文件系統呢?事實上,根文件系統的安裝分為兩個階段,首先Linux內核會安裝一個特殊的RootFS文件系統,該文件系統僅提供一個作為初始安裝點的空目錄,然后Linux內核再在空目錄上安裝一個真正的根目錄。Linux內核對Flash的訪問都是通過MTD子系統來進行的,它抽象了對於各種Flash設備的訪問,提供統一的接口。
7、Linux內核繼續初始化各種類型的驅動程序,完成之后會啟動第一個應用程序,它的進程ID為1。這個應用程序可以由內核啟動參數傳入,如果沒有則會默認執行/sbin/init。init進程會讀取配置文件/etc/inittab,根據配置文件的內容它會完成兩個工作,執行rcS和啟動Shell。至此,Linux系統已經啟動完成,給用戶提供了一個Shell的交互環境,后續的行為就取決於用戶的輸入或者系統特定應用的加載。