開機啓動流程分析

本節索引


  在對系統啓動流程進行分析的時候,我想你一定是對系統有了一定的瞭解。系統的啓動目前來講大都爲串行接力的方式來啓動。而所謂的並行方式的啓動方式也是某一個階段的並行。所以我按照系統啓動的順序來把文章連綴起來。

    *  BIOS階段

    *  BootLoader階段

    *  內核階段

    *  用戶層階段

wKioL1nCF_bT9vfTAADFVGrEFD8663.png


BIOS階段


加載BIOS

  當按下開機鍵後,系統會自動自動加載BIOS,加載的詳細過程不再詳述,感興趣的讀者可學習微機原理和或對彙編代碼分析

BIOS從CMOS芯片中讀取硬件配置信息

  開機所需要的BIOS設置和用戶自定義的設置都保存在CMOS芯片中。

POST自檢

  POSTpower on system  test

  BIOS的代碼中包含有診斷功能,用以保證重要硬件被正確初始化,比如內存,CPU,以及一些主板上的各種芯片組。如果硬件損壞,用戶可通過主板的debug顯示或者蜂鳴器的聲音來診斷哪些硬件有故障。

加載Bootloader

  POST自檢無誤後,BIOS會執行一個 INT 13的中斷例程來進入加載Bootloader階段。

  INT13 中斷會從第一啓動項的0磁道1扇區讀取BootLoader,把系統啓動的任務移交給BootLoader

Bootloader階段


Bootloader具體到Linux系統就是grub了。早期使用的LILO以不再使用。

BootLoader的主要作用就是識別和加載操作系統的內核文件,並移交至內存中運行,進而啓動操作系統。

磁盤的第一塊扇區被稱爲主引導記錄(MBR—Master boot Record ),該扇區的446字節存儲grub第一階段的代碼。把一個龐大的操作系統內核交給446個字節來引導顯然是不現實的,所以可以簡單理解爲第一階段的grub的任務就是爲了加載第二階段的grub

第二階段的grub把對資源的控制權轉交給內核鏡像。

BootLoader主要功能

  1. 提供菜單功能讓用戶選擇操作系統。

  2. 加載內核文件 。

  3. 移交給其他的BootLoader(該項有些bootloader不支持,比如Windowsloader)。

  4. 命令行編輯 當系統BootLoader 加載內核出現故障,用戶可在命令行模式下修改啓動參數。

 

grub爲例分析BootLoader階段多做的那些事:

  1.  BIOS 進行POST自檢並無誤後,執行INT 13中斷,讀取對應MBR中前446字節的grub stag1代碼並執行。

  2. 加載boot分區文件系統驅動。Grubstag1階段存儲了grub的預啓動信息和grub stag1_5階段代碼地址信息,grub stag1_5 階段的代碼位於磁盤的主引導記錄之後的27個扇區中(修復grub時的數據,非標準,該段空間主要存儲掛載/boot分區文件系統所需要的驅動程序。一般在系統的/boot/grub目錄下會有stag1_5階段的備份文件。

  3.  掛載/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也稱爲虛擬文件系統,該文件是在系統安裝的最後階段生成的,只用來加載根文件系統的驅動程序,在內核無法驅動根文件系統的時候就要加載虛擬文件系統,然後在根文件系統下找到對應的驅動模塊後在進行根切換。 

系統啓動內核階段的步驟

  1.  加載內核至內存後解壓運行,嘗試掛載根文件系統,如果掛載成功,動態加載個驅動模塊,對周圍硬件設備進行探測並進行初始化。

  2.  如果無法掛載根文件系統,加載initrd虛擬文件系統,然後掛載真正的根文件系統,並切換根,再執行第一步。

至此,Linux內核已經建立起來了。

用戶層階段


  內核被加載成功之後,這個系統已經正常運行,這也是最初的Linux,但是作爲一個用戶是無法直接使用內核的。所以就要初始化啓動相關的進程或者服務來供用戶來使用。

  管理進程的工具多種,以centOS爲例,有sysVinitsystemd兩種。本文主要分析sysVinit的啓動方式。

Systemd是由sysVint進化而來,因此更好的掌握了sysVinit啓動方式有助於理解systemd的啓動方式

執行init程序

  內核在引導完成之後會執行系統的第一個進程init。這時也就正式進入了sysVinit的引導環境。Init之後的所有進程都是由init派生出來,它的PID永遠爲1

init進程加載inittab配置文件

  init進程依據inittab文件來設定運行級別,不同的運行級別可以定義一組不同服務的啓動順序。CentOS56版本默認有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種運行級別。

執行rc.sysinit

  init在得到運行級別之後並不會立即執行該運行級別的一組服務程序,而執行的第一個程序是/etc/rc.d/rc.sysinit腳本程序。該程序的在centos5inittab文件中有如下一行:

si:sysinit:/etc/rc.d/rc.sysinit

這個腳本所做的工作有很多,包括主機名,文件系統,swapSELinuxudev,內核參數,系統時鐘,RaidLVM等服務的開啓。爲後續服務啓動準備基礎環境。

加載rc$runlevel.d下的服務

  在rc.sysinit腳本初始化完成之後,會加載默認啓動級別下的一組服務。這個時候可以查看對應rc$runlevel.d下的文件,有大量以KS開頭的腳本文件(軟連接),跟蹤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目錄下,這時需要修改服務腳本的格式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章