Linux系統啓動過程分析

通過對Linux系統有了必定了解和熟悉後,想對其更深層次的東西作進一步探究。這當中就包括系統的啓動流程、文件系統的組成結構、基於動態庫和靜態庫的程序在執行時的異同、協議棧的架構和原理、驅動程序的機制等等。html

       本人在綜合了現有網上你們智慧的基礎上,結合對2.6.32的內核代碼的研讀,基於CentOS 6.0系統對Linux的啓動流程作了些分析。因爲才疏學淺,知識所限,有些地方分析不妥之處還請各位高手不吝賜教。linux

        OK,咱們言歸正傳。對於一臺安裝了Linux系統的主機來講,當用戶按下開機按鈕時,一共要經歷如下幾個過程,如圖:shell


        其中,每一個過程都執行了本身該作的初始化部分的事情,有些過程又可分爲好幾個子過程。接下來,咱們就對每一個階段作一個詳細分析和講解。小程序


  • BIOS自檢網絡


        稍有計算機基礎的人都應該聽過BIOS(Basic Input / Output System),又稱基本輸入輸出系統,能夠視爲是一個永久地記錄在ROM中的一個軟件,是操做系統輸入輸出管理系統的一部分。早期的BIOS芯片確實是"只讀"的,裏面的內容是用一種燒錄器寫入的,一旦寫入就不能更改,除非更換芯片。如今的主機板都使用一種叫Flash EPROM的芯片來存儲系統BIOS,裏面的內容可經過使用主板廠商提供的擦寫程序擦除後從新寫入,這樣就給用戶升級BIOS提供了極大的方便。架構

        BIOS的功能由兩部分組成,分別是POST碼和Runtime服務。POST階段完成後它將從存儲器中被清除,而Runtime服務會被一直保留,用於目標操做系統的啓動。BIOS兩個階段所作的詳細工做以下:ide

         步驟1:上電自檢POST(Power-on self test),主要負責檢測系統外圍關鍵設備(如:CPU、內存、顯卡、I/O、鍵盤鼠標等)是否正常。例如,最多見的是內存鬆動的狀況,BIOS自檢階段會報錯,系統就沒法啓動起來;oop

         步驟2:步驟1成功後,便會執行一段小程序用來枚舉本地設備並對其初始化。這一步主要是根據咱們在BIOS中設置的系統啓動順序來搜索用於啓動系統的驅動器,如硬盤、光盤、U盤、軟盤和網絡等。咱們以硬盤啓動爲例,BIOS此時去讀取硬盤驅動器的第一個扇區(MBR,512字節),而後執行裏面的代碼。實際上這裏BIOS並不關心啓動設備第一個扇區中是什麼內容,它只是負責讀取該扇區內容、並執行。測試

至此,BIOS的任務就完成了,此後將系統啓動的控制權移交到MBR部分的代碼。字體

        PS: 在我的電腦中,Linux的啓動是從0xFFFF0地址開始的。


  • 系統引導


      咱們首先來了解一下MBR,它是Master Boot Record的縮寫。硬盤的0柱面、0磁頭、1扇區稱爲主引導扇區。它由三個部分組成,主引導程序(Bootloader)、 硬盤分區表DPT(Disk Partition table)和硬盤有效標誌(55AA),其結構圖以下所示:


        磁盤分區表包含如下三部分:

        1)、Partition ID  (5:延申  82:Swap   83:Linux   8e:LVM     fd:RAID)

        2)、Partition起始磁柱

        3)、Partition的磁柱數量

       一般狀況下,諸如lilo、grub這些常見的引導程序都直接安裝在MBR中。咱們以grub爲例來分析這個引導過程。

       grub引導也分爲兩個階段stage1階段和stage2階段(有些較新的grub又定義了stage1.5階段)。

        1)、stage1:stage1是直接被寫入到MBR中去的,這樣機器一啓動檢測完硬件後,就將控制權交給了GRUB的代碼。也就是上圖所看到的前446個字節空間中存放的是stage1的代碼。BIOS將stage1載入內存中0x7c00處並跳轉執行。stage1(/stage1/start.S)的任務很是單純,僅僅是將硬盤0頭0道2扇區讀入內存。而0頭0道2扇區內容是源代碼中的/stage2/start.S,編譯後512字節,它是stage2或者stage1_5的入口。而此時,stage1是沒有識別文件系統的能力的。若是感受腦子有些暈了,那麼下面的過程就直接跳過,去看stage2吧!

        【外傳】定位硬盤的0頭0道2扇區的過程:

         BIOS將stage1載入內存0x7c00處並執行,而後調用BIOS INIT13中斷,將硬盤0頭0道2扇區內容載入內存0x7000處,而後調用copy_buffer將其轉移到內存0x8000處。在定位0頭0道2扇區時一般有兩種尋址方式:LBA和CHS。若是你是刨根問底兒型的愛好者,那麼此時去找谷哥打聽打聽這兩種方式的前因後果吧。

         2)、stage2:嚴格來講這裏還應該再區分個stage1.5的,就一併把stage1.5放在這裏一塊兒介紹了,省得你們看得內心亂哄哄的。好的,咱們繼續說0頭0到2扇區的/stage2/start.S文件,當它的內容被讀入到內存以後,它的主要做用就是負責將stage2或stage1.5從硬盤讀到內存中。若是是stage2,它將被載入到0x820處;若是是stage1.5,它將被載入到0x2200處。這裏的stage2或者stage1_5不是/boot分區/boot/grub目錄下的文件,由於這個時候grub尚未能力識別任何文件系統

        ?  若是start.S加載stage1.5:stage1.5它存放在硬盤0頭0道3扇區向後的位置,stage1_5做爲stage1和stage2中間的橋樑,stage1_5有識別文件系統的能力,此後grub纔有能力去訪問/boot分區/boot/grub目錄下的 stage2文件,將stage2載入內存並執行。

        ?  若是start.S加載stage2:一樣,這個stage2也不是/boot分區/boot/grub目錄下的stage2,這個時候start.S讀取的是存放在/boot分區Boot Sector的stage2。這種狀況下就有一個限制:由於start.S經過BIOS中斷方式直接對硬盤尋址(而非經過訪問具體的文件系統),其尋址範圍有限,限制在8GB之內。所以這種狀況須要將/boot分區分在硬盤8GB尋址空間以前。

        假如是情形2,咱們將/boot/grub目錄下的內容清空,依然能成功啓動grub;假如是情形1,將/boot/grub目錄下stage2刪除後,則系統啓動過程當中grub會啓動失敗。


  • 啓動內核


     當stage2被載入內存執行時,它首先會去解析grub的配置文件/boot/grub/grub.conf,而後加載內核鏡像到內存中,並將控制權轉交給內核。而內核會當即初始化系統中各設備並作相關的配置工做,其中包括CPU、I/O、存儲設備等。

關於Linux的設備驅動程序的加載,有一部分驅動程序直接被編譯進內核鏡像中,另外一部分驅動程序則是以模塊的形式放在initrd(ramdisk)中。

      Linux內核須要適應多種不一樣的硬件架構,可是將全部的硬件驅動編入內核又是不實際的,並且內核也不可能每新出一種硬件結構,就將該硬件的設備驅動寫入內核。實際上Linux的內核鏡像僅是包含了基本的硬件驅動,在系統安裝過程當中會檢測系統硬件信息,根據安裝信息和系統硬件信息將一部分設備驅動寫入 initrd 。這樣在之後啓動系統時,一部分設備驅動就放在initrd中來加載。這裏有必要給你們再多介紹一下initrd這個東東:

       initrd 的英文含義是 bootloader initialized RAM disk,就是由 boot loader 初始化的內存盤。在 linu2.6內核啓動前,boot loader 會將存儲介質中的 initrd 文件加載到內存,內核啓動時會在訪問真正的根文件系統前先訪問該內存中的 initrd 文件系統。在 boot loader 配置了 initrd 的狀況下,內核啓動被分紅了兩個階段,第一階段先執行 initrd 文件系統中的init,完成加載驅動模塊等任務,第二階段纔會執行真正的根文件系統中的 /sbin/init 進程。

      另一個概念:initramfs

       initramfs 是在 kernel 2.5中引入的技術,實際上它的含義就是:在內核鏡像中附加一個cpio包,這個cpio包中包含了一個小型的文件系統,當內核啓動時,內核將這個 cpio包解開,而且將其中包含的文件系統釋放到rootfs中,內核中的一部分初始化代碼會放到這個文件系統中,做爲用戶層進程來執行。這樣帶來的明顯的好處是精簡了內核的初始化代碼,並且使得內核的初始化過程更容易定製。

疑惑的是:個人內核是2.6.32-71.el6.i686版本,但在個人/boot分區下面卻存在的是/boot/initramfs-2.6.32-71.el6.i686.img類型的文件,沒搞明白,還望高人解惑。我只知道在2.6內核中支持兩種格式的initrd,一種是2.4內核的文件系統鏡像p_w_picpath-initrd,一種是cpio格式。接下來咱們就來探究一下initramfs-2.6.32-71.el6.i686.img裏到底放了那些東西。

    在tmp文件夾中解壓initrd.img裏的內容:


若是initrd.img文件的格式顯示爲「initrd.img:ISO 9660 CD-ROM filesystem data」,則可直接輸入命令「mount -o loop initrd.img /mnt/test」進行掛載。

         經過上的分析和咱們的驗證,咱們確實獲得了這樣的結論:

         grub的stage2將initrd加載到內存裏,讓後將其中的內容釋放到內容中,內核便去執行initrd中的init腳本,這時內核將控制權交給了init文件處理。咱們簡單瀏覽一下init腳本的內容,發現它也主要是加載各類存儲介質相關的設備驅動程序。當所需的驅動程序加載完後,會建立一個根設備,而後將根文件系統rootfs以只讀的方式掛載。這一步結束後,釋放未使用的內存,轉換到真正的根文件系統上面去,同時運行/sbin/init程序,執行系統的1號進程。此後系統的控制權就全權交給/sbin/init進程了。

l  初始化系統

通過千辛萬苦的跋涉,咱們終於接近黎明的曙光了。接下來就是最後一步了:初始化系統。/sbin/init進程是系統其餘全部進程的父進程,當它接管了系統的控制權先以後,它首先會去讀取/etc/inittab文件來執行相應的腳本進行系統初始化,如設置鍵盤、字體,裝載模塊,設置網絡等。主要包括如下工做:

1)、執行系統初始化腳本(/etc/rc.d/rc.sysinit),對系統進行基本的配置,以讀寫方式掛載根文件系統及其它文件系統,到此係統算是基本運行起來了,後面須要進行運行級別的肯定及相應服務的啓動。rc.sysinit所作的事情(不一樣的Linux發行版,該文件可能有些差別)以下:

(1)獲取網絡環境與主機類型。首先會讀取網絡環境設置文件"/etc/sysconfig/network",獲取主機名稱與默認網關等網絡環境。

(2)測試與載入內存設備/proc及usb設備/sys。除了/proc外,系統會主動檢測是否有usb設備,並主動加載usb驅動,嘗試載入usb文件系統。

(3)決定是否啓動SELinux。

(4)接口設備的檢測與即插即用(pnp)參數的測試。

(5)用戶自定義模塊的加載。用戶能夠再"/etc/sysconfig/modules/*.modules"加入自定義的模塊,此時會加載到系統中。

(6)加載核心的相關設置。按"/etc/sysctl.conf"這個文件的設置值配置功能。

(7)設置系統時間(clock)。

(8)設置終端的控制檯的字形。

(9)設置raid及LVM等硬盤功能。

(10)以方式查看檢驗磁盤文件系統。

(11)進行磁盤配額quota的轉換。

(12)從新以讀取模式載入系統磁盤。

(13)啓動quota功能。

(14)啓動系統隨機數設備(產生隨機數功能)。

(15)清楚啓動過程當中的臨時文件。

(16)將啓動信息加載到"/var/log/dmesg"文件中。

 當/etc/rc.d/rc.sysinit執行完後,系統就能夠順利工做了,只是還須要啓動系統所須要的各類服務,這樣主機才能夠提供相關的網絡和主機功能,所以便會執行下面的腳本。

2)、執行/etc/rc.d/rc腳本。該文件定義了服務啓動的順序是先K後S,而具體的每一個運行級別的服務狀態是放在/etc/rc.d/rc*.d(*=0~6)目錄下,全部的文件均是指向/etc/init.d下相應文件的符號連接。rc.sysinit經過分析/etc/inittab文件來肯定系統的啓動級別,而後纔去執行/etc/rc.d/rc*.d下的文件。

/etc/init.d-> /etc/rc.d/init.d

/etc/rc ->/etc/rc.d/rc

/etc/rc*.d ->/etc/rc.d/rc*.d

/etc/rc.local-> /etc/rc.d/rc.local

/etc/rc.sysinit-> /etc/rc.d/rc.sysinit

也就是說,/etc目錄下的init.d、rc、rc*.d、rc.local和rc.sysinit均是指向/etc/rc.d目錄下相應文件和文件夾的符號連接。咱們以啓動級別3爲例來簡要說明一下。

/etc/rc.d/rc3.d目錄,該目錄下的內容所有都是以 S 或 K 開頭的連接文件,都連接到"/etc/rc.d/init.d"目錄下的各類shell腳本。S表示的是啓動時須要start的服務內容,K表示關機時須要關閉的服務內容。/etc/rc.d/rc*.d中的系統服務會在系統後臺啓動,若是要對某個運行級別中的服務進行更具體的定製,經過chkconfig命令來操做,或者經過setup、ntsys、system-config-services來進行定製。若是咱們須要本身增長啓動的內容,能夠在init.d目錄中增長相關的shell腳本,而後在rc*.d目錄中創建連接文件指向該shell腳本。這些shell腳本的啓動或結束順序是由S或K字母后面的數字決定,數字越小的腳本越先執行。例如,/etc/rc.d/rc3.d /S01sysstat就比/etc/rc.d/rc3.d /S99local先執行。

3)、執行用戶自定義引導程序/etc/rc.d/rc.local。其實當執行/etc/rc.d/rc3.d/S99local時,它就是在執行/etc/rc.d/rc.local。S99local是指向rc.local的符號連接。就是通常來講,自定義的程序不須要執行上面所說的繁瑣的創建shell增長連接文件的步驟,只須要將命令放在rc.local裏面就能夠了,這個shell腳本就是保留給用戶自定義啓動內容的。

4)、完成了系統全部的啓動任務後,linux會啓動終端或X-Window來等待用戶登陸。tty1,tty2,tty3...這表示在運行等級1,2,3,4的時候,都會執行"/sbin/mingetty",並且執行了6個,因此linux會有6個純文本終端,mingetty就是啓動終端的命令。

除了這6個以外還會執行"/etc/X11/prefdm-nodaemon"這個主要啓動X-Window

至此,系統就啓動完畢了。以上分析不到的地方還請各位大蝦不吝指正。

關於Linux的其餘分析內容下次再繼續寫。

最後附上一張很是完整的系統啓動流程圖,適合各個水平階段的讀者。



參考文獻:

http://www.cnblogs.com/scnutiger/archive/2009/09/30/1576795.html

http://www.it.com.cn/f/edu/0411/24/51090.htm

http://bbs.chinaunix.net/thread-2046548-1-1.html

http://space.itpub.net/8111049/viewspace-680043

http://dongdiy.blog.51cto.com/1908223/366909

http://icarusli.iteye.com/blog/625755

http://www.54sa.net/?p=549

http://roclinux.cn/?p=1301

相關文章
相關標籤/搜索