Linux啓動過程剖析

Linux啓動過程剖析

作者:王姍姍,華清遠見嵌入式學院講師。

Linux啓動過程的剖析能幫助那些想深入學習Linux用戶建立一個相關Linux啓動過程的清晰概念,進而可以進一步研究Linux接下來是如何工作的。

Linux啓動過程如下:當用戶打開PC的電源,BIOS開機自檢,按BIOS中設置的啓動設備(通常是硬盤)啓動,接着啓動設備上安裝的引導程序lilo或grub開始引導Linux,Linux首先進行內核的引導,接下來執行init程序,init程序調用了rc.sysinit和rc等程序,rc.sysinit和rc當完成系統初始化和運行服務的任務後,返回init;init啓動了mingetty後,打開了終端供用戶登錄系統,用戶登錄成功後進入了Shell,這樣就完成了從開機到登錄的整個啓動過程。如圖所示:

下面分步來介紹下linux的啓動過程:

1、BIOS自檢

當你打開計算機電源,計算機會首先加載BIOS信息,BIOS信息是如此的重要,以至於計算機必須在最開始就找到它。這是因爲BIOS中包含了CPU的相關信息、設備啓動順序信息、硬盤信息、內存信息、時鐘信息、PnP特性等等。在此之後,計算機心裏就有譜了,知道應該去讀取哪個硬件設備了。

計算機在接通電源之後首先由BIOS進行自檢,即進行所謂的POST(Power On Self  Test),然後依據BIOS內設置的引導順序從硬盤、軟盤或CDROM中讀入“引導塊”。 在 PC 中,引導 Linux 是從 BIOS 中的地址 0xFFFF0 處開始的。BIOS 的第一個步驟是加電自檢(POST)。POST 的工作是對硬件進行檢測。BIOS 的第二個步驟是進行本地設備的枚舉和初始化。給定 BIOS 功能的不同用法之後,BIOS 由兩部分組成:POST 代碼和運行時服務。當 POST 完成之後,它被從內存中清理了出來,但是 BIOS 運行時服務依然保留在內存中,目標操作系統可以使用這些服務。

要引導一個操作系統,BIOS 運行時會按照 CMOS 的設置定義的順序來搜索處於活動狀態並且可以引導的設備。引導設備可以是軟盤、CD-ROM、硬盤上的某個分區、網絡上的某個設備,甚至是 USB 閃存。通常,Linux 都是從硬盤上引導的,其中主引導記錄(MBR)中包含主引導加載程序。

衆所周知,硬盤上第0磁道第一個扇區被稱爲MBR,也就是Master Boot Record,即主引導記錄,它的大小是512字節,別看地方不大,可裏面卻存放了預啓動信息、分區表信息。系統找到BIOS所指定的硬盤的MBR後,就會將其複製到0×7c00地址所在的物理內存中。當 MBR 被加載到 RAM 中之後,BIOS 就會將控制權交給 MBR。其實被複制到物理內存的內容就是Boot Loader,而具體到你的電腦,那就是lilo或者grub了。

提取MBR的信息

要看MBR的內容,請使用下面的命令

#從/dev/sda上讀取前512個字節的內容,並將其寫入mbr.bin文件中

root@farsight:/home/linux# dd if=/dev/sda of=mbr.bin bs=512 count=1
    1+0 records in
    1+0 records out
    512 bytes (512 B) copied, 0.000798615 seconds, 641 kB/s
    #以十六進制和ASCII碼格式打印這個二進制文件的內容
    root@farsight:/home/linux# od -xa mbr.bin
    0000000 48eb 1090 d08e 00bc b8b0 0000 d88e c08e
          k   H dle dle  so   P   < nul   0   8 nul nul  so   X  so   @
    0000020 befb 7c00 00bf b906 0200 a4f3 21ea 0006
          {   > nul   |   ? nul ack   9 nul stx   s   $   j   ! ack nul
    0000040 be00 07be 0438 0b75 c683 8110 fefe 7507
        nul   >   > bel   8 eot   u  vt etx   F dle soh   ~   ~ bel   u
    ……

這個 dd 命令需要以 root 用戶的身份運行,它從 /dev/hda(第一個 IDE 盤) 上讀取前 512 個字節的內容,並將其寫入 mbr.bin 文件中。od 命令會以十六進制和 ASCII 碼格式打印這個二進制文件的內容。

2、啓動GRUB/LILO

Boot Loader 就是在操作系統內核運行之前運行的一段小程序。通過這段小程序,我們可以初始化硬件設備、建立內存空間的映射圖,從而將系統的軟硬件環境帶到一個合適的狀態,以便爲最終調用操作系統內核做好一切準備。

Boot Loader有若干種,其中Grub、Lilo和spfdisk是常見的Loader。

GRUB和LILO都是引導加載程序,它們會引導操作系統。當機器引導它的操作系統時,BIOS會讀取引導介質上最前面的512字節(即MBR: master boot record)。在單一的 MBR 中只能存儲一個操作系統的引導記錄,所以當需要多個操作系統時就會出現問題。所以需要更靈活的引導加載程序。

GRUB 與 LILO 的比較

所有引導加載程序都以類似的方式工作,滿足共同的目的。不過,LILO 和 GRUB 之間有很多不同之處:

● LILO 沒有交互式命令界面,而 GRUB 擁有。

● LILO 不支持網絡引導,而 GRUB 支持。 

● LILO 將關於可以引導的操作系統位置的信息物理上存儲在 MBR 中。如果修改了 LILO 配置文件,必須將 LILO 第一階段引導加載程序重寫到 MBR。相對於 GRUB,這是一個更爲危險的選擇,因爲錯誤配置的 MBR 可能會讓系統無法引導。使用 GRUB,如果配置文件配置錯誤,則只是默認轉到 GRUB 命令行界面。

安全提示:

關於安全性,任何可以接觸到引導磁盤/CD 的人,只需要使用沒有設置安全性的 grub.conf 或 lilo.conf,就可以繞過本文中提及的所有安全措施。特別是使用 GRUB 時,因爲能夠引導到單用戶模式,所以是一個嚴重的安全漏洞。解決此問題的一個簡單方法是在機器的 BIOS 中禁止通過 CD 和軟盤進行引導,並確保爲 BIOS 設置了一個口令,使得其他人不能修改這些設置。

我們以Grub爲例來講解。系統讀取內存中的grub配置信息(一般爲menu.lst或grub.lst),並依照此配置信息來啓動不同的操作系統。

3、加載內核

當內核映像被加載到內存後,內核階段就開始了。 內核映像並不是一個可執行的內核,而是一個壓縮過的內核映像。通常它是一個zImage(壓縮映像,小於512KB)或bzImage(較大的壓縮映像,大於512KB),它是提前使用zlib進行壓縮的。在這個內核映像前面是一個例程,它實現少量硬件設置,並對內核映像中包含的內核進行解壓,然後將其放入高端內存中,如果有初始RAM磁盤映像,就會將它移動到內存中,並標明以後使用。然後此例程會調用內核,並開始啓動內核引導的過程。

在GRUB命令中,我們可以使用initrd映像引導一個特定的內核,方法如下:

grub> kernel /bzImage-2.6.14.2
    [Linux-bzImage, setup=0x1400, size=0x29672e]
    grub>initrd /initrd-2.6.14.2.img
    [Linux-initrd @ 0x5f13000, 0xcc199 bytes]
    grub> boot
    Uncompressing Linux... Ok, booting the kernel.

根據grub設定的內核映像所在路徑,系統讀取內存映像,並進行解壓縮操作。此時,屏幕一般會輸出“Uncompressing Linux”的提示。當解壓縮內核完成後,屏幕輸出“OK, booting the kernel”。 如果不知道要引導的內核的名稱,只需使用/然後按下Tab鍵,就會顯示內核和initrd映像列表。

系統將解壓後的內核放置在內存之中,並調用start_kernel()函數來啓動一系列的初始化函數並初始化各種設備,完成Linux核心環境的建立。至此,Linux內核已經建立起來了,基於Linux的程序應該可以正常運行了。

4、執行init進程

init進程是所有進程的起點,內核在完成內核引導後,即在本線程(進程)空間內加載init程序,它的進程號爲1。init進程是所有進程的發起者和控制者。因爲在任何基於Unix的系統(比如Linux)中,它都是第一個運行的進程,所以init進程的編號(Process ID,PID)永遠是1。如果init出現了問題,系統的其餘部分也就隨之而垮掉了。

init進程有兩個作用:

● 扮演終結父進程的角色:所有的孤兒進程都會被init進程接管。快速執行一下ps -af 命令,可以列出許多父進程ID(Parent Process ID,PPID)爲1的進程來。

● 進入某個特定的運行級別時運行相應的程序,以此對各種運行級別進行管理,這個作用由/etc/inittab文件定義的。 內核被加載後,第一個運行的程序便是/sbin/init,該文件會讀取/etc/inittab文件,並依據此文件來進行初始化工作。

5、通過/etc/inittab文件進行初始化

init進程的工作是根據/etc/inittab來執行相應的腳本進行系統初始化,如設置鍵盤、字體,裝載模塊,設置網絡等。其最主要的作用就是設定Linux的運行等級,其設定形式是“:id:5:initdefault:”,這就表明Linux需要運行在等級5上。Linux的運行等級設定如下:

0:關機
    1:單用戶模式
    2:無網絡支持的多用戶模式
    3:有網絡支持的多用戶模式
    4:保留,未使用
    5:有網絡支持有X-Window支持的多用戶模式
    6:重新引導系統,即重啓

對於RedHat來說,按以下順序執行:

a、執行/etc/rc.d/rc.sysinit(由init執行的第一個腳本)

在設定了運行等級後,Linux系統執行的第一個用戶層文件就是/etc/rc.d/rc.sysinit腳本程序,它做的工作非常多,包括設定PATH、設定網絡配置(/etc/sysconfig/network)、啓動swap分區、設定/proc、把root文件系統輸入到mtab、使用系統爲裝入模塊做準備、查找模塊的相關文件、檢查文件系統,以進行必要的修復、加載所有其他文件系統、清除幾個/etc文件,如/etc/mtab、/etc/fastboot和/etc/nologin、刪除UUCP的lock文件、刪除過時的子系統文件、刪除過時的pid文件、設置系統時鐘、打開交換、初始化串行端口、裝入模塊等等。如果你有興趣,可以到/etc/rc.d中查看一下rc.sysinit文件,裏面的腳本夠你看幾天的。

b、執行/etc/rc.d/rcX.d[KS]

首先終止K開頭的服務(用來關閉一個服務),然後啓動S開頭的服務(用來啓動一個服務);對每一個運行級別來說,在/etc/rc.d子目錄中都有一個對應的下級目錄。這些運行級別的下級子目錄的命名方法上rcX.d, 其中X就是代表運行級別的數字。在各個運行級別的子目錄中,都建立有到/etc/rc.d/init.d子目錄中命令腳本程序的符號鏈接。鏈接的名稱在K與S後有一個數字,表示執行順序,數字小的先執行如K01tog-pegasus  、 S00microcode_ctl。對以K開頭的腳本執行時系統會傳遞stop參數,而S開頭的腳本系統會傳遞start參數。

c、執行/etc/rc.d/rc.local

Redhat中運行模式2,3,5都把/etc/rc.d/rc.local作爲初始化腳本中的最後一個文件,所以用戶可以自己在這個文件中添加一些需要在其他初始化工作之後,登陸之前執行的命令。

你如果打開了此文件,裏面有一句話,讀過之後,你就會對此命令的作用一目瞭然:

# This script will be executed *after* all the other init scripts.
    # You can put your own initialization stuff in here if you don’t want to do the full Sys V style init stuff.

rc.local就是在一切初始化工作後,Linux留給用戶進行個性化的地方。你可以把你想設置和啓動的東西放到這裏。

6、執行/bin/login

login程序會提示使用者需輸入帳號與密碼,接着編碼並確認密碼的正確性,若二者相合,則爲使用者進行初始化環境,並將控制權交給shell,即用戶登錄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章