一.linux啓動大概流程如下:
POST --> Boot Sequence(BIOS) --> Boot Loader (MBR) --> Kernel(ramdisk) --> rootfs --> switchroot --> /sbin/init -->(/etc/inittab, /etc/init/*.conf) --> 設定默認運行級別 --> 系統初始化腳本 --> 關閉或啓動對應級別下的服務 --> 啓動終端,流程圖如下:
二.詳細剖析過程
1.
POST開機自檢:電腦主機打開電源的時候,隨後會聽到滴的一聲,系統啓動開始了開機自檢 (POST-power on selftest)自檢開始),這個過程中主要是檢測計算機硬件設備比如: 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),其結構圖如下所示:
磁盤分區表包含以下三部分:
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階段;
由此可見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目錄下:
再看grub下文件:
再看看grub.conf配置文件
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下文件:
再看其中init腳本的內容:
從上面的腳本內容我們可以看到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的配置的詳細內容:
各個級別的定義
默認運行級別 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
如上圖所示: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下的文件。
由上圖可知,
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 腳本 等