本節索引centos
在對系統啓動流程進行分析的時候,我想你必定是對系統有了必定的瞭解。系統的啓動目前來說大都爲串行接力的方式來啓動。而所謂的並行方式的啓動方式也是某一個階段的並行。因此我按照系統啓動的順序來把文章連綴起來。
app
* BIOS階段
ide
* BootLoader階段
工具
* 內核階段學習
* 用戶層階段
this
BIOS階段
spa
加載BIOS
操作系統
當按下開機鍵後,系統會自動自動加載BIOS,加載的詳細過程再也不詳述,感興趣的讀者可學習微機原理和或對彙編代碼分析命令行
BIOS從CMOS芯片中讀取硬件配置信息debug
開機所須要的BIOS設置和用戶自定義的設置都保存在CMOS芯片中。
POST自檢
POST(power on system test)
BIOS的代碼中包含有診斷功能,用以保證重要硬件被正確初始化,好比內存,CPU,以及一些主板上的各類芯片組。若是硬件損壞,用戶可經過主板的debug顯示或者蜂鳴器的聲音來診斷哪些硬件有故障。
加載Bootloader
當POST自檢無誤後,BIOS會執行一個 INT 13的中斷例程來進入加載Bootloader階段。
INT13 中斷會從第一啓動項的0磁道1扇區讀取BootLoader,把系統啓動的任務移交給BootLoader。
Bootloader具體到Linux系統就是grub了。早期使用的LILO以再也不使用。
BootLoader的主要做用就是識別和加載操做系統的內核文件,並移交至內存中運行,進而啓動操做系統。
磁盤的第一塊扇區被稱爲主引導記錄(MBR—Master boot Record ),該扇區的前446字節存儲grub第一階段的代碼。把一個龐大的操做系統內核交給446個字節來引導顯然是不現實的,因此能夠簡單理解爲第一階段的grub的任務就是爲了加載第二階段的grub。
第二階段的grub把對資源的控制權轉交給內核鏡像。
BootLoader主要功能
提供菜單功能,讓用戶選擇操做系統。
加載內核文件 。
移交給其餘的BootLoader(該項有些bootloader不支持,好比Windows的loader)。
命令行編輯 當系統BootLoader 加載內核出現故障,用戶可在命令行模式下修改啓動參數。
以grub爲例分析BootLoader階段多作的那些事:
BIOS 進行POST自檢並沒有誤後,執行INT 13中斷,讀取對應MBR中前446字節的grub stag1代碼並執行。
加載boot分區文件系統驅動。Grubstag1階段存儲了grub的預啓動信息和grub stag1_5階段代碼地址信息,grub stag1_5 階段的代碼位於磁盤的主引導記錄以後的27個扇區中(修復grub時的數據,非標準),該段空間主要存儲掛載/boot分區文件系統所須要的驅動程序。通常在系統的/boot/grub目錄下會有stag1_5階段的備份文件。
掛載/boot目錄,進入grubstag2階段,讀取grub.conf配置文件,根據配置信息,啓動或者由用戶選擇內核啓動或者移交給其餘其餘BootLoader,並提供命令行功能用於手動加載內核。把全部的控制權移交給內核。
注:此階段的不含有rootfs的概念,尋找內核文件都是以boot爲根 |
Grub.conf文件以下:
default=0 timeout=5 title CentOS 6 (2.6.32-696.el6.x86_64) root (hd0,0) kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos6-lv_root #以boot爲根的內核路徑 initrd /initramfs-2.6.32-696.el6.x86_64.img |
Linux內核的設計風格是單內核,單內核設計要支持市面大部分硬件設備的前提下就要把不少的驅動程序編譯在內核文件中,會使得內核文件體積異常龐大。可是Linux系統內核在設計上吸取了微內核的一些優勢,把大部分的驅動程序,文件系統驅動程序還有一些外圍的驅動程序封裝成一個個單獨的模塊,在使用過程當中只需動態的加載所須要的模塊就行了。
內核模塊文件在/lib/modules/`uname -r` 這個目錄下,這時候問題就來了,若是內核文件要加載模塊驅動,就要先從根分區查找模塊位置,而要找到根分區,就要有根文件系統的驅動模塊,而模塊又在根文件系統下又回到了先有雞先有蛋的問題。
爲了解決這個問題,一種方法是能夠把根文件系統的文件系統驅動程序直接編譯在內核文件中,可是市場上的Linux發行版本要支持不少文件系統類型,把全部的文件系統驅動程序編譯進內核又會讓內核文件體積變得很是龐大。爲了解決這一矛盾,就有了initrd這個文件,固然這個是最先期的,在centos6版本稱爲initramfs也稱爲虛擬文件系統,該文件是在系統安裝的最後階段生成的,只用來加載根文件系統的驅動程序,在內核沒法驅動根文件系統的時候就要加載虛擬文件系統,而後在根文件系統下找到對應的驅動模塊後在進行根切換。
系統啓動內核階段的步驟
加載內核至內存後解壓運行,嘗試掛載根文件系統,若是掛載成功,動態加載個驅動模塊,對周圍硬件設備進行探測並進行初始化。
若是沒法掛載根文件系統,加載initrd虛擬文件系統,而後掛載真正的根文件系統,並切換根,再執行第一步。
至此,Linux內核已經創建起來了。
內核被加載成功以後,這個系統已經正常運行,這也是最初的Linux,可是做爲一個用戶是沒法直接使用內核的。因此就要初始化啓動相關的進程或者服務來供用戶來使用。
管理進程的工具多種,以centOS爲例,有sysVinit和systemd兩種。本文主要分析sysVinit的啓動方式。
Systemd是由sysVint進化而來,所以更好的掌握了sysVinit啓動方式有助於理解systemd的啓動方式
內核在引導完成以後會執行系統的第一個進程init。這時也就正式進入了sysVinit的引導環境。Init以後的全部進程都是由init派生出來,它的PID永遠爲1
init進程依據inittab文件來設定運行級別,不一樣的運行級別能夠定義一組不一樣服務的啓動順序。CentOS5和6版本默認有7個運行級別。詳情以下:
# Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:3:initdefault: #默認的運行級別 |
生產環境中默認使用3級別,運行級別的只是用於定義一組不一樣的啓動順序,用戶徹底能夠自定義,也能夠自定義這7種運行級別。
init在獲得運行級別以後並不會當即執行該運行級別的一組服務程序,而執行的第一個程序是/etc/rc.d/rc.sysinit腳本程序。該程序的在centos5的inittab文件中有以下一行:
si:sysinit:/etc/rc.d/rc.sysinit |
這個腳本所作的工做有不少,包括主機名,文件系統,swap,SELinux,udev,內核參數,系統時鐘,Raid和LVM等服務的開啓。爲後續服務啓動準備基礎環境。
在rc.sysinit腳本初始化完成以後,會加載默認啓動級別下的一組服務。這個時候能夠查看對應rc$runlevel.d下的文件,有大量以K和S開頭的腳本文件(軟鏈接),跟蹤rc.d目錄下的rc腳本能夠發現這樣兩個循環結構,仔細研究以後符合如下邏輯。
for i in /etc/rc$runlevel.d/K* ; do $i stop #依次關閉以K開頭的服務 done for i in /etc/rc$runlevel.d/S* ; do $i start #依次開啓以S開頭的服務,即開機自啓動 Done |
經過這個結構咱們很容易發現服務的啓動時順序執行的,前一個服務腳本沒有執行成功的後續腳本就要等待。
經過對rc腳本的分析能夠得出對應runlevel下以S開頭的腳本是開機啓動的,咱們能夠經過chkconfig命令調整程序是否開啓啓動或者指定模式下的開機自啓動。
跟蹤對應模式下的腳本軟鏈接能夠,找到服務腳本大多放置在/etc/init.d目錄之下。可使用service 命令來管理這些腳本。
在2345運行級別所對應的rc$runlevel.d目錄中都有一個$99local的腳本軟鏈接,該腳本通常是最後一個執行的腳本,該腳本位置在/etc/rc.d/local。因此用戶能夠把開機後須要執行的操做寫在該腳本中。
固然也能夠把開機須要的操做定義爲服務放置於/etc/init.d目錄下,這時須要修改服務腳本的格式。