1. 程式人生 > 實用技巧 >linux系統啟動流程詳解

linux系統啟動流程詳解

一.linux啟動大概流程如下:

POST --> Boot Sequence(BIOS) --> Boot Loader (MBR) --> Kernel(ramdisk) --> rootfs --> switchroot --> /sbin/init -->(/etc/inittab, /etc/init/*.conf) --> 設定預設執行級別 --> 系統初始化指令碼 --> 關閉或啟動對應級別下的服務 --> 啟動終端,流程圖如下:

wKiom1aE17KTQ8xsAANWq_R4oNA991.png

二.詳細剖析過程

1.

POST開機自檢:電腦主機開啟電源的時候,隨後會聽到滴的一聲,系統啟動開始了開機自檢
(POST-poweronselftest)自檢開始),這個過程中主要是檢測計算機硬體裝置比如:
CPU,記憶體,主機板,顯示卡,CMOS等裝置是否有故障存在,如果有硬體故障的話將按兩種情況
理:對於嚴重故障(致命性故障)則停機,此時由於各種初始化操作還沒完成,不能給出任
何提示或訊號;對於非嚴重故障則給出提示或聲音報警訊號,等待使用者處理),如果沒有
故障,POST完整自己的接力任務,將尾部工作交接給BIOS處理。

2.

BIOS:計算機加電自檢完成後第一個讀取的地方就是就是BIOS(基礎輸入輸出系統),BIOS裡面記錄了主機板的晶片集與相關設定,如CPU與介面裝置的通訊頻率、啟動裝置的搜尋順序、硬碟的大小與型別、系統時間、外部匯流排、各種介面裝置的I/O地址、已經與CPU通訊的IRQ中斷資訊,所以,啟動如果要順利啟動,首先要讀取BIOS設定。BIOS此時去讀取硬碟驅動器的第一個扇區(MBR,512位元組),然後執行裡面的程式碼。

實際上這裡BIOS並不關心啟動裝置第一個扇區中是什麼內容,它只是負責讀取該扇區內容、並執行。此後將系統啟動的控制權移交到MBR部分的程式碼,在個人電腦中, Linux的啟動是從0xFFFF0地址開始的。


3.

Boot Loader 系統引導,我們首先來了解一下MBR,它是Master Boot Record的縮寫。硬碟的0柱面、0磁頭、1扇區稱為主引導扇區。它由三個部分組成,主載入程式(Bootloader)硬碟分割槽表DPT(Disk Partition table)和硬碟有效標誌(55AA),其結構圖如下所示:

wKioL1aE4G-SNgU8AABOPhrk2l4392.png

磁碟分割槽表包含以下三部分:

1). Partition ID (5:延申 82:Swap 83:Linux 8e:LVM fd:RAID)
2). Partition起始磁柱
3). Partition的磁柱數量


4.主引導裝置載入Bootloader

通常情況下,諸如lilo、grub這些常見的載入程式都直接安裝在MBR中。我們以grub為例來分析這個引導過程。grub引導也分為兩個階段stage1階段,stage1.5階段和stage2階段;

wKiom1aE4b2RZo8mAADt0NaEP4A521.png由此可見grub目錄下包含了這三個階段的檔案,他們各自的作用是什麼呢?

stage1:stage1是直接被寫入到MBR中去的,這樣機器一啟動檢測完硬體後,就將控制權交給了GRUB的程式碼。也就是上上圖所看到的前446個位元組空間中存放的是stage1的程式碼。BIOS將stage1載入記憶體中0x7c00處並跳轉執行。stage1(/stage1/start.S)的任務非常單純,僅僅是將硬碟0頭0道2扇區讀入記憶體。此時,stage1是沒有識別檔案系統的能力的。

stage1主要負責BIOS和GRUB之間的交接,載入存放於各個分割槽中的開機檔案。例如Linux下/boot/grub/..下面的一些檔案。這部分才是真正放在MBR中的bootloader。

stage1檔案的大小正好是512位元組,事實上stage1檔案其實就是MBR中bootloader的備份,而之所以是bootloader而不是MBR, 是因為這個檔案的前446位元組才是和MBR是一樣的。


stage1.5:GRUB開始沒有OS,也沒有檔案系統的概念。那麼GRUB是從何時開始有檔案系統的功能的呢。這就是stage1.5乾的事情,stage1.5過後,GRUB就能識別檔案系統了,就能在磁碟上識別載入檔案了怎麼做到的?start.S載入的磁碟上的那些扇區的內容,就是檔案系統的程式碼,(即start.S的彙編程式碼,有興趣的筒子可以去了解一下),將其(大概14個扇區)載入到記憶體,就具備了操作啟動裝置上面檔案的功能了,此時檔案系統支撐程式碼到記憶體之後,我們在也不需要直接呼叫INT 13載入扇區內容,我們有了檔案系統,我們可以直接操作檔案了。那麼/boot/grub/stage2這樣的比較大的檔案可以直接操作了。此後grub才有能力去訪問/boot分割槽/boot/grub目錄下的 stage2檔案,將stage2載入記憶體並執行。

Grub的做法是把stage1.5安裝在硬碟最前面的32K,由stage1負責去該區域將stage1.5找出來並執行。


stage2:grub的核心部分,讓使用者以選項的方式將作業系統載入、修改選項以及新增引數,平時開機啟動的時候看到的Grub選項、資訊,還有修改GRUB背景等功能都是stage2提供的,stage2會去讀入/boot/grub/grub.conf配置檔案。


總結:

1) BIOS將控制權交給硬碟的主引導區,即MBR。

2) MBR中的bootloader(stage1)通過內建的地址載入stage1_5;

3)bootloader通過stage1_5的內容,將分割槽中的stage2載入;

4)stage2此時就可以在檔案系統中將grub.conf檔案載入,讓使用者看到選項介面。


通過下面我們可以看到linux的核心VMLnuz,grub、initrd都在/boot目錄下:

wKiom1aE7miRdAHCAAAQ5dScYbs309.png

再看grub下檔案:

wKioL1aE7rjSpal4AAGWEQLIfT8814.png

再看看grub.conf配置檔案

wKioL1aE7x2BTktIAAK9BjWgBvs859.png


5.Kernel:當stage2被載入記憶體執行時,它首先會去解析grub的配置檔案/boot/grub/grub.conf,然後載入核心映象到記憶體中,並將控制權轉交給核心.而核心會立即初始化系統中各裝置並做相關的配置工作,其中包括CPU、I/O、儲存裝置等,並且以讀寫的方式掛載根檔案系統(根切換),那麼這裡就出現了一個“先有雞還是先有蛋的檔案了”,具體是什麼呢?

要想訪問真正的根檔案系統(rootfs)的話,就必須載入根檔案系統中的裝置,這時根檔案系統又沒有掛載,要掛載根檔案系統又得載入根檔案系統中的驅動程式,那怎麼辦呢?為了解決這個問題,這是就用到了initrd檔案了。

在來說下kernel初始化所要工作的內容做下簡單總結:

探測硬體->載入驅動(initrd)->掛載根檔案系統->rootfs(/sbin/init)


詳細解釋如下:

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程序。


我們看一下initrd下檔案:

wKioL1aE8tvCqTq2AAKJaCCxuog128.png



再看其中init指令碼的內容:

wKioL1aE9CLjfWqmAAJCY2ymd-U053.pngwKiom1aE9DTSl1aJAAIerdx3yiI556.png

wKioL1aE9IXQcAzRAAJhV9hGEfc928.png

從上面的指令碼內容我們可以看到init程序的主要工作:

掛載 :將initrd中的/proc, /sys /dev 掛載到當前的主分割槽中的相應目錄

建立目錄:/dev/mapper

通過mknod完成block or character special files的建立

相關模組的掛載

建立root裝置

掛載 /sysroot

最後完成根切換


由上面圖片可知,initrd這樣一個虛擬檔案根檔案系統,作用就是將kernel和真的根檔案系統建立關聯關係,讓kernel去initrd中載入根檔案系統所需要的驅動程式,並以讀寫的方式掛載根檔案系統,並讓執行使用者當中第一個程序init。


現在再讓我們把這一步跟上一步結合起來總結一下:

grub的stage2將initrd載入到記憶體裡,然後將其中的內容釋放到記憶體中,核心便去執行initrd中的init指令碼,這時核心將控制權交給了init檔案處理。我們簡單瀏覽一下init指令碼的內容,發現它也主要是載入各種儲存介質相關的裝置驅動程式。當所需的驅動程式載入完後,會建立一個根裝置,然後將根檔案系統rootfs以只讀的方式掛載。這一步結束後,釋放未使用的記憶體,轉換到真正的根檔案系統上面去,同時執行/sbin/init程式,執行系統的1號程序。此後系統的控制權就全權交給/sbin/init程序了。


6.到此為止,跋涉千山萬水,核心空間的工作終於完成,黎明的曙光就要顯現,下一步就是初始化系統了,核心空間的任務開始向用戶空間轉移。/sbin/init程序是系統其他所有程序的父程序,當它接管了系統的控制權先之後,它首先會去讀取/etc/inittab檔案來執行相應的指令碼進行系統初始化,如設定鍵盤、字型,裝載模組,設定網路等。它分為以下工作:


現在先讓我們看下/etc/inittab的配置的詳細內容:

wKioL1aE91GwHJ6dAAKps1DfPEk562.png

wKioL1aE93fDZrswAAL-S4nz-Ss809.png

各個級別的定義

預設執行級別3,5

0:halt //關機 ,shutdown

1: single user mode //單使用者維護模式),root使用者,無須認證;維護模式;

2:multi user mode, without NFS //不支援NFS功能 ,會啟動網路功能,維護模式;

3: multi user mode, text mode //完全功能模式;文字介面

4:reserved //系統保留,目前無特別使用目的,但習慣以同3級別功能使用;

5: multi user mode, graphic mode //圖形化介面,完全功能模式

6: reboot //重啟


級別切換:init #

級別檢視:who -r | runlevel


/etc/inittab的格式及語法:

[選項]:[runlevel]:[行為]:[命令]即:id:runlevels:action:process

行為:

wait:等待切換至此任務所在的級別時執行一次;

respawn:一旦此任務終止,就自動重新啟動之;

initdefault:設定預設執行級別;此時,process省略;

sysinit:設定系統初始化方式,此處一般為指定/etc/rc.d/rc.sysinit指令碼;

命令:通常是一些指令碼


1) 執行系統初始化指令碼(/etc/rc.d/rc.sysinit),對系統進行基本的配置,以讀寫方式掛載根檔案系統及其它檔案系統,到此係統算是基本執行起來了,後面需要進行執行級別的確定及相應服務的啟動。

我們可以看看inittab內定義的初始化指令碼:rc.sysinit --/etc/rc.d/rc.sysinit

wKiom1aE-pjRkPoSAAE8WQeCBfI422.pngwKiom1aE-sSDWyudAAEQcS5U3mg012.png


如上圖所示:rc.sysinit指令碼內定義了一些與系統初始化的定義:

(1) 設定主機名;

(2) 設定歡迎資訊;

(3) 啟用udev和selinux;

(4) 掛載/etc/fstab檔案中定義的所有檔案系統;

(5) 檢測根檔案系統,並以讀寫方式重新掛載根檔案系統;

(6) 設定系統時鐘;

(7) 根據/etc/sysctl.conf檔案來設定核心引數;

(8) 啟用lvm及軟raid裝置;

(9) 啟用swap裝置;

(10) 載入額外裝置的驅動程式;

(11) 清理操作;

(12)然後根據系統執行級別執行相關的服務指令碼:/etc/rc.d/init.d/指令碼和/etc/rc.d/rc#d

當/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下的檔案。

wKiom1aE--Ki_9IbAAER7d2imKo762.png


由上圖可知,

rc0-rc6目錄下指令碼:

K* ##只要是以K開頭的檔案均執行stop工作

S* ##只要是以S開頭的檔案均執行start工作

0-99 (執行次序,數字越小越先被執行)

使用者自定義開機啟動程式(/etc/rc.d/rc.local),可以根據自己的需求將一些執行命令或是指令碼寫到/etc/rc.d/rc.local裡,當開機時,可以自動載入


也就是說,/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指令碼就是保留給使用者自定義啟動內容的。


完成了系統所有的啟動任務後,linux會啟動終端或X-Window來等待使用者登入。tty1,tty2,tty3...這表示在執行等級1,2,3,4的時候,都會執行"/sbin/mingetty",而且執行了6個,所以linux會有6個純文字終端,mingetty就是啟動終端的命令。

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

至此,系統啟動完畢!


在系統啟動過程中主要的指令碼和目錄有:

boot

/grub

/boot/grub/grub.conf

/boot/initrd+核心版本

/initrd檔案中的/proc/ /sys/ /dev/ 目錄的掛載 及根的切換

/etc/inittab 指令碼

/etc/rc.d/rc.sysinit 指令碼 等


轉載於:https://blog.51cto.com/niefeifly/1730533