走進(jìn)Linux 操作系統(tǒng)
; 附件——linux系統(tǒng)啟動的標(biāo)準(zhǔn)流程 系統(tǒng)的啟動是指從計算機(jī)加電到顯示用戶登陸提示的整個過程。我們將在這里對整個流程以及關(guān)系到的一 些內(nèi)容做討論。過程主要可以分為兩個階段:載入內(nèi)核和準(zhǔn)備運(yùn)行環(huán)境,我們分別進(jìn)行討論。本部分的 討論只基于i386硬 件架構(gòu),但大部分內(nèi)容是有共通性的。![]() 圖一 啟動過程 綜述 載入內(nèi)核(將內(nèi)核載入內(nèi)存,并將控制權(quán)傳遞給它) 計算機(jī)加電到boot loader開始工作,硬件含量 遠(yuǎn)大于軟件含量,所以這里暫不提及,如果實在有關(guān)心的朋友,請先別著急,我們將在下期里討論它?! ∵@一階段是 boot loader 的主戰(zhàn)場。它必須將可執(zhí)行的內(nèi)核映像和內(nèi)核啟動所需的額外數(shù)據(jù)信息從存儲介質(zhì)上載入內(nèi)存,這并不是 件簡單的工作,因為除了從硬盤載入,可能還會需要從網(wǎng)絡(luò)引導(dǎo)服務(wù)器這樣的外部介質(zhì)上載入。各種紛繁蕪雜的文件系統(tǒng)類型也給載入帶來了巨大的挑戰(zhàn)。 boot loader 可能還需要改變cpu的運(yùn)行特權(quán)級別,然后就可以讓內(nèi)核投 入運(yùn)行了?! 〕酥?,boot loader 還要完成一些其它功能,比如從bios中獲取系統(tǒng)信息,或者從啟動時的命令行參數(shù)中提取信息等。有的 boot loader 還要扮演引導(dǎo)選擇工具的角色,方便用戶選擇不同的操作系 統(tǒng)。 boot loader的職責(zé): 判斷到底要載入什么,這可以要求用戶進(jìn)行選擇 載入內(nèi)核和它可能需要用到的相關(guān)數(shù)據(jù),比如initrd或者其它參數(shù) 為內(nèi)核準(zhǔn)備好運(yùn)行環(huán)境,比如,讓cpu進(jìn)入特權(quán)模式 讓內(nèi)核投入運(yùn)行 boot loader的 歷史變遷: 早期的linux只支持軟盤引導(dǎo)扇區(qū)和 shoelace 兩種 boot loader。 shoelace 是從minix繼承下來的、對文件系統(tǒng)相關(guān)的 boot loader。它只支持 minix 文件系統(tǒng)。當(dāng)時linux只使用 minix 一種文件 系統(tǒng),所以這樣做并沒什么問題。可是, minix 文件系統(tǒng)存在不能保存創(chuàng)建、修改和訪問時間信息;文件名長度限制在14個字節(jié)等問題。隨著linux的發(fā)展,這些與傳統(tǒng)unix文件系統(tǒng)大相徑庭的缺陷越來越讓人 難以忍受,它已經(jīng)不適合作為linux的主要文件系統(tǒng)了。 為了支持其它文件系統(tǒng)的實現(xiàn),linux引入了vfs(虛擬文件系統(tǒng))。這個舉措很快就引起了熱烈的反響,一大批新的文件系統(tǒng)實現(xiàn)出現(xiàn)了。其中一個 minix 文件系統(tǒng)的變體,擴(kuò)展文件系統(tǒng) xiafs (根據(jù)它的作者命名)突破了 minix 文件系統(tǒng)的文件名長度限制,將此長度一舉提高到全部30個字符。當(dāng)時文件系統(tǒng)之間的競爭著實激 烈,很難看出誰會勝出,甚至搞不清楚會不會有一個最終的“贏家”。 盡管不確定性很大,但是有一點(diǎn)卻是清楚的:不管最后哪種文 件系統(tǒng)會受到青睞,但是除了 minix 作為根文件系統(tǒng),誰也不能從硬盤上啟動,因為 shoelace 只支持minix文件系統(tǒng)。lilo應(yīng)運(yùn)而生了。由于支持多種文件系統(tǒng)(當(dāng)時內(nèi)核支持的主流文件系統(tǒng)已經(jīng)有 minix ,擴(kuò)展文件系統(tǒng) ext , xiafs 。還有人在移植 bsd 的 ffs ,根本看不出來什么時候是個盡頭)在實現(xiàn)和維護(hù)上難度太大,而 boot loader 也不 應(yīng)該成為人們試驗新的文件系統(tǒng)的絆腳石,所以lilo采取了和文件系統(tǒng)無關(guān)的設(shè)計?! ∵@種設(shè)計經(jīng)受住了時間的考驗,被證明是非常成功的。即使在今天,lilo仍舊可以從內(nèi)核支持的絕大部分文件 系統(tǒng)的硬盤上啟動。但是,由于ext2歷經(jīng)這么長的時間一直沒有大的演變,成為了事實上的標(biāo)準(zhǔn),所以跟文件系統(tǒng)相關(guān)的boot loader又漸漸流行了起來。盡管ext2已經(jīng)能滿足大部分人的日常需要,但 是文件系統(tǒng)的設(shè)計者們還是在研制以日志機(jī)制為特征的新的文件系統(tǒng),并且已經(jīng)取得了相當(dāng)大的進(jìn)展??紤]到當(dāng)前又有可能出現(xiàn)多種文件系統(tǒng)的實現(xiàn)同時并存的情 況,因此對與文件系統(tǒng)無關(guān)的boot loader的需求可能會再次變得強(qiáng)勁。初始化基本的操作環(huán)境 一旦內(nèi)核開始運(yùn)行,它會初始化內(nèi)部的數(shù)據(jù)結(jié)構(gòu),檢測硬件,并且激活相應(yīng)的驅(qū)動程序,為應(yīng)用軟件的準(zhǔn) 備運(yùn)行環(huán)境。其間包含一個重要操作——應(yīng)用軟件的運(yùn)行環(huán)境必須要有一個文件系統(tǒng),所以內(nèi)核必須首先裝載root文件系統(tǒng)。由于我們的目的是介紹基 本流程,所以相關(guān)的硬件初始化細(xì)節(jié)就不再討論,相關(guān)內(nèi)容在下一期雜志中會有詳細(xì)介紹。 硬件初始化完成后,內(nèi)核著手創(chuàng)建第一個進(jìn)程——初始進(jìn)程。說是創(chuàng)建, 其實也不盡然,該進(jìn)程其實是整個硬件上電初始化過程的延續(xù),只不過執(zhí)行到這里,進(jìn)程的邏輯已經(jīng)完備,所以我們就按照進(jìn)程的創(chuàng)建方式給它進(jìn)行了“規(guī)格化” ——我們把這個初始進(jìn)程也叫做“硬件進(jìn)程”,它會占據(jù)進(jìn)程描述符表的第一個位置,所以可以用task[0]?或init_task表示。該進(jìn)程進(jìn)而會再創(chuàng)建一 個新進(jìn)程去執(zhí)行init()函數(shù),其實,這個新進(jìn)程才是系統(tǒng)第一個實際有用的進(jìn)程,它會負(fù)責(zé)接著執(zhí)行下一個階段的初始化操作; 而初始進(jìn)程(init_task)自己則會開始執(zhí)行idle循環(huán),也就是說,內(nèi)核初始化完成之后,初始進(jìn)程唯一的任務(wù)就是在沒有任何其它進(jìn)程需要執(zhí)行的時候, 消耗空閑的cpu時 間(因此初始進(jìn)程也被稱為idle進(jìn)程)?! ∠乱浑A段的初始化工作要比前一階段輕松一點(diǎn),因為現(xiàn)在是由一個真正進(jìn)程接手負(fù)責(zé)完成它們了,而前一 階段都是由“硬件進(jìn)程”手工去做的。在此階段,這個由init_task創(chuàng)建的新進(jìn)程需要初始化總線、網(wǎng)絡(luò)并啟動系統(tǒng)中的各種系統(tǒng)內(nèi)核后臺線程,然后再初始化外設(shè)、設(shè)置文 件格式,在這之后,它要為進(jìn)入系統(tǒng)做最后的準(zhǔn)備——初始化文件系統(tǒng),安裝root文件系統(tǒng),打開/dev/console設(shè)備,重定向stdin、stdout和stderr到控制臺,然后 搜索文件系統(tǒng)中的init程序,并使用 execve()系統(tǒng)調(diào) 用加載執(zhí)行init程 序。系統(tǒng)自此進(jìn)入了用戶態(tài)。裝載root文件系統(tǒng) 為了裝載文件系統(tǒng),內(nèi)核需要:1知道root文件系統(tǒng)位于那個存儲介質(zhì)上;2有訪問該種介質(zhì)的驅(qū)動程序。最常見的情況是root是ext2文件系統(tǒng),位于ide硬盤上。這種情況下需要的操作很簡單:將設(shè)備號作為參數(shù)給內(nèi)核就可以了,ide的設(shè)備驅(qū)動程序通常都會編譯進(jìn)內(nèi)核 的。 如果內(nèi)核沒有相關(guān)介質(zhì)的驅(qū)動程序,問題就會變得更為復(fù)雜。而這種情況并不罕見,比如linux的安裝盤使用的“通用”內(nèi)核一般都會碰到。如果內(nèi)核把所有支持的硬件的設(shè)備驅(qū)動程序都包含進(jìn)來,就會變成一個龐然 大物;而且一些驅(qū)動程序在檢測硬件的時候會影響其它設(shè)備。 這個問題可以通過initrd機(jī)制解決,它允 許在裝載實際的root文件系統(tǒng)之前先使用ram文件系統(tǒng)。除了上述兩個原因,引入initrd還可以解決內(nèi)核 的動態(tài)合成問題。(詳見參考資料一。) 不過我們應(yīng)該注意到,init在整個啟動過程中并不是從來就有的,它可以說是一個插件,為了解決以上問題,而被加入啟動過程,象圖一所示,linux系統(tǒng)在啟動時也可以不選擇它。為什么要引入initrd? linux啟動過程中肯定要載入內(nèi)核鏡像,在此過程中有些要素必須考慮: 首先,內(nèi)核鏡像不能太大。由于受到各種硬件和兼容性的限制,linux的內(nèi)核鏡像不能太大,但是這并不 容易做到。linux內(nèi)核的核心部分本身就不小了;而且還必須加入會使用到的驅(qū)動程序?! ∑浯危С直M可能多的硬件設(shè)備。我們在啟動過程中有一件重要工作:掛載root文件系統(tǒng),因為進(jìn)一步的數(shù)據(jù)和應(yīng)用 軟件都在其上,所以我們的內(nèi)核必須能夠訪問root文件系統(tǒng)。對于一般用戶,如果他們使用ide硬盤上的ext2文件分區(qū)作為root文件系統(tǒng),不會有什么問題。因為不管是ide硬盤還是ext2文件系統(tǒng),它們的驅(qū)動肯定會包含在內(nèi)核鏡像自身里面。但是,確實存在一些特殊情況:比如說我們希望 發(fā)行l(wèi)inux系 統(tǒng)的安裝光盤,那么對光盤的驅(qū)動,就不一定包含在內(nèi)核里面了。(有人可能要奇怪了,咦,光盤中的內(nèi)核鏡像不都已經(jīng)讀進(jìn)來了嗎,怎么內(nèi)核還訪問不了光盤呢? 注意,讀入內(nèi)核鏡像的是 boot loader ,內(nèi)核并不具備 boot loader 的功能。)如果沒有光盤的驅(qū)動,我們又怎么把光盤里的軟件包安裝到用戶的 計算機(jī)里呢?把驅(qū)動程序預(yù)先編譯到內(nèi)核里?聽起來還不錯,可是如果我們除了光盤還有一些其它的安裝介質(zhì),那么所有這些驅(qū)動就會讓內(nèi)核鏡像龐大不堪?! 《?,還有更嚴(yán)重的問題,各種不同的驅(qū)動程序很有可能會發(fā)生沖突,特別是以前isa設(shè)備占市場主導(dǎo)地位的時候,這種沖突 簡直難以避免。 那時的解決辦法是發(fā)行商提供預(yù)先編譯好的支持各種設(shè)備的不同內(nèi)核,把每個內(nèi)核放進(jìn)一張軟盤,隨發(fā)行 包一起交給用戶,用戶自己選擇裝有合適內(nèi)核的軟盤進(jìn)行引導(dǎo)?;蛘呓o用戶提供制作引導(dǎo)盤的工具,讓用戶在安裝前制作自己的啟動盤。當(dāng)然,哪一種辦法都不能讓 人滿意?! ∥ㄒ坏南M谟谑褂媚K化機(jī)制。在內(nèi)核啟動的時候調(diào)用相應(yīng)的模塊加載驅(qū)動程序,然后訪問root文件系統(tǒng)。無論是通過內(nèi)核對設(shè)備做 進(jìn)一步的分析還是直接從用戶那里得到配置信息,先配置再加載模塊的辦法,都能有效地避免沖突的發(fā)生。 除了在安裝的時候需要在掛載root文件系統(tǒng)之前調(diào)用相應(yīng)的模塊之外,在完成安裝的系統(tǒng)上,我們可能仍然需要在掛載root文件系統(tǒng)之前調(diào)用一些模塊。這主要 是為給計算機(jī)進(jìn)行配置——一般都要針對不同的計算機(jī)進(jìn)行內(nèi)核配置?! ±硐肭闆r下,用戶按照自己的實際情況配置編譯文件,重新編譯內(nèi)核,一步步完成這種工作。但是沒有幾個用戶喜歡這種冗長并且極易出現(xiàn)錯誤的工作。而且編譯和生成內(nèi)核需要相應(yīng)的 工具,可是大部分用戶不需要 |