經(jīng)過對(duì)Linux系統(tǒng)有了一定了解和熟悉后,,想對(duì)其更深層次的東西做進(jìn)一步探究。這當(dāng)中就包括系統(tǒng)的啟動(dòng)流程,、文件系統(tǒng)的組成結(jié)構(gòu),、基于動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的程序在執(zhí)行時(shí)的異同、協(xié)議棧的架構(gòu)和原理,、驅(qū)動(dòng)程序的機(jī)制等等,。 本人在綜合了現(xiàn)有網(wǎng)上大家智慧的基礎(chǔ)上,,結(jié)合對(duì)2.6.32的內(nèi)核代碼的研讀,,基于CentOS 6.0系統(tǒng)對(duì)Linux的啟動(dòng)流程做了些分析。由于才疏學(xué)淺,,知識(shí)所限,,有些地方分析不妥之處還請(qǐng)各位高手不吝賜教。 OK,,我們言歸正傳,。對(duì)于一臺(tái)安裝了Linux系統(tǒng)的主機(jī)來說,當(dāng)用戶按下開機(jī)按鈕時(shí),,一共要經(jīng)歷以下幾個(gè)過程,,如圖:
其中,每個(gè)過程都執(zhí)行了自己該做的初始化部分的事情,,有些過程又可分為好幾個(gè)子過程,。接下來,,我們就對(duì)每個(gè)階段做一個(gè)詳細(xì)分析和講解。
稍有計(jì)算機(jī)基礎(chǔ)的人都應(yīng)該聽過BIOS(Basic Input / Output System),,又稱基本輸入輸出系統(tǒng),,可以視為是一個(gè)永久地記錄在ROM中的一個(gè)軟件,是操作系統(tǒng)輸入輸出管理系統(tǒng)的一部分,。早期的BIOS芯片確實(shí)是"只讀"的,,里面的內(nèi)容是用一種燒錄器寫入的,一旦寫入就不能更改,,除非更換芯片?,F(xiàn)在的主機(jī)板都使用一種叫Flash EPROM的芯片來存儲(chǔ)系統(tǒng)BIOS,里面的內(nèi)容可通過使用主板廠商提供的擦寫程序擦除后重新寫入,,這樣就給用戶升級(jí)BIOS提供了極大的方便,。 BIOS的功能由兩部分組成,分別是POST碼和Runtime服務(wù),。POST階段完成后它將從存儲(chǔ)器中被清除,,而Runtime服務(wù)會(huì)被一直保留,用于目標(biāo)操作系統(tǒng)的啟動(dòng),。BIOS兩個(gè)階段所做的詳細(xì)工作如下: 步驟1:上電自檢POST(Power-on self test),,主要負(fù)責(zé)檢測(cè)系統(tǒng)外圍關(guān)鍵設(shè)備(如:CPU、內(nèi)存,、顯卡,、I/O、鍵盤鼠標(biāo)等)是否正常,。例如,,最常見的是內(nèi)存松動(dòng)的情況,BIOS自檢階段會(huì)報(bào)錯(cuò),,系統(tǒng)就無法啟動(dòng)起來,; 步驟2:步驟1成功后,便會(huì)執(zhí)行一段小程序用來枚舉本地設(shè)備并對(duì)其初始化,。這一步主要是根據(jù)我們?cè)贐IOS中設(shè)置的系統(tǒng)啟動(dòng)順序來搜索用于啟動(dòng)系統(tǒng)的驅(qū)動(dòng)器,,如硬盤、光盤,、U盤,、軟盤和網(wǎng)絡(luò)等。我們以硬盤啟動(dòng)為例,,BIOS此時(shí)去讀取硬盤驅(qū)動(dòng)器的第一個(gè)扇區(qū)(MBR,,512字節(jié)),然后執(zhí)行里面的代碼,。實(shí)際上這里BIOS并不關(guān)心啟動(dòng)設(shè)備第一個(gè)扇區(qū)中是什么內(nèi)容,,它只是負(fù)責(zé)讀取該扇區(qū)內(nèi)容,、并執(zhí)行。 至此,,BIOS的任務(wù)就完成了,,此后將系統(tǒng)啟動(dòng)的控制權(quán)移交到MBR部分的代碼。 PS: 在個(gè)人電腦中,,Linux的啟動(dòng)是從0xFFFF0地址開始的,。
磁盤分區(qū)表包含以下三部分: 1),、Partition ID (5:延申 82:Swap 83:Linux 8e:LVM fd:RAID) 2)、Partition起始磁柱 3),、Partition的磁柱數(shù)量 通常情況下,,諸如lilo、grub這些常見的引導(dǎo)程序都直接安裝在MBR中,。我們以grub為例來分析這個(gè)引導(dǎo)過程,。 grub引導(dǎo)也分為兩個(gè)階段stage1階段和stage2階段(有些較新的grub又定義了stage1.5階段)。 1),、stage1:stage1是直接被寫入到MBR中去的,這樣機(jī)器一啟動(dòng)檢測(cè)完硬件后,,就將控制權(quán)交給了GRUB的代碼,。也就是上圖所看到的前446個(gè)字節(jié)空間中存放的是stage1的代碼。BIOS將stage1載入內(nèi)存中0x7c00處并跳轉(zhuǎn)執(zhí)行,。stage1(/stage1/start.S)的任務(wù)非常單純,,僅僅是將硬盤0頭0道2扇區(qū)讀入內(nèi)存,。而0頭0道2扇區(qū)內(nèi)容是源代碼中的/stage2/start.S,,編譯后512字節(jié),它是stage2或者stage1_5的入口,。而此時(shí),,stage1是沒有識(shí)別文件系統(tǒng)的能力的。如果感覺腦子有些暈了,,那么下面的過程就直接跳過,,去看stage2吧,! 【外傳】定位硬盤的0頭0道2扇區(qū)的過程: BIOS將stage1載入內(nèi)存0x7c00處并執(zhí)行,然后調(diào)用BIOS INIT13中斷,,將硬盤0頭0道2扇區(qū)內(nèi)容載入內(nèi)存0x7000處,然后調(diào)用copy_buffer將其轉(zhuǎn)移到內(nèi)存0x8000處,。在定位0頭0道2扇區(qū)時(shí)通常有兩種尋址方式:LBA和CHS,。如果你是刨根問底兒型的愛好者,,那么此時(shí)去找谷哥打聽打聽這兩種方式的來龍去脈吧。 2),、stage2:嚴(yán)格來說這里還應(yīng)該再區(qū)分個(gè)stage1.5的,,就一并把stage1.5放在這里一起介紹了,,免得大家看得心里亂哄哄的。好的,,我們繼續(xù)說0頭0到2扇區(qū)的/stage2/start.S文件,,當(dāng)它的內(nèi)容被讀入到內(nèi)存之后,它的主要作用就是負(fù)責(zé)將stage2或stage1.5從硬盤讀到內(nèi)存中,。如果是stage2,,它將被載入到0x820處,;如果是stage1.5,,它將被載入到0x2200處。這里的stage2或者stage1_5不是/boot分區(qū)/boot/grub目錄下的文件,,因?yàn)檫@個(gè)時(shí)候grub還沒有能力識(shí)別任何文件系統(tǒng),。 ? 如果start.S加載stage1.5:stage1.5它存放在硬盤0頭0道3扇區(qū)向后的位置,stage1_5作為stage1和stage2中間的橋梁,,stage1_5有識(shí)別文件系統(tǒng)的能力,,此后grub才有能力去訪問/boot分區(qū)/boot/grub目錄下的 stage2文件,將stage2載入內(nèi)存并執(zhí)行,。 ? 如果start.S加載stage2:同樣,,這個(gè)stage2也不是/boot分區(qū)/boot/grub目錄下的stage2,這個(gè)時(shí)候start.S讀取的是存放在/boot分區(qū)Boot Sector的stage2,。這種情況下就有一個(gè)限制:因?yàn)閟tart.S通過BIOS中斷方式直接對(duì)硬盤尋址(而非通過訪問具體的文件系統(tǒng)),,其尋址范圍有限,限制在8GB以內(nèi),。因此這種情況需要將/boot分區(qū)分在硬盤8GB尋址空間之前,。 假如是情形2,,我們將/boot/grub目錄下的內(nèi)容清空,依然能成功啟動(dòng)grub,;假如是情形1,,將/boot/grub目錄下stage2刪除后,則系統(tǒng)啟動(dòng)過程中g(shù)rub會(huì)啟動(dòng)失敗,。
當(dāng)stage2被載入內(nèi)存執(zhí)行時(shí),,它首先會(huì)去解析grub的配置文件/boot/grub/grub.conf,然后加載內(nèi)核鏡像到內(nèi)存中,,并將控制權(quán)轉(zhuǎn)交給內(nèi)核,。而內(nèi)核會(huì)立即初始化系統(tǒng)中各設(shè)備并做相關(guān)的配置工作,其中包括CPU,、I/O,、存儲(chǔ)設(shè)備等。 關(guān)于Linux的設(shè)備驅(qū)動(dòng)程序的加載,,有一部分驅(qū)動(dòng)程序直接被編譯進(jìn)內(nèi)核鏡像中,,另一部分驅(qū)動(dòng)程序則是以模塊的形式放在initrd(ramdisk)中。 Linux內(nèi)核需要適應(yīng)多種不同的硬件架構(gòu),,但是將所有的硬件驅(qū)動(dòng)編入內(nèi)核又是不實(shí)際的,,而且內(nèi)核也不可能每新出一種硬件結(jié)構(gòu),就將該硬件的設(shè)備驅(qū)動(dòng)寫入內(nèi)核,。實(shí)際上Linux的內(nèi)核鏡像僅是包含了基本的硬件驅(qū)動(dòng),,在系統(tǒng)安裝過程中會(huì)檢測(cè)系統(tǒng)硬件信息,根據(jù)安裝信息和系統(tǒng)硬件信息將一部分設(shè)備驅(qū)動(dòng)寫入 initrd ,。這樣在以后啟動(dòng)系統(tǒng)時(shí),,一部分設(shè)備驅(qū)動(dòng)就放在initrd中來加載。這里有必要給大家再多介紹一下initrd這個(gè)東東: initrd 的英文含義是 bootloader initialized RAM disk,,就是由 boot loader 初始化的內(nèi)存盤,。在 linu2.6內(nèi)核啟動(dòng)前,boot loader 會(huì)將存儲(chǔ)介質(zhì)中的 initrd 文件加載到內(nèi)存,,內(nèi)核啟動(dòng)時(shí)會(huì)在訪問真正的根文件系統(tǒng)前先訪問該內(nèi)存中的 initrd 文件系統(tǒng),。在 boot loader 配置了 initrd 的情況下,內(nèi)核啟動(dòng)被分成了兩個(gè)階段,,第一階段先執(zhí)行 initrd 文件系統(tǒng)中的init,,完成加載驅(qū)動(dòng)模塊等任務(wù),第二階段才會(huì)執(zhí)行真正的根文件系統(tǒng)中的 /sbin/init 進(jìn)程,。 另外一個(gè)概念:initramfs initramfs 是在 kernel 2.5中引入的技術(shù),,實(shí)際上它的含義就是:在內(nèi)核鏡像中附加一個(gè)cpio包,這個(gè)cpio包中包含了一個(gè)小型的文件系統(tǒng),,當(dāng)內(nèi)核啟動(dòng)時(shí),,內(nèi)核將這個(gè) cpio包解開,并且將其中包含的文件系統(tǒng)釋放到rootfs中,,內(nèi)核中的一部分初始化代碼會(huì)放到這個(gè)文件系統(tǒng)中,,作為用戶層進(jìn)程來執(zhí)行。這樣帶來的明顯的好處是精簡(jiǎn)了內(nèi)核的初始化代碼,,而且使得內(nèi)核的初始化過程更容易定制,。 疑惑的是:我的內(nèi)核是2.6.32-71.el6.i686版本,但在我的/boot分區(qū)下面卻存在的是/boot/initramfs-2.6.32-71.el6.i686.img類型的文件,,沒搞明白,,還望高人解惑。我只知道在2.6內(nèi)核中支持兩種格式的initrd,,一種是2.4內(nèi)核的文件系統(tǒng)鏡像image-initrd,,一種是cpio格式。接下來我們就來探究一下initramfs-2.6.32-71.el6.i686.img里到底放了那些東西,。
在tmp文件夾中解壓initrd.img里的內(nèi)容:
如果initrd.img文件的格式顯示為“initrd.img:ISO 9660 CD-ROM filesystem data”,,則可直接輸入命令“mount -o loop initrd.img /mnt/test”進(jìn)行掛載。 通過上的分析和我們的驗(yàn)證,,我們確實(shí)得到了這樣的結(jié)論: grub的stage2將initrd加載到內(nèi)存里,,讓后將其中的內(nèi)容釋放到內(nèi)容中,內(nèi)核便去執(zhí)行initrd中的init腳本,,這時(shí)內(nèi)核將控制權(quán)交給了init文件處理,。我們簡(jiǎn)單瀏覽一下init腳本的內(nèi)容,發(fā)現(xiàn)它也主要是加載各種存儲(chǔ)介質(zhì)相關(guān)的設(shè)備驅(qū)動(dòng)程序,。當(dāng)所需的驅(qū)動(dòng)程序加載完后,,會(huì)創(chuàng)建一個(gè)根設(shè)備,然后將根文件系統(tǒng)rootfs以只讀的方式掛載,。這一步結(jié)束后,,釋放未使用的內(nèi)存,轉(zhuǎn)換到真正的根文件系統(tǒng)上面去,,同時(shí)運(yùn)行/sbin/init程序,,執(zhí)行系統(tǒng)的1號(hào)進(jìn)程。此后系統(tǒng)的控制權(quán)就全權(quán)交給/sbin/init進(jìn)程了,。 l 初始化系統(tǒng) 經(jīng)過千辛萬苦的跋涉,,我們終于接近黎明的曙光了。接下來就是最后一步了:初始化系統(tǒng),。/sbin/init進(jìn)程是系統(tǒng)其他所有進(jìn)程的父進(jìn)程,,當(dāng)它接管了系統(tǒng)的控制權(quán)先之后,它首先會(huì)去讀取/etc/inittab文件來執(zhí)行相應(yīng)的腳本進(jìn)行系統(tǒng)初始化,如設(shè)置鍵盤,、字體,,裝載模塊,設(shè)置網(wǎng)絡(luò)等,。主要包括以下工作: 1),、執(zhí)行系統(tǒng)初始化腳本(/etc/rc.d/rc.sysinit),對(duì)系統(tǒng)進(jìn)行基本的配置,,以讀寫方式掛載根文件系統(tǒng)及其它文件系統(tǒng),,到此系統(tǒng)算是基本運(yùn)行起來了,后面需要進(jìn)行運(yùn)行級(jí)別的確定及相應(yīng)服務(wù)的啟動(dòng),。rc.sysinit所做的事情(不同的Linux發(fā)行版,,該文件可能有些差異)如下: (1)獲取網(wǎng)絡(luò)環(huán)境與主機(jī)類型。首先會(huì)讀取網(wǎng)絡(luò)環(huán)境設(shè)置文件"/etc/sysconfig/network",,獲取主機(jī)名稱與默認(rèn)網(wǎng)關(guān)等網(wǎng)絡(luò)環(huán)境,。 (2)測(cè)試與載入內(nèi)存設(shè)備/proc及usb設(shè)備/sys。除了/proc外,,系統(tǒng)會(huì)主動(dòng)檢測(cè)是否有usb設(shè)備,,并主動(dòng)加載usb驅(qū)動(dòng),嘗試載入usb文件系統(tǒng),。 (3)決定是否啟動(dòng)SELinux,。 (4)接口設(shè)備的檢測(cè)與即插即用(pnp)參數(shù)的測(cè)試。 (5)用戶自定義模塊的加載,。用戶可以再"/etc/sysconfig/modules/*.modules"加入自定義的模塊,,此時(shí)會(huì)加載到系統(tǒng)中。 (6)加載核心的相關(guān)設(shè)置,。按"/etc/sysctl.conf"這個(gè)文件的設(shè)置值配置功能,。 (7)設(shè)置系統(tǒng)時(shí)間(clock)。 (8)設(shè)置終端的控制臺(tái)的字形,。 (9)設(shè)置raid及LVM等硬盤功能,。 (10)以方式查看檢驗(yàn)磁盤文件系統(tǒng)。 (11)進(jìn)行磁盤配額quota的轉(zhuǎn)換,。 (12)重新以讀取模式載入系統(tǒng)磁盤,。 (13)啟動(dòng)quota功能。 (14)啟動(dòng)系統(tǒng)隨機(jī)數(shù)設(shè)備(產(chǎn)生隨機(jī)數(shù)功能),。 (15)清楚啟動(dòng)過程中的臨時(shí)文件,。 (16)將啟動(dòng)信息加載到"/var/log/dmesg"文件中。 當(dāng)/etc/rc.d/rc.sysinit執(zhí)行完后,,系統(tǒng)就可以順利工作了,,只是還需要啟動(dòng)系統(tǒng)所需要的各種服務(wù),這樣主機(jī)才可以提供相關(guān)的網(wǎng)絡(luò)和主機(jī)功能,因此便會(huì)執(zhí)行下面的腳本,。 2),、執(zhí)行/etc/rc.d/rc腳本。該文件定義了服務(wù)啟動(dòng)的順序是先K后S,,而具體的每個(gè)運(yùn)行級(jí)別的服務(wù)狀態(tài)是放在/etc/rc.d/rc*.d(*=0~6)目錄下,,所有的文件均是指向/etc/init.d下相應(yīng)文件的符號(hào)鏈接,。rc.sysinit通過分析/etc/inittab文件來確定系統(tǒng)的啟動(dòng)級(jí)別,,然后才去執(zhí)行/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目錄下相應(yīng)文件和文件夾的符號(hào)鏈接,。我們以啟動(dòng)級(jí)別3為例來簡(jiǎn)要說明一下。 /etc/rc.d/rc3.d目錄,,該目錄下的內(nèi)容全部都是以 S 或 K 開頭的鏈接文件,,都鏈接到"/etc/rc.d/init.d"目錄下的各種shell腳本。S表示的是啟動(dòng)時(shí)需要start的服務(wù)內(nèi)容,,K表示關(guān)機(jī)時(shí)需要關(guān)閉的服務(wù)內(nèi)容,。/etc/rc.d/rc*.d中的系統(tǒng)服務(wù)會(huì)在系統(tǒng)后臺(tái)啟動(dòng),如果要對(duì)某個(gè)運(yùn)行級(jí)別中的服務(wù)進(jìn)行更具體的定制,,通過chkconfig命令來操作,,或者通過setup、ntsys,、system-config-services來進(jìn)行定制,。如果我們需要自己增加啟動(dòng)的內(nèi)容,可以在init.d目錄中增加相關(guān)的shell腳本,,然后在rc*.d目錄中建立鏈接文件指向該shell腳本,。這些shell腳本的啟動(dòng)或結(jié)束順序是由S或K字母后面的數(shù)字決定,數(shù)字越小的腳本越先執(zhí)行,。例如,,/etc/rc.d/rc3.d /S01sysstat就比/etc/rc.d/rc3.d /S99local先執(zhí)行。 3),、執(zhí)行用戶自定義引導(dǎo)程序/etc/rc.d/rc.local,。其實(shí)當(dāng)執(zhí)行/etc/rc.d/rc3.d/S99local時(shí),它就是在執(zhí)行/etc/rc.d/rc.local,。S99local是指向rc.local的符號(hào)鏈接,。就是一般來說,自定義的程序不需要執(zhí)行上面所說的繁瑣的建立shell增加鏈接文件的步驟,只需要將命令放在rc.local里面就可以了,,這個(gè)shell腳本就是保留給用戶自定義啟動(dòng)內(nèi)容的,。 4)、完成了系統(tǒng)所有的啟動(dòng)任務(wù)后,,linux會(huì)啟動(dòng)終端或X-Window來等待用戶登錄,。tty1,tty2,tty3...這表示在運(yùn)行等級(jí)1,2,,3,,4的時(shí)候,都會(huì)執(zhí)行"/sbin/mingetty",,而且執(zhí)行了6個(gè),,所以linux會(huì)有6個(gè)純文本終端,mingetty就是啟動(dòng)終端的命令,。 除了這6個(gè)之外還會(huì)執(zhí)行"/etc/X11/prefdm-nodaemon"這個(gè)主要啟動(dòng)X-Window 至此,,系統(tǒng)就啟動(dòng)完畢了。以上分析不到的地方還請(qǐng)各位大蝦不吝指正,。 關(guān)于Linux的其他分析內(nèi)容下次再繼續(xù)寫,。 最后附上一張非常完整的系統(tǒng)啟動(dòng)流程圖,適合各個(gè)水平階段的讀者,。
參考文獻(xiàn): http://www.cnblogs.com/scnutiger/archive/2009/09/30/1576795.html http://www./f/edu/0411/24/51090.htm http://bbs./thread-2046548-1-1.html http://space./8111049/viewspace-680043 |
|