ARM Linux啟動流程大致為:bootloader ---->kernel---->root filesystem。bootloader 是一上電就拿到cpu 的控制權的,而bootloader實現了硬體的初始化。bootloader儼然就成了Power on 之後”第一個吃螃蟹”的代碼。
談到這就得想到硬體機制是如何滿足這個功能的了。CPU內部一般都整合小容量的SRAM (又叫stapping stone,墊腳石),當系統一上電,NAND controler 就自動地將Nand flash 裡的前內容複寫到墊腳石裡,而PC 指標一上電就指向墊腳石的起始地址0x00000000。這樣這一部分的代碼就可以得到執行。所以,這一部分的代碼就是 bootloader 部分,那一上電bootloader 不就可以得到運行了麼。事實確實如此,在嵌入式Linux的軟體系統中,nandflash前面一部分代碼往往就是bootloader ,然後就是kernel, 再接著就是根檔案系統。
說了這麼多,好像都沒說到啟動流程啊,別著急,咱慢慢談,所謂磨刀不誤砍柴工嘛。
要說啟動流程,如果只是簡單的介紹從哪到哪,誰幹了啥啥,得到的結果可能只是只知其然不知其所以然。個人覺得隨著CPU的PC指標走,循著代碼的足跡才能把整個流程理清楚,當找到了代碼的執行過程,再分析一下代碼,自然知道了哪個部分完成了哪些事,更重要的是為代碼的移植打下了堅實的基礎。自然這個過程是痛苦和枯燥的,甚至是看代碼看了幾天也沒弄明白,不過這也是一種鍛煉。 bootloder
前面說了,bootloader一上電就拿到了cpu 的使用權,它當然得幹一些初始化的工作啊,比如關閉看門狗、設定cpu 的運行模式、設定堆棧等等比較急迫的事情。當然還要對主板的一些其他硬體進行簡單的初始化,比如外部DDR記憶體、網卡、顯示屏、nand flash等等的初始化工作,最後還要負責把Linux核心載入到記憶體中。正所謂責任和權力是並存的嘛,你得到了權益,當然就得付出。當bootloader 完成它的使命之後就會把cpu 的使用權交給下一部分代碼:kernel 。 kernel
在討論kernel 是如何啟動之前,先瞭解kernel 的組成結構以及是如何得來的。下面這張圖是核心編譯即將結束時顯示的資訊:
下面的這張圖說明了上面的編譯過程,
可以看到,當核心源檔案編譯連結成 vmlinux 檔案以後還進行了幾個模組的編譯和連結。其中(1)vmlinux 是ELF格式的object檔案,這種檔案只是各個原始碼經過串連以後的得到的檔案,並不能在arm平台上運行。(2)經過objcopy這個工具轉換以後,得到了二進位格式檔案Image,Image檔案相比於vmlinux 檔案,除了格式不同以外,還被去除了許多注釋和調試的資訊。(3)Image檔案經過壓縮以後得到了piggy.gz ,這個檔案僅僅是Image的壓縮版,並無其他不同。(4)接著編譯產生另外幾個模組檔案misc.o、big_endian.o、head.o、head-xscale.o,這幾個檔案組成一個叫 bootstrap loader 的組件,又叫引導程式。編譯產生 piggy.o 檔案。(5)最後piggy.o檔案和bootstrap loader 組成一個bootable kernel Image 檔案(可開機檔案)。
可以看到最後得到的可執行檔就是上圖最右邊那個,這也是我們最後燒寫到開發板的鏡像。其中piggy.o 就是核心鏡像,而剩下的幾個檔案就組成了引導程式。
下面開始討論CPU的流轉過程,還是用一個圖來展示:
從上圖可以看出,系統一上電就開始執行bootloader。當bootloader 執行完以後,把控制權交給了引導程式的head.o 檔案裡的start 標號處,當引導程式完成引導工作以後就將控制權轉給真正的核心的head.o 檔案裡的start 標號處。這裡就是核心的進入點,最後核心的head.o將控制交給main.o 的start_kernel 函數。這樣,通過查看相應的代碼就可以知道這些代碼到底完成了哪些工作。在這裡我們可以找到相應的代碼,分析一下,看它們到底完成哪些事。下面是我的分析結果: 引導程式:
head.o從bootloader接過控制權,並完成如下任務: 使能 I/D caches ,關閉中斷 , 建立C運行環境(即設定堆棧)由 head.o 和head-xscal.o 完成 解壓縮並重定位代碼 ,由misc.o 完成 其他硬體相關的設定,如big.endian.o 為cpu設定大端模式
核心進入點:從引導程式接過控制權,完成如下任務 檢查有效cpu 和cpu的資訊 建立初始化頁表入口 使能MMU 檢測錯誤並報告 跳轉到核心本身 main.c 檔案裡的 start_kernel()函數 核心啟動:
從 kernel 的head.o接過控制權,開始核心的啟動,在這裡完成核心的初始化,如核心各個子系統的初始化。 root filesystem
到此止,kernel完成了系統硬體探測及硬體驅動的初始化,核心空間的相關工作已經完成,開始向使用者空間轉移,核心空間通過一個間接的initrd(一個虛擬檔案系統)向使用者空間過度,然後開始掛載跟檔案系統了,其過程:initrd ----> /sbin/init ----> /etc/inittab。
initrd是一個虛擬檔案系統,裡面有lib、bin、sbin、usr、proc、sys、var、dev、boot等一些目錄,其目錄有點像真的/,所以我們稱之為虛擬根檔案系統,作用就是將kernel和真的根檔案系統建立關聯關係,讓kernel去initrd中載入根檔案系統所需要的驅動程式,並以讀寫的方式掛載根檔案系統,並讓執行使用者當中第一個進程init。
init執行完畢以後會啟動系統內的/etc/inittab檔案,來完成系統系統的初始化工作。