上篇咱們知道,kernel初始化後將啓動init進程,那麼這個進程將幹些什麼呢?除此以外,kernel還須要作些什麼事情呢?(想一想文件系統、根存儲設備是在何時初始化的呢?) linux
先從文件系統初始化提及。之前一直不明白,有了kernel爲什麼還須要一個文件系統?通過反覆琢磨,明白一個道理,kernel加載到內存後,kernel運行起來是沒有問題的,可是若是沒有Root FS,就好像PC上沒有硬盤.....。另外,Linux中不少虛擬文件系統(proc,sys,dev等)都是掛靠在RootFS中的,因此RootFS在Linux中更加關鍵(必要條件簡直就是)。(kernel中的FS是另一個龐大的部分) android
一 根文件系統 ubuntu
1 FHS:File system Hierachy Standard:Linux上文件系統佈局的標準,例如 usr目錄大概是幹嘛的,tmp目錄大概是幹嗎的。有空能夠瞧瞧....其實使用LINUX OS多了,天然就理解了。 架構
2 經常使用的文件夾佈局:其實就是ES上廣泛的文件目錄: electron
二 Post Boot 函數
這裏講的是execve init以前的事情,由於源碼中: 工具
三 init 佈局
init進程很重要,不過android上的init進程的工做流程比較簡單。這裏介紹非Android上的init。通常它讀取的配置文件是/etc/inittab中(ubuntu上彷佛沒有這個文件了,之後得找個FCore的系統看看)。 spa
另外,這裏還有一個叫run level的概念。見圖1. 進程
圖1 run level
Run level說白了就是將系統運行狀態分紅幾個級別,例如shutdown的時候init須要執行一些操做,reboot的時候須要執行一些操做。
這裏關於Init的東西就不介紹了,不少關於linux系統配置的知識都有涉及。(確實比android的init要複雜多了)
四 Initial RAM Disk
LK在早期初始化的過程當中,須要mount一個FS,目前有新舊兩種方法:
old方法就是使用initial ram disk,也叫initrd
new方法就是使用iniramfs
這兩個東西很是常見,我們要好好研究下。
4.1 initrd
這個功能須要配置kernel的編譯選項。
ARM支持將前面的initrd和vmlinux打包到一個image中。實際上只有ARM架構支持。(內核編譯的時候要選擇這一項)。講了這麼多,那麼到底怎麼用呢?
initrd也是一個image。由bootloader啓動的時候,或者bootloader下載到某個地方
bootloader把initrd的地址告訴內核。內核啓動時候把這個image解壓並掛載
另一種辦法,編譯的時候將initrd和kernel放到一個image中,這種方法只有ARM架構支持。使用這種辦法話,建議用initramfs。注意,android中使用的就是一個kernel+initramfs的單一image。也就是第二種辦法
(這裏有不少細節問題,之後咱們分析源碼再來搞懂它)
BL啓動內核的時候,須要給LK傳遞參數,即告訴LK這個initrd在什麼位置...很簡單不是?
KL如何使用這個initrd呢?
KL先根據參數指定的initrd地址,將這個image拷貝到內存中,而後解壓,並掛載爲/
找到這個disk中的linuxrc文件,而後執行裏邊的語句《====這給了咱們定製化本身ES的好計劃
處理完linuxrc後,KL unmount這個initrd,並加載真正的root device(看到沒,這個initrd就是作些初始化的工做,可是你也能夠不umount這個initrd。)這裏的處理稍有差別。若是BL在參數中指明root=/dev/ram0,(代碼中可見到這些語句),那麼KL就不會執行linuxrc,而且也不會umount initrd。也就是這個initrd就是最終的根文件系統了。
那麼如何製做這個Initrd呢?
其實就是一個gzip打包的文件夾....
(這部分代碼在do_mounts.c中的prepare_namespace函數中)
4.2 initramfs
(詳細說明:參考kernel/documentations/filesystems/ramfs-rootfs-initramfs.txt)
kernel默認支持這個initramfs,因此編譯的時候,會整一個default的initramfs放到內核中。initramfs是一個cpio的打包文件。我特地查了下cpio的info。通常用法就是:讀取一個目錄下全部文件的信息及其全部文件的內容(多是直接read數據到一個buffer中),而後把這些信息寫到一個文件中。說白了,可能就是一個序列化的工具。而後LK用一樣的方法就能夠反序列化,恢復原來目錄中的內容了。
前面說,LK編譯的時候默認會有一個簡單的initramfs目錄結構。這個結構由kernel/scripts/gen_initramfs_list.sh腳本生成。這個腳本很簡單:
dir /dev 0755 0 0
nod /dev/console/ 0600 0 0 c 5 1
dir /root 0700 0 0
執行的時候,前面加上mk...就生成一個目錄了,而後用cpio打包,生成iniramfs,最後由LK解包並掛載
(具體內容,參考ramfs-rootfs-initramfs.txt)
如何製做本身的initramfs呢?
搞一個文件夾吧,可仿照PC機器上linux的文件結構。也能夠把busybox放上去。
find testramfs -depth -print | cpio -ov > testramfs.cpio cpio的輸入是文件名,輸出經過>定向到testramfs.cpio。你們能夠試試。
解壓的話,cpio -ivd < testramfs.cpio。這樣就能還原testramfs文件夾中的內容了。
cpio:-o表示output,-v表示打印一些verbose信息,-i表示input,-d表示創建整個文件夾結構。沒有-d的話,會出問題。
不過有了kernel編譯的支持,咱們不用本身調用cpio了,在編譯選項中有一個INITRAMFS_SOURCE,把它指向目標文件夾,編譯的時候天然會生成這個initramfs了。
參考文獻:
這些參考文獻中,最重要的是最後一個,ols2k-9.ps,下載並處理後獲得一個pdf,實際上一篇論文。主要介紹了
Linux啓動的一些問題。
再三解釋一下,爲何須要init ram disk。FS通常安裝在存儲介質上,而讀取這些存儲介質須要驅動。內核啓動的時候若是把這些驅動都加載的話,會很是麻煩,即便你把驅動靜態編譯到內核中,也不是一個完美的解決辦法。因此。先整一個簡單的,基於內存的FS,這樣初始化工做均可以順利進行。最後,等驅動都加載完後,再把實際存儲上的FS掛載上來。這裏要明白一點,沒有一個FS的話,LK是無法正常工做的。
五 U-Boot
全名爲Das U-Boot,是一個使用很是普遍的Bootloader。之後會專門撰文介紹UB。這裏簡單說兩個點:
UB的代碼結構,先從CPU的start.S開始,這裏會根據不一樣的CPU進行初始化,大部分代碼都不須要咱們修改
再是Board的啓動,這個和具體的板子有關。如今更名叫lowlevel_init.S了。
(最難的部分在於各個設備的初始化了,須要結合開發板的datasheet來作)
這裏列出如下參考書:
其中,關於SDRAM.pdf,網址已經移到了:http://www.maxwell.com/products/microelectronics/docs/INTRO_TO_SDRAM.PDF
各位看官能夠下載看看。