機器加電啟動後,BIOS開始檢測系統參數,如記憶體的大小,日期和時間,磁碟
裝置及這些磁碟裝置用來引導的順序,通常情況下,BIOS都是被設定成首先檢查
軟碟機或光碟機(或兩者都檢查),然後再嘗試從硬碟引導。如果在這些可移動的設
備中,沒有找到可引導的介質,那麼BIOS通常是轉向第一塊硬碟最初的幾個扇區,
尋找用於裝載作業系統的指令。裝載作業系統的這個程式就是boot loader.
linux裡面的boot loader通常是lilo或grub,從Red Hat Linux 7.2起,GRUB(
GRand Unified Bootloader)取代LILO成為了預設的啟動裝載程式。那麼啟動的時候
grub是怎麼被載入的呢
grub有幾個重要的檔案,stage1,stage2,有的時候需要stage1.5.這些檔案一般都
在/boot/grub目錄下面.grub被載入通常包括以下幾個步驟:
1. 裝載基本的引導裝載程式(stage1),stage1非常小,網上說是512位元組,不過在我的系統上
用 du -b /boot/grub/stage1 顯示的是1024個位元組,不知道是不是grub版本不同的
緣故還是我理解有誤.stage1通常位於主開機磁區裡面,對於硬碟就是MBR了,stage1的
主要功能就是裝載第二引導程式(stage2).這主要是歸結於在主開機磁區中沒有足夠的
空間用於其他東西了,我用的是grub 0.93,stage2檔案的大小是 107520 bit.
2. 裝載第二引導裝載程式(stage2),這第二引導裝載程式實際上是引出更進階的功能,
以允許使用者裝載入一個特定的作業系統。在GRUB中,這步是讓使用者顯示一個菜單或
是輸入命令。由於stage2非常大,所以他一般位於檔案系統之中(通常是boot所在的根
分區).
上面還提到了stage1.5這個檔案,他的作用是什麼呢 你到/boot/grub目錄下看看,
fat_stage_1.5 e2fs_stage_1.5 xfs_stage_1.5等等,非常容易猜想stage1.5和檔案系統
有關係.有時候基本引導裝載程式(stage1)不能識別stage2所在的檔案系統分區,那麼這
時候就需要stage1.5來串連stage1和stage2了.因此對於不同的檔案系統就會有不同的
stage1.5.不過對於grub 0.93似乎stage1.5並不是非常重要,因為我試過了,在沒有stage1.5
的情況下, 我把stage1安裝在磁碟片的開機磁區內,然後把stage2放在格式化成ext2或
fat格式的磁碟片內,啟動的時候照常引導,並不必e2fs_stage_1.5或fat_stage_1.5.
下面是我的實驗:
#mkfs.ext2 /dev/fd0
#mount -t ext2 /dev/fd0 /mnt/floppy
#cd /mnt/floppy
#mkdir boot
#cd boot
#mkdir grub (以上三步可用mkdir -p boot/grub命令完成)
#cd grub
#cp /boot/grub/{stage1,stage2,grub.conf} ./
#cd; umount /mnt/floppy
以上幾步把磁碟片格式化成ext2格式,然後把stage1,stage2,grub.conf這幾個啟動的
時候必須的檔案拷貝到磁碟片的指定目錄下.下面安裝grub到磁碟片上.
#grub (進入grub環境)
grub> install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2
p (fd0)/boot/grub/grub.conf
以上這條命令也能用下面的兩句代替
grub>root (fd0) #grub的根目錄所在的分區
grub>setup (fd0) #這一步就相當於上面的install命令
我在這裡解釋一下
install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2 p
(fd0)/boot/grub/grub.conf 這條命令.
install
告訴GRUB將(fd0)/boot/grub/grub/stage1
安裝到軟碟機的開機磁區(fd0).
(fd0)/boot/grub/stage2
告訴grub stage2這個檔案所在的位置.
p 參數後面跟著(fd0)/boot/grub/grub.conf 告訴grub的設定檔案所在的位置.
好了,讓BIOS從軟碟機啟動,試一下,沒有e2fs_stage_1.5檔案照樣能夠進入系統.
其實這就是個小小的引導盤啊.(瞭解了grub的運行原理,就簡單多了^_^)
3. 目前我們已到grub的開機選單這一步了,接下來grub所需要做的就是裝載在一個特
定分區上的作業系統,如linux核心。一旦GRUB從他的命令列或設定檔案中,接到開始
作業系統的正確指令,他就尋找必要的引導檔案,然後把機器的控制權移交給作業系統.
由於篇幅有限,避免冗長,grub的命令我就不多說了,網上非常有多的資料,一個典型
完整的引導linux的命令如下:
title 51base
root(hd0,0)
kernel /bzImage ro root=/dev/ram0
initrd /initrd.img
這裡有必要注意一下幾個問題:
(1)grub的磁碟及分區的命名方式和linux有所差別,第一個磁碟是從0開始,第一
個分區也是從0開始.譬如第一個硬碟的第5分區在linux下面是/dev/hda5 ,而在grub裡面
是(hd0,4).再如/dev/fd0在grub裡面是(fd0,0).(最後一句如有錯誤望提醒)
(2)不管是IDE硬碟hda,hdb還是SCSI硬碟sda,sdb在grub裡面都是以hd方式命名.
譬如虛擬機器裡面的/dev/sda2在grub裡面是(hd0,1),再如/dev/hdb7在grub裡面以(hd1,6)
命名.
(3)要搞清晰上面兩個root的關係,root (hd0,0)中的root是grub命令,他用來指定
boot所在的分區作為grub的根目錄.而root=/dev/ram0是kernel的參數,他告訴作業系統
核心載入完畢之後,真實的檔案系統所在的裝置.要注意grub的根目錄和檔案系統的根
目錄的差別.
再回到上面的幾行命令.
kernel命令用來指定核心所在的位置,"/"代表(hd0,0),也就是grub的根目錄
initrd命令用來指定初始化ram的img檔案所在位置.
grub載入核心bzImage並展開到指定位置(應該是0x100000這個地方),同時載入
initrd.img到記憶體(不知道是什麼地方).
ps:
grub的任務至此就結束了,下面grub將機器的控制權轉交給作業系統(linux).
作業系統接到控制權之後,開始start_kernel,接著核心將initrd.img展開到/dev/ram0
為臨時根檔案系統,執行裡面的linuxrc檔案.
P.這裡有必要說一下initrd的作用特別是他裡面的核心檔案linuxrc的作用.
initrd是inital ram disk的宿寫.
當存在initrd的時候,機器啟動的過程大概是以下幾個步驟(當initrd這一行用
noinitrd 命令代替後,就不存在initrd了)
1)boot loader(grub)載入核心和initrd.img
2)核心將壓縮的initrd.img解壓成正常的ram disk並且釋放initrd所佔的記憶體空間
3)initrd作為根目錄以讀寫方式被掛載
4)initrd裡面的檔案linuxrc被執行
5)linuxrc掛載新的檔案系統
6)linuxrc使用pivot_root系統調用指定新的根目錄並將現有的根目錄place到指定
位置.
7)在新的檔案系統下正式init
8)initrd被卸載.
為了便於理解,我將red hat linnux9 裡面的initrd-2.4.20-8.img拿出來分析一下.
這其實是個壓縮了的檔案,是以gz結尾的.
[root@localhost root]#cp /boot/initrd-2.4.20-8.img /mnt/initrd-2.4.20-8.gz
[root@localhost root]#gunzip /mnt/initrd-2.4.20-8.gz
[root@localhost root]#mount -o loop /mnt/initrd-2.4.20-8 /mnt/ram
[root@localhost root]#cd /mnt/ram
[root@localhost ram]#ls
bin dev etc lib linuxrc loopfs proc sbin sysroot
[root@localhost ram]#ls bin
insmod modprobe nash
[root@localhost ram]#ls lib
Buslogic.o ext3.o jbd.o scsi_mod.o sd_mod.o
[root@localhost ram]ls dev
console null ram systty tty1 tty2 tty3 tty4
sbin目錄是指向bin目錄的一個串連,其他目錄是空的.
[root@localhost ram]cat linuxrc
#!/bin/nash
1.echo "Loading scsi_mod.o module"
2.insmod /lib/scsi_mod.o
3.echo "Loading sd_mod.o module"
4.insmod /lib/sd_mod.o
5.echo "Loading BusLogic.o module"
6.insmod /lib/BusLogic.o
7.echo "Loading jbd.o module"
8.insmod /lib/jbd.o
9.echo "Loading ext3.o module"
10.insmod /lib/ext3.o
11.echo Mounting /proc filesystem
12.mount -t proc /proc /proc
13.echo Creating block devices
14.mkdevices /dev
15.echo Creating root device
16.mkrootdev /dev/root
17.echo 0x0100 > /proc/sys/kernel/real-root-dev
18.echo Mounting root filesystem
19.mount -o defaults --ro -t ext3 /dev/root /sysroot
20.pivot_root /sysroot /sysroot/initrd
21.umount /initrd/proc
上面的編號是我為了下面好說明加上去的.
首先我們必須注意的是這裡使用的shell是nash而不是bash,nash是專門為linuxrc可執行
指令碼設計的,因此你有必要看一看nash的man檔案.
1-10行是載入一些必要的模快.11-12行載入proc核心檔案系統,13-14行利用nash內建的
命令mkdevices建立塊裝置,mkdevices是根據/proc/partitions檔案建立裡面列出的所有
塊裝置.15-16行利用nash內建的命令mkrootdev,mkrootdev使他後面的參數/dev/root成
為一個塊節點從而使得根分區裝置被掛載,其中根分區裝置由grub.conf裡面的kernel命
令後面所帶的參數root=決定,如果root=參數沒有被指定,/proc/sys/kernel/real-root-
dev檔案將提供根分區裝置號.17行將數字256寫入到後面的檔案裡面去.18-19行掛載根文
件系統到/sysroot目錄下,/dev/root裡面的內容就是root=參數所指定的裝置裡面的內容
20行調用pivot_root改動根目錄所在地並place舊的根目錄到指定的位置.21行卸載舊的
根目錄裡面的proc核心檔案系統.
從這裡面我們總結一下linuxrc的作用: (參考/usr/src/linux-2.4/Documenta
tion/initrd.txt檔案)
2)/linuxrc檔案決定在掛載真正的檔案系統之前所需完成的事情(譬如載入必要的網
絡驅動或載入ext3檔案系統).
3)/linuxrc載入必要的模組.
4)/linuxrc掛載根檔案系統
5)/linuxrc調用pivot_root來改動根目錄
關於initrd的用途能查考上面提到的檔案,想知道linux系統是怎麼安裝的嗎 那裡
面由答案.
既然linuxrc的主要目的是載入模快用的,那如果我們的核心沒有動態模組而所需
的功能都是靜態編譯進核心的,那麼是不是能不用linuxrc檔案呢
答案是能不用,在普通的linux作業系統裡面能加入noinitrd選項以告知boot
loader 不使用initrd.如果我們做網關,因為ram是我們的檔案系統的載體,所以initrd
一行當然不能去掉,不過我們能不用linuxrc檔案,sysroot目錄和initrd目錄.
不信的話,試試看吧.
好了,initrd(linuxrc)已介紹完了.
linuxrc執行完畢之後,系統就會以真正的根目錄正式init.
系統在/bin/或/sbin目錄下找到init程式,然後根據他的設定檔案/etc/fstab進行
初始化,最後調用mingetty程式啟動login完成引導.
ps:init這一部分網上有非常多的周詳資料所以我在這裡並沒有展開來說.