BIOS啟動(dòng)模式下計(jì)算機(jī)的整個(gè)啟動(dòng)過(guò)程分成四個(gè)階段。
一、第一階段:BIOS
BIOS(Basic Input Output System)叫做”基本輸出輸入系統(tǒng)”,是一組固化到計(jì)算機(jī)主板ROM芯片內(nèi)的程序,計(jì)算機(jī)通電后,第一件事就是讀取它。
BIOS程序主要包括硬件自檢和初始化程序、CMOS設(shè)置程序、系統(tǒng)自動(dòng)裝載程序和主要I/O驅(qū)動(dòng)程序和中斷服務(wù)(BIOS和硬件直接打交道,需要加載I/O驅(qū)動(dòng)程序)。
BIOS程序首先進(jìn)行開(kāi)機(jī)自檢,即POST(Power-On Self-Test),此時(shí)只對(duì)內(nèi)存、CPU這樣的核心硬件進(jìn)行檢查,判斷硬件能否滿足計(jì)算機(jī)運(yùn)行的基本條件。如果核心硬件出現(xiàn)問(wèn)題,計(jì)算機(jī)一般會(huì)通過(guò)主板上的蜂鳴器發(fā)出規(guī)律重復(fù)的報(bào)警聲,啟動(dòng)中止。如果核心硬件沒(méi)有問(wèn)題,主板蜂鳴器一般會(huì)發(fā)出清脆的一聲“滴”聲,然后BIOS開(kāi)始對(duì)所有的計(jì)算機(jī)硬件進(jìn)行初始化,以便為操作系統(tǒng)管理和調(diào)配硬件做好準(zhǔn)備。在進(jìn)行硬件初始化時(shí),BIOS會(huì)首先初始化顯卡,然后將后繼初始化硬件的基本信息呈現(xiàn)在顯示器上,并通過(guò)顯示器顯示硬件初始化時(shí)可能發(fā)現(xiàn)的問(wèn)題,提示用戶處理。
初始化硬件之后,BIOS就按照CMOS里設(shè)置好的”啟動(dòng)順序”(Boot Sequence),依次尋找U盤、硬盤、網(wǎng)絡(luò)等設(shè)備,以找到引導(dǎo)操作系統(tǒng)的代碼MBR(Master Boot Record),并把控制權(quán)交給它。硬盤的MBR代碼由硬盤初始化命令和軟件寫于硬盤的第一個(gè)物理扇區(qū),如果要從硬盤啟動(dòng)電腦,硬件初始化之后,BIOS直接讀取位于磁盤最前邊的引導(dǎo)代碼MBR,由它接管操作系統(tǒng)的引導(dǎo)。MBR首先讀取位于其后,和它同在第一個(gè)扇區(qū)的硬盤分區(qū)表DPT(Disk Partition Table),并通過(guò)分析DPT找到硬盤分區(qū)中的活動(dòng)分區(qū)(Active Partition),然后加載在活動(dòng)分區(qū)內(nèi)的主引導(dǎo)記錄PBR代碼硬盤它要尋找引導(dǎo)操作系統(tǒng)的要把控制權(quán)轉(zhuǎn)交給下一階段的啟動(dòng)程序。這時(shí),BIOS需要知道,”下一階段的啟動(dòng)程序”具體存放在哪一個(gè)設(shè)備。也就是說(shuō),BIOS需要有一個(gè)外部?jī)?chǔ)存設(shè)備的排序,排在前面的設(shè)備就是優(yōu)先轉(zhuǎn)交控制權(quán)的設(shè)備。這種排序叫做。
二、第二階段:主引導(dǎo)記錄
BIOS按照”啟動(dòng)順序”,把控制權(quán)轉(zhuǎn)交給排在第一位的儲(chǔ)存設(shè)備。即根據(jù)用戶指定的引導(dǎo)順序從軟盤、硬盤或是可移動(dòng)設(shè)備中讀取啟動(dòng)設(shè)備的MBR,并放入指定的位置(0x7c000)內(nèi)存中。
這時(shí),計(jì)算機(jī)讀取該設(shè)備的第一個(gè)扇區(qū),也就是讀取最前面的512個(gè)字節(jié)。如果這512個(gè)字節(jié)的最后兩個(gè)字節(jié)是0x55和0xAA,表明這個(gè)設(shè)備可以用于啟動(dòng);如果不是,表明設(shè)備不能用于啟動(dòng),控制權(quán)于是被轉(zhuǎn)交給”啟動(dòng)順序”中的下一個(gè)設(shè)備。
這最前面的512個(gè)字節(jié),就叫做”主引導(dǎo)記錄”(Master boot record,縮寫為MBR)。
2.1 主引導(dǎo)記錄的結(jié)構(gòu)
“主引導(dǎo)記錄”只有512個(gè)字節(jié),放不了太多東西。它的主要作用是,告訴計(jì)算機(jī)到硬盤的哪一個(gè)位置去找操作系統(tǒng)。
主引導(dǎo)記錄由三個(gè)部分組成:
(1) 第1-446字節(jié):調(diào)用操作系統(tǒng)的機(jī)器碼。
(2) 第447-510字節(jié):分區(qū)表(Partition table)。
(3) 第511-512字節(jié):主引導(dǎo)記錄簽名(0x55和0xAA)。
其中,第二部分”分區(qū)表”的作用,是將硬盤分成若干個(gè)區(qū)。
2.2 分區(qū)表
硬盤分區(qū)有很多好處??紤]到每個(gè)區(qū)可以安裝不同的操作系統(tǒng),”主引導(dǎo)記錄”因此必須知道將控制權(quán)轉(zhuǎn)交給哪個(gè)區(qū)。
分區(qū)表的長(zhǎng)度只有64個(gè)字節(jié),里面又分成四項(xiàng),每項(xiàng)16個(gè)字節(jié)。所以,一個(gè)硬盤最多只能分四個(gè)一級(jí)分區(qū),又叫做”主分區(qū)”。
每個(gè)主分區(qū)的16個(gè)字節(jié),由6個(gè)部分組成:
(1) 第1個(gè)字節(jié):如果為0x80,就表示該主分區(qū)是激活分區(qū),控制權(quán)要轉(zhuǎn)交給這個(gè)分區(qū)。四個(gè)主分區(qū)里面只能有一個(gè)是激活的。
(2) 第2-4個(gè)字節(jié):主分區(qū)第一個(gè)扇區(qū)的物理位置(柱面、磁頭、扇區(qū)號(hào)等等)。
(3) 第5個(gè)字節(jié):主分區(qū)類型。
(4) 第6-8個(gè)字節(jié):主分區(qū)最后一個(gè)扇區(qū)的物理位置。
(5) 第9-12字節(jié):該主分區(qū)第一個(gè)扇區(qū)的邏輯地址。
(6) 第13-16字節(jié):主分區(qū)的扇區(qū)總數(shù)。
最后的四個(gè)字節(jié)(”主分區(qū)的扇區(qū)總數(shù)”),決定了這個(gè)主分區(qū)的長(zhǎng)度。也就是說(shuō),一個(gè)主分區(qū)的扇區(qū)總數(shù)最多不超過(guò)2的32次方。
如果每個(gè)扇區(qū)為512個(gè)字節(jié),就意味著單個(gè)分區(qū)最大不超過(guò)2TB。再考慮到扇區(qū)的邏輯地址也是32位,所以單個(gè)硬盤可利用的空間最大也不超過(guò)2TB。如果想使用更大的硬盤,只有2個(gè)方法:一是提高每個(gè)扇區(qū)的字節(jié)數(shù),二是增加扇區(qū)總數(shù)。
三、第三階段:硬盤啟動(dòng)
這時(shí),計(jì)算機(jī)的控制權(quán)就要轉(zhuǎn)交給硬盤的某個(gè)分區(qū)了,這里又分成三種情況。
3.1 情況A:卷引導(dǎo)記錄
上一節(jié)提到,四個(gè)主分區(qū)里面,只有一個(gè)是激活的。計(jì)算機(jī)會(huì)讀取激活分區(qū)的第一個(gè)扇區(qū),叫做”卷引導(dǎo)記錄”(Volume boot record,縮寫為VBR)。
“卷引導(dǎo)記錄”的主要作用是,告訴計(jì)算機(jī),操作系統(tǒng)在這個(gè)分區(qū)里的位置。然后,計(jì)算機(jī)就會(huì)加載操作系統(tǒng)了。
3.2 情況B:擴(kuò)展分區(qū)和邏輯分區(qū)
隨著硬盤越來(lái)越大,四個(gè)主分區(qū)已經(jīng)不夠了,需要更多的分區(qū)。但是,分區(qū)表只有四項(xiàng),因此規(guī)定有且僅有一個(gè)區(qū)可以被定義成”擴(kuò)展分區(qū)”(Extended partition)。
所謂”擴(kuò)展分區(qū)”,就是指這個(gè)區(qū)里面又分成多個(gè)區(qū)。這種分區(qū)里面的分區(qū),就叫做”邏輯分區(qū)”(logical partition)。
計(jì)算機(jī)先讀取擴(kuò)展分區(qū)的第一個(gè)扇區(qū),叫做”擴(kuò)展引導(dǎo)記錄”(Extended boot record,縮寫為EBR)。它里面也包含一張64字節(jié)的分區(qū)表,但是最多只有兩項(xiàng)(也就是兩個(gè)邏輯分區(qū))。
計(jì)算機(jī)接著讀取第二個(gè)邏輯分區(qū)的第一個(gè)扇區(qū),再?gòu)睦锩娴姆謪^(qū)表中找到第三個(gè)邏輯分區(qū)的位置,以此類推,直到某個(gè)邏輯分區(qū)的分區(qū)表只包含它自身為止(即只有一個(gè)分區(qū)項(xiàng))。因此,擴(kuò)展分區(qū)可以包含無(wú)數(shù)個(gè)邏輯分區(qū)。
但是,似乎很少通過(guò)這種方式啟動(dòng)操作系統(tǒng)。如果操作系統(tǒng)確實(shí)安裝在擴(kuò)展分區(qū),一般采用下一種方式啟動(dòng)。
3.3 情況C:?jiǎn)?dòng)管理器
在這種情況下,計(jì)算機(jī)讀取”主引導(dǎo)記錄”前面446字節(jié)的機(jī)器碼之后,不再把控制權(quán)轉(zhuǎn)交給某一個(gè)分區(qū),而是運(yùn)行事先安裝的”啟動(dòng)管理器”(boot loader),由用戶選擇啟動(dòng)哪一個(gè)操作系統(tǒng)。
Linux環(huán)境中,目前最流行的啟動(dòng)管理器是Grub。
對(duì)于grub而言,在MBR中的446字節(jié)的引導(dǎo)程序?qū)儆贕RUB的開(kāi)始執(zhí)行程序,通過(guò)這段程序,進(jìn)一步執(zhí)行stage1.5或是stage2的執(zhí)行程序,將在下面詳細(xì)介紹執(zhí)行過(guò)程。
其中stage1.5或是stage2便屬于階段2引導(dǎo)的過(guò)程了,stage2過(guò)程也是作為GRUB kernel的核心代碼出現(xiàn)。Stage1.5過(guò)程(對(duì)于GRUB而言存在stage1.5,GRUB2則不存在)的功能很單一,主要就是為了引導(dǎo)stage2過(guò)程服務(wù)。由于stage2過(guò)程的代碼存放在文件系統(tǒng)下的boot分區(qū)目錄中,因此stage1.5過(guò)程就是需要提供一個(gè)文件系統(tǒng)的環(huán)境,而該文件系統(tǒng)環(huán)境需要保證系統(tǒng)可以找到stage2過(guò)程的文件,那么stage1.5階段提供的文件系統(tǒng)需要是boot文件系統(tǒng)所對(duì)應(yīng)的,這個(gè)在執(zhí)行g(shù)rub install過(guò)程中就已經(jīng)確定了。stage2過(guò)程中,主要會(huì)把系統(tǒng)切換到保護(hù)模式,設(shè)置好C運(yùn)行時(shí)環(huán)境,找到config文件(事實(shí)上就是menulist文件),如果沒(méi)有找到就執(zhí)行一個(gè)shell,等待用戶的執(zhí)行。然后的工作就變成了輸入命令->解析命令->執(zhí)行命令的循環(huán)中。當(dāng)然該階段引導(dǎo)的最終狀態(tài)就是執(zhí)行boot命令,將內(nèi)核和initrd鏡像加載進(jìn)入內(nèi)存中,進(jìn)而將控制權(quán)轉(zhuǎn)交給內(nèi)核。
四、第四階段:操作系統(tǒng)
控制權(quán)轉(zhuǎn)交給操作系統(tǒng)后,操作系統(tǒng)的內(nèi)核首先被載入內(nèi)存。
以Linux系統(tǒng)為例,先載入/boot目錄下面的kernel。內(nèi)核加載成功后,第一個(gè)運(yùn)行的程序是/sbin/init。它根據(jù)配置文件(Debian系統(tǒng)是/etc/initab)產(chǎn)生init進(jìn)程。這是Linux啟動(dòng)后的第一個(gè)進(jìn)程,pid進(jìn)程編號(hào)為1,其他進(jìn)程都是它的后代。
然后,init線程加載系統(tǒng)的各個(gè)模塊,比如窗口程序和網(wǎng)絡(luò)程序,直至執(zhí)行/bin/login程序,跳出登錄界面,等待用戶輸入用戶名和密碼。
至此,全部啟動(dòng)過(guò)程完成。
另外在大磊的
博客中還有許多細(xì)節(jié)部分:
BIOS啟動(dòng)細(xì)節(jié):
a) 按下電源開(kāi)關(guān),電源就開(kāi)始向主板和其它設(shè)備供電;當(dāng)芯片組檢測(cè)到電源已經(jīng)開(kāi)始穩(wěn)定供電了(當(dāng)然從不穩(wěn)定到穩(wěn)定的過(guò)程只是一瞬間的事情),它便撤去RESET信號(hào)(如果是手工按下計(jì)算機(jī)面板上的Reset按鈕來(lái)重啟機(jī)器,那么松開(kāi)該按鈕時(shí)芯片組就會(huì)撤去RESET信號(hào));CPU馬上就從地址FFFF:0000H 處開(kāi)始執(zhí)行指令,放在這里的只是一條跳轉(zhuǎn)指令,跳到系統(tǒng)BIOS中真正的啟動(dòng)代碼處。
b) 系統(tǒng)BIOS的啟動(dòng)代碼首先進(jìn)行POST(Power-On Self Test,加電后自檢)。POST的主要檢測(cè)系統(tǒng)中一些關(guān)鍵設(shè)備是否存在和能否正常工作,例如內(nèi)存和顯卡等設(shè)備;由于POST是最早進(jìn)行的檢測(cè)過(guò)程,此時(shí)顯卡還沒(méi)有初始化,如果系統(tǒng)BIOS在進(jìn)行POST的過(guò)程中發(fā)現(xiàn)了一些致命錯(cuò)誤,例如沒(méi)有找到內(nèi)存或者內(nèi)存有問(wèn)題(此時(shí)只會(huì)檢查640K常規(guī)內(nèi)存),那么系統(tǒng)BIOS就會(huì)直接控制喇叭發(fā)聲來(lái)報(bào)告錯(cuò)誤,聲音的長(zhǎng)短和次數(shù)代表了錯(cuò)誤的類型;在正常情況下,POST過(guò)程進(jìn)行得非??欤瑤缀鯚o(wú)法感覺(jué)到它的存在。POST結(jié)束之后就會(huì)調(diào)用其它代碼來(lái)進(jìn)行更完整的硬件檢測(cè)。
c) 接下來(lái)系統(tǒng)BIOS將查找顯卡的BIOS。前面說(shuō)過(guò),存放顯卡BIOS的ROM芯片的起始地址通常設(shè)在C0000H處,系統(tǒng)BIOS在這個(gè)地方找到顯卡BIOS之后就調(diào)用它的初始化代碼,由顯卡BIOS來(lái)初始化顯卡。此時(shí)多數(shù)顯卡都會(huì)在屏幕上顯示出一些初始化信息,介紹生產(chǎn)廠商、圖形芯片類型等內(nèi)容,不過(guò)這個(gè)畫面幾乎是一閃而過(guò)。系統(tǒng)BIOS接著會(huì)查找其它設(shè)備的BIOS程序,找到之后同樣要調(diào)用這些BIOS內(nèi)部的初始化代碼來(lái)初始化相關(guān)的設(shè)備。
d) 查找完所有其它設(shè)備的BIOS之后,系統(tǒng)BIOS將顯示出它自己的啟動(dòng)畫面,其中包括有系統(tǒng)BIOS的類型、序列號(hào)和版本號(hào)等內(nèi)容。
e) 接著系統(tǒng)BIOS將檢測(cè)和顯示CPU的類型和工作頻率,測(cè)試所有的RAM,并同時(shí)在屏幕上顯示內(nèi)存測(cè)試的進(jìn)度??梢栽贑MOS設(shè)置中自行決定使用簡(jiǎn)單耗時(shí)少或者詳細(xì)耗時(shí)多的測(cè)試方式。
f) 內(nèi)存測(cè)試通過(guò)之后,系統(tǒng)BIOS將開(kāi)始檢測(cè)系統(tǒng)中安裝的一些標(biāo)準(zhǔn)硬件設(shè)備,包括硬盤、CD-ROM、串口、并口和軟驅(qū)等設(shè)備,另外絕大多數(shù)較新版本的系統(tǒng)BIOS在這一過(guò)程中還要自動(dòng)檢測(cè)和設(shè)置內(nèi)存的定時(shí)參數(shù)、硬盤參數(shù)和訪問(wèn)模式等。
g) 標(biāo)準(zhǔn)設(shè)備檢測(cè)完畢后,系統(tǒng)BIOS內(nèi)部支持即插即用的代碼將開(kāi)始檢測(cè)和配置系統(tǒng)中安裝的即插即用設(shè)備。每找到一個(gè)設(shè)備之后,系統(tǒng)BIOS都會(huì)在屏幕上顯示出設(shè)備的名稱和型號(hào)等信息,同時(shí)為該設(shè)備分配中斷、DMA通道和I/O端口等資源。
h) 到這一步為止,所有硬件都已經(jīng)檢測(cè)配置完畢了,多數(shù)系統(tǒng)BIOS會(huì)重新清屏并在屏幕上方顯示出一個(gè)表格,其中概略地列出了系統(tǒng)中安裝的各種標(biāo)準(zhǔn)硬件設(shè)備,以及它們使用的資源和一些相關(guān)工作參數(shù)。
i) 接下來(lái)系統(tǒng)BIOS將更新ESCD(Extended System Configuration Data,擴(kuò)展系統(tǒng)配置數(shù)據(jù))。ESCD是系統(tǒng)BIOS用來(lái)與操作系統(tǒng)交換硬件配置信息的一種手段,這些數(shù)據(jù)被存放在CMOS(一小塊特殊的RAM,由主板上的電池來(lái)供電)之中。通常ESCD數(shù)據(jù)只在系統(tǒng)硬件配置發(fā)生改變后才會(huì)更新,所以不是每次啟動(dòng)機(jī)器時(shí)都能夠看到“Update ESCD… Success”這樣的信息。不過(guò),某些主板的系統(tǒng)BIOS在保存ESCD數(shù)據(jù)時(shí)使用了與Windows 9x不相同的數(shù)據(jù)格式,于是Windows 9x在它自己的啟動(dòng)過(guò)程中會(huì)把ESCD數(shù)據(jù)修改成自己的格式。但在下一次啟動(dòng)機(jī)器時(shí),即使硬件配置沒(méi)有發(fā)生改變,系統(tǒng)BIOS也會(huì)把ESCD的數(shù)據(jù)格式改回來(lái)。如此循環(huán),將會(huì)導(dǎo)致在每次啟動(dòng)機(jī)器時(shí),系統(tǒng)BIOS都要更新一遍ESCD,這就是為什么有些機(jī)器在每次啟動(dòng)時(shí)都會(huì)顯示出相關(guān)信息的原因。
j) ESCD更新完畢后,系統(tǒng)BIOS的啟動(dòng)代碼將進(jìn)行它的最后一項(xiàng)工作:即根據(jù)用戶指定的啟動(dòng)順序從軟盤、硬盤或光驅(qū)啟動(dòng)MBR。在這個(gè)過(guò)程中會(huì)按照啟動(dòng)順序順序比較其放置MBR的位置的結(jié)尾兩位是否為0xAA55,通過(guò)這種方式判斷從哪個(gè)引導(dǎo)設(shè)備進(jìn)行引導(dǎo)。在確定之后,將該引導(dǎo)設(shè)備的MBR內(nèi)容讀入到0x7C00[1]的位置,并再次判斷其最后兩位,當(dāng)檢測(cè)正確之后,進(jìn)行階段1的引導(dǎo)。
EFI啟動(dòng)細(xì)節(jié)
與傳統(tǒng)MBR相比,GPT采用了不同的分區(qū)方式。
對(duì)于傳統(tǒng)MBR,其結(jié)構(gòu)主要如下:
上圖即對(duì)上文中所述的很形象的說(shuō)明,在圖中看到MBR被分成三個(gè)部分,分別是:Bootloader、分別表以及Magic Number。其中Bootloader部分為stage1中被執(zhí)行的起始部分。
相反,對(duì)于EFI系統(tǒng)中所采用的GPT分區(qū)方式,則采用了不同于MBR分區(qū)方式的形式,從下圖中可以發(fā)現(xiàn):
如上圖所示,GPT分區(qū)表主要包括:保護(hù)MBR、首要GPT頭、首要GPT、備用GPT、備用GPT頭和磁盤數(shù)據(jù)區(qū)。保護(hù)MBR與正常的MBR區(qū)別不大,主要是分區(qū)表上的不同,在保護(hù)MBR中只要一個(gè)表示為0xEE的分區(qū),以此來(lái)表示這塊硬盤使用GPT分區(qū)表。首要GPT頭包含了眾多信息,具體內(nèi)容如下:
分區(qū)表頭定義了硬盤的可用空間以及組成分區(qū)表的項(xiàng)的大小和數(shù)量。分區(qū)表頭還記錄了這塊硬盤的GUID,記錄了分區(qū)表頭本身的位置和大?。ㄎ恢每偸窃贚BA1)以及備份分區(qū)表頭和分區(qū)表的位置和大小(在硬盤的最后)。它還存儲(chǔ)著它本身和分區(qū)表的CRC32校驗(yàn)。固件、引導(dǎo)程序和操作系統(tǒng)在啟動(dòng)時(shí)可以根據(jù)這個(gè)校驗(yàn)值來(lái)判斷分區(qū)表是否有錯(cuò)誤,如果出錯(cuò)了,可以使用軟件從硬盤最后的備份GPT分區(qū)表恢復(fù)整個(gè)分區(qū)表,如果備份GPT也校驗(yàn)錯(cuò)誤,那么磁盤將不可用,系統(tǒng)拒絕啟動(dòng)。
接下來(lái)主要是128個(gè)分區(qū)表項(xiàng),GPT分區(qū)表使用簡(jiǎn)單而直接的方式表示分區(qū)。一個(gè)分區(qū)表項(xiàng)的前16字節(jié)是分區(qū)類型GUID。例如,EFI系統(tǒng)分區(qū)的GUID類型是{C12A7328-F81F-11D2-BA4B-00A0C93EC93B} 。接下來(lái)的16字節(jié)是該分區(qū)的唯一的GUID(這個(gè)指的是該分區(qū)本身,而之前的GUID指的是該分區(qū)的類型)。在接下來(lái)是分區(qū)其實(shí)和末尾的64位LBA編號(hào),以及分區(qū)的名字和屬性。具體結(jié)構(gòu)如下表:
MBR引導(dǎo)
接下來(lái)開(kāi)始真正的引導(dǎo)過(guò)程了,主要說(shuō)明GRUP的引導(dǎo)??傮w上GRUB更像是一個(gè)mini os,只不過(guò)這個(gè)mini os的作用只是加載其他的操作系統(tǒng),在GRUB中包括stage1、stage1.5(可選)和stage2,其中stage1和stage1.5屬于boot loader,stage2屬于mini os的內(nèi)核部分。GRUB中stage1過(guò)程主要位于MBR的前446字節(jié)中(對(duì)于支持GPT分區(qū)的磁盤,同樣有最開(kāi)始的512字節(jié)作為保護(hù)MBR,保護(hù)MBR與正常的MBR區(qū)別不大,主要是分區(qū)表上的不同,在保護(hù)MBR中只要一個(gè)表示為0xEE的分區(qū),以此來(lái)表示這塊硬盤使用GPT分區(qū)表,不能識(shí)別GPT硬盤的操作系統(tǒng)通常會(huì)識(shí)別出一個(gè)未知類型的分區(qū),并且拒絕對(duì)硬盤進(jìn)行操作),之后的64字節(jié)為硬盤的分區(qū)表,最后兩個(gè)字節(jié)為MBR結(jié)束標(biāo)志位(0xAA55)。
stage1部分占用了446字節(jié),其代碼文件是源碼目錄下stage1/stage1.S文件,匯編后生成一個(gè)512字節(jié)的boot.img,被寫在硬盤的0面0道1扇區(qū)中,作為硬盤的MBR。stage1的工作很簡(jiǎn)單,就是加載0面0道2扇區(qū)上的512字節(jié)到0×8000,然后跳轉(zhuǎn)到0×8000執(zhí)行。
在0面0道2扇區(qū)上的512字節(jié)內(nèi)容為stage1/start.S文件匯編后生成。該扇區(qū)上的內(nèi)容的作用是加載stage1.5或是stage2過(guò)程,并將控制權(quán)轉(zhuǎn)交。
Grub引導(dǎo)
在start過(guò)程將控制權(quán)轉(zhuǎn)交后,接下來(lái)就是GRUB的核心過(guò)程了。該過(guò)程之所以區(qū)分stage1.5和stage2,主要原因是GRUB和GRUB2的區(qū)別。在GRUB2中,將stage1.5過(guò)程集成到了stage2的過(guò)程中,所以stage1.5過(guò)程僅僅是針對(duì)GRUB的。下面將會(huì)分別介紹兩種GRUB版本的兩種過(guò)程。
4.1 GRUB中stage1.5過(guò)程
Stage1.5過(guò)程很無(wú)辜,它的作用很單一,但是非常關(guān)鍵。它的主要功用就是構(gòu)造一個(gè)boot分區(qū)系統(tǒng)對(duì)應(yīng)的文件系統(tǒng),這樣可以通過(guò)文件系統(tǒng)的路徑(/boot/grub/)尋找stage2過(guò)程需要的core.img,進(jìn)而加載到內(nèi)存中開(kāi)始執(zhí)行。
Stage1.5存在于0面0道3扇區(qū)開(kāi)始的地方,并一直延續(xù)十幾k字節(jié)的區(qū)域,具體的大小與相應(yīng)的文件系統(tǒng)的大小有關(guān)(文中涉及到了0面0道1-3+x扇區(qū),這部分扇區(qū)為保留扇區(qū),BIOS不會(huì)放置任何數(shù)據(jù)。正因?yàn)槿绱巳绻D(zhuǎn)換到GPT分區(qū)形式,系統(tǒng)將不能被正確引導(dǎo),如上文所示,MBR后面的扇區(qū)都被其他內(nèi)容所占據(jù))。Stage1.5過(guò)程被構(gòu)建成多種不同類型,但是功能類似,下面簡(jiǎn)單介紹一下基本的stage1.5過(guò)程的文件系統(tǒng)。e2fs_stage1_5(針對(duì)ext2fs,可引導(dǎo)ext2和ext3文件系統(tǒng))、fat_stage1_5(針對(duì)fat文件系統(tǒng),可引導(dǎo)fat32和fat16)、ffs_stage1_5、jfs_stage1_5、minix_stage1_5、reiserfs_stage1_5、vstafs_stage1_5和xfs_stage1_5,這些文件被稱為stage1.5過(guò)程,這些文件每個(gè)至少都在11k以上。除此之外還有兩個(gè)比較特殊的文件,分別為nbgrub和pxegrub,這兩個(gè)文件主要是在網(wǎng)絡(luò)引導(dǎo)時(shí)使用,只是格式不同而已,他們很類似與stage2,只是需要建立網(wǎng)絡(luò)來(lái)獲取配置文件。
由于stage1.5過(guò)程中會(huì)涉及到多個(gè)文件系統(tǒng)對(duì)應(yīng)的文件,因此本文中主要以ext2fs為例進(jìn)行說(shuō)明,其他文件系統(tǒng)與此類似,可以同樣進(jìn)行分析理解。
對(duì)于ext2fs文件系統(tǒng),用于生成該文件系統(tǒng)的stage1.5過(guò)程文件(e2fs_stage1_5)的代碼為stage2/fsys_ext2fs.c文件。
在stage2/filesys.h文件中定義了每個(gè)文件系統(tǒng)對(duì)外的接口,用于上層調(diào)用,作為stage2過(guò)程尋找核心代碼使用,文件系統(tǒng)一般被定義的接口主要就是三個(gè)函數(shù),分別是mount、read和dir函數(shù)。對(duì)應(yīng)ext2fs,其定義的函數(shù)為:
12345678
#ifdef FSYS_EXT2FS
#define FSYS_EXT2FS_NUM 1
int ext2fs_mount (void);
int ext2fs_read (char *buf, int len);
int ext2fs_dir (char *dirname);
#else
#define FSYS_EXT2FS_NUM 0
#endif
針對(duì)ext2fs有如上的函數(shù)名稱,每個(gè)函數(shù)將具體在stage2/fsys_ext2fs.c文件中被定義,這里面沒(méi)有包含任何的寫的過(guò)程,對(duì)于bootloader而言僅僅讀就可以完成任務(wù)了,沒(méi)必要對(duì)其系統(tǒng)進(jìn)行寫操作。其中ext2fs_mount函數(shù)用于檢查文件系統(tǒng)類型,并將superblock讀入到內(nèi)存中;ext2fs_read函數(shù)和ext2fs_dir函數(shù)用于對(duì)文件系統(tǒng)具體的操作。在stage2/fsys_ext2fs.c文件中除了需要對(duì)這三個(gè)函數(shù)的定義之外,還需要文件系統(tǒng)的屬性的數(shù)據(jù)結(jié)構(gòu)(superblock、inode和group結(jié)構(gòu),這些結(jié)構(gòu)最初被定義在include/linux/ext2_fs.h文件中),通過(guò)這些數(shù)據(jù)結(jié)構(gòu)描述一個(gè)文件系統(tǒng)。
如果讀者有興趣可以試著創(chuàng)建新的文件系統(tǒng)的支持,可以參照目前存在的一些文件系統(tǒng)的模板(實(shí)例)編寫。
4.2 GRUB中stage2過(guò)程
GRUB中的核心過(guò)程也就是stage2過(guò)程了,該過(guò)程主要是在文件系統(tǒng)建立以后選擇合適的操作系統(tǒng)進(jìn)行加載并轉(zhuǎn)交控制權(quán),達(dá)到最后引導(dǎo)操作系統(tǒng)的目標(biāo)。由于GRUB屬于multi boot loader,因此在引導(dǎo)的時(shí)候要進(jìn)行選擇,選擇哪種操作系統(tǒng)來(lái)運(yùn)行。在GRUB內(nèi)部主要包括兩種方式,首先是從menu.list中讀取顯示到屏幕讓用戶選擇,其次是通過(guò)grub-shell中定義的命令手動(dòng)進(jìn)行啟動(dòng)。本文將在后面介紹這兩種方式如何運(yùn)行,接下來(lái)先介紹一下stage2的具體的執(zhí)行過(guò)程。
在上面一節(jié)中介紹過(guò),stage1.5過(guò)程中將boot分區(qū)的文件系統(tǒng)加載了,之后又做了一件事情,就是將控制權(quán)轉(zhuǎn)交給stage2,而stage2入口的地方就是stage2/asm.S文件。Stage2/asm.S文件屬于匯編代碼,主要作用是初始化C語(yǔ)言的運(yùn)行環(huán)境,為下面執(zhí)行C語(yǔ)言的函數(shù)做好準(zhǔn)備,在準(zhǔn)備好之后,將執(zhí)行init_bios_info(stage2/common.c)函數(shù)。init_bios_info函數(shù)的作用是執(zhí)行一些底層的函數(shù),然后跳轉(zhuǎn)到cmain執(zhí)行,cmain函數(shù)位于stage2/stage2.c文件中。cmain函數(shù)內(nèi)部進(jìn)行一個(gè)死循環(huán),在循環(huán)內(nèi)部首先加載配置文件,顯示給用戶,在這同時(shí)循環(huán)一個(gè)內(nèi)層循環(huán),在內(nèi)層循環(huán)中,獲取配置文件中的命令,并解析執(zhí)行。過(guò)程中如果沒(méi)有可用的配置文件,那么進(jìn)入命令行模式(enter_cmdline函數(shù)),如果找到可用的menu,那么開(kāi)始執(zhí)行menu的對(duì)應(yīng)的內(nèi)容(run_menu函數(shù))。
對(duì)于enter_cmdline(stage2/stage2.c)函數(shù),將調(diào)用find_command(stage2/cmdline.c),進(jìn)而執(zhí)行相應(yīng)命令的函數(shù)。
對(duì)于run_menu(stage2/stage2.c)函數(shù),將調(diào)用stage2/cmdline.c文件中的run_script函數(shù),進(jìn)而調(diào)用find_command,執(zhí)行相應(yīng)命令的函數(shù)。
這兩種方式雖然經(jīng)過(guò)了不同的過(guò)程,對(duì)用戶輸入的行為進(jìn)行分析和處理,最終調(diào)用的函數(shù)為find_command,在該函數(shù)中順序循環(huán)比較“輸入”的命令是否與系統(tǒng)內(nèi)部定義的相同,如果相同轉(zhuǎn)到執(zhí)行該函數(shù)。在這個(gè)比較的過(guò)程中包含了一個(gè)全局的數(shù)據(jù)結(jié)構(gòu)為struct builtin(stage2/shared.h),由該數(shù)據(jù)結(jié)構(gòu)組成了一個(gè)table類型(stage2/builtins.c),將命令與相對(duì)應(yīng)的builtin結(jié)構(gòu)對(duì)應(yīng)一起并進(jìn)行串聯(lián)。下面描述一下builtin結(jié)構(gòu)的定義:
1234567891011121314
struct builtin {
/* 命令名稱,重要,是搜索命令時(shí)的依據(jù)*/
char *name;
/* 命令函數(shù),重要,是搜索匹配后調(diào)用的函數(shù)*/
int (*func) (char *, int);
/* 功能標(biāo)示,一般未用到. */
int flags;
/* 簡(jiǎn)短幫助信息*/
char *short_doc;
/* 完整幫助信息*/
char *long_doc;
};
struct builtin *builtin_table[];
有興趣的讀者可以對(duì)上面的內(nèi)容進(jìn)行擴(kuò)展,形成自己的命令,主要在stage2/builtins.c文件中按照預(yù)定的格式更新,并添加到builtin_table中即可。
在上面打開(kāi)配置文件的過(guò)程中,主要是通過(guò)一些文件操作函數(shù)(被定義在stage2/disk_io.c中)完成。這些文件操作函數(shù)主要包括:grub_open、grub_read、grub_seek和grub_close等,這些函數(shù)屬于grub對(duì)外的上層接口,具體的函數(shù)內(nèi)部將調(diào)用前文中提到的boot分區(qū)對(duì)應(yīng)的文件系統(tǒng)的相應(yīng)的函數(shù)完成,這個(gè)過(guò)程主要是通過(guò)回調(diào)函數(shù)來(lái)完成。該過(guò)程整體思路類似于面向?qū)ο筮^(guò)程,通過(guò)對(duì)象操作具體的函數(shù)。