Linux 引導過程內幕
從主開機記錄到第一個使用者空間應用程式的指導 |
|
早期時,啟動一臺計算機意味著要給計算機喂一條包含載入程式的紙帶,或者手工使用前端皮膚地址/資料/控制開關來載入載入程式。儘管目前的計算機已經裝備了很多工具來簡化引導過程,但是這一切並沒有對整個過程進行必要的簡化。 |
|
讓我們先從高階的視角來檢視 Linux 引導過程,這樣就可以看到整個過程的全貌了。然後將回顧一下在各個步驟到底發生了什麼。在整個過程中,參考一下核心原始碼可以幫助我們更好地瞭解核心原始碼樹,並在以後對其進行深入分析。 |
|
## 概述 |
|
圖 1 是我們在 20,000 英尺的高度看到的檢視。 |
|
##### 圖 1. Linux 引導過程在 20,000 英尺處的檢視 |
|
![](https://www.ibm.com/developerworks/cn/linux/l-linuxboot/fig1.gif) |
|
當系統首次引導時,或系統被重置時,處理器會執行一個位於已知位置處的程式碼。在個人計算機(PC)中,這個位置在基本輸入/輸出系統(BIOS)中,它儲存在主機板上的快閃記憶體中。嵌入式系統中的中央處理單元(CPU)會呼叫這個重置向量來啟動一個位於快閃記憶體/ROM 中的已知地址處的程式。在這兩種情況下,結果都是相同的。因為 PC 提供了很多靈活性,BIOS 必須確定要使用哪個裝置來引導系統。稍後我們將詳細介紹這個過程。 |
|
當找到一個引導裝置之後,第一階段的引導載入程式就被裝入 RAM 並執行。這個引導載入程式在大小上小於 512 位元組(一個扇區),其作用是載入第二階段的引導載入程式。 |
|
當第二階段的引導載入程式被裝入 RAM 並執行時,通常會顯示一個動畫螢幕,並將 Linux 和一個可選的初始 RAM 磁碟(臨時根檔案系統)載入到記憶體中。在載入映像時,第二階段的引導載入程式就會將控制權交給核心映像,然後核心就可以進行解壓和初始化了。在這個階段中,第二階段的引導載入程式會檢測系統硬體、列舉系統連結的硬體裝置、掛載根裝置,然後載入必要的核心模組。完成這些操作之後啟動第一個使用者空間程式( `init`),並執行高階系統初始化工作。 |
|
這就是 Linux 引導的整個過程。現在讓我們深入挖掘一下這個過程,並深入研究一下 Linux 引導過程的一些詳細資訊。 |
|
## 系統啟動 |
|
系統啟動階段依賴於引導 Linux 系統上的硬體。在嵌入式平臺中,當系統加電或重置時,會使用一個啟動環境。這方面的例子包括 U-Boot、RedBoot 和 Lucent 的 MicroMonitor。嵌入式平臺通常都是與引導監視器搭配銷售的。這些程式位於目標硬體上的快閃記憶體中的某一段特殊區域,它們提供了將 Linux 核心映像下載到快閃記憶體並繼續執行的方法。除了可以儲存並引導 Linux 映像之外,這些引導監視器還執行一定級別的系統測試和硬體初始化過程。在嵌入式平臺中,這些引導監視器通常會涉及第一階段和第二階段的引導載入程式。 |
|
##### 提取 MBR 的資訊 |
|
要檢視 MBR 的內容,請使用下面的命令: |
|
``` |
# **dd if=/dev/hda of=mbr.bin bs=512 count=1** |
# **od -xa mbr.bin** |
``` |
|
這個 `dd` 命令需要以 root 使用者的身份執行,它從 /dev/hda(第一個 IDE 盤) 上讀取前 512 個位元組的內容,並將其寫入 `mbr.bin`檔案中。 `od` 命令會以十六進位制和 ASCII 碼格式列印這個二進位制檔案的內容。 |
|
在 PC 中,引導 Linux 是從 BIOS 中的地址 0xFFFF0 處開始的。BIOS 的第一個步驟是加電自檢(POST)。POST 的工作是對硬體進行檢測。BIOS 的第二個步驟是進行本地裝置的列舉和初始化。 |
|
給定 BIOS 功能的不同用法之後,BIOS 由兩部分組成:POST 程式碼和執行時服務。當 POST 完成之後,它被從記憶體中清理了出來,但是 BIOS 執行時服務依然保留在記憶體中,目標作業系統可以使用這些服務。 |
|
要引導一個作業系統,BIOS 執行時會按照 CMOS 的設定定義的順序來搜尋處於活動狀態並且可以引導的裝置。引導裝置可以是軟盤、CD-ROM、硬碟上的某個分割槽、網路上的某個裝置,甚至是 USB 快閃記憶體。 |
|
通常,Linux 都是從硬碟上引導的,其中主開機記錄(MBR)中包含主引導載入程式。MBR 是一個 512 位元組大小的扇區,位於磁碟上的第一個扇區中(0 道 0 柱面 1 扇區)。當 MBR 被載入到 RAM 中之後,BIOS 就會將控制權交給 MBR。 |
|
## 第一階段引導載入程式 |
|
MBR 中的主引導載入程式是一個 512 位元組大小的映像,其中包含程式程式碼和一個小分割槽表(參見圖 2)。前 446 個位元組是主引導載入程式,其中包含可執行程式碼和錯誤訊息文字。接下來的 64 個位元組是分割槽表,其中包含 4 個分割槽的記錄(每個記錄的大小是 16 個位元組)。MBR 以兩個特殊數字的位元組(0xAA55)結束。這個數字會用來進行 MBR 的有效性檢查。 |
|
##### 圖 2. MBR 剖析 |
|
![](https://www.ibm.com/developerworks/cn/linux/l-linuxboot/fig2.gif) |
|
主引導載入程式的工作是查詢並載入次引導載入程式(第二階段)。它是透過在分割槽表中查詢一個活動分割槽來實現這種功能的。當找到一個活動分割槽時,它會掃描分割槽表中的其他分割槽,以確保它們都不是活動的。當這個過程驗證完成之後,就將活動分割槽的引導記錄從這個裝置中讀入 RAM 中並執行它。 |
|
## 第二階段引導載入程式 |
|
次引導載入程式(第二階段引導載入程式)可以更形象地稱為核心載入程式。這個階段的任務是載入 Linux 核心和可選的初始 RAM 磁碟。 |
|
##### GRUB 階段引導載入程式 |
|
`/boot/grub` 目錄中包含了 `stage1`、 `stage1.5` 和 `stage2` 引導載入程式,以及很多其他載入程式(例如,CR-ROM 使用的是 `iso9660_stage_1_5`)。 |
|
在 x86 PC 環境中,第一階段和第二階段的引導載入程式一起稱為 Linux Loader(LILO)或 GRand Unified Bootloader(GRUB)。由於 LILO 有一些缺點,而 GRUB 克服了這些缺點,因此下面讓我們就來看一下 GRUB。(有關 GRUB、LILO 和相關主題的更多內容,請參閱本文後面的 [ 參考資料](https://www.ibm.com/developerworks/cn/linux/l-linuxboot/#artrelatedtopics) 部分的內容。) |
|
關於 GRUB,很好的一件事情是它包含了有關 Linux 檔案系統的知識。GRUB 不像 LILO 一樣使用裸扇區,而是可以從 ext2 或 ext3 檔案系統中載入 Linux 核心。它是透過將兩階段的引導載入程式轉換成三階段的引導載入程式來實現這項功能的。階段 1 (MBR)引導了一個階段 1.5 的引導載入程式,它可以理解包含 Linux 核心映像的特殊檔案系統。這方面的例子包括 `reiserfs_stage1_5`(要從 Reiser 日誌檔案系統上進行載入)或 `e2fs_stage1_5`(要從 ext2 或 ext3 檔案系統上進行載入)。當階段 1.5 的引導載入程式被載入並執行時,階段 2 的引導載入程式就可以進行載入了。 |
|
當階段 2 載入之後,GRUB 就可以在請求時顯示可用核心列表(在 `/etc/grub.conf` 中進行定義,同時還有幾個軟符號連結 `/etc/grub/menu.lst` 和 `/etc/grub.conf`)。我們可以選擇核心甚至修改附加核心引數。另外,我們也可以使用一個命令列的 shell 對引導過程進行高階手工控制。 |
|
將第二階段的引導載入程式載入到記憶體中之後,就可以對檔案系統進行查詢了,並將預設的核心映像和 `initrd` 映像載入到記憶體中。當這些映像檔案準備好之後,階段 2 的引導載入程式就可以呼叫核心映像了。 |
|
## 核心 |
|
##### GRUB 中的手工引導 |
|
在 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. |
|
如果您不知道要引導的核心的名稱,只需使用斜線(/)然後按下 Tab 鍵即可。GRUB 會顯示核心和 `initrd` 映像列表。 |
|
當核心映像被載入到記憶體中,並且階段 2 的引導載入程式釋放控制權之後,核心階段就開始了。核心映像並不是一個可執行的核心,而是一個壓縮過的核心映像。通常它是一個 zImage(壓縮映像,小於 512KB)或一個 bzImage(較大的壓縮映像,大於 512KB),它是提前使用 zlib 進行壓縮過的。在這個核心映像前面是一個例程,它實現少量硬體設定,並對核心映像中包含的核心進行解壓,然後將其放入高階記憶體中,如果有初始 RAM 磁碟映像,就會將它移動到記憶體中,並標明以後使用。然後該例程會呼叫核心,並開始啟動核心引導的過程。 |
|
當 bzImage(用於 i386 映像)被呼叫時,我們從 `./arch/i386/boot/head.S` 的 `start` 彙編例程開始執行(主要流程圖請參看圖 3)。這個例程會執行一些基本的硬體設定,並呼叫 `./arch/i386/boot/compressed/head.S` 中的 `startup_32` 例程。此例程會設定一個基本的環境(堆疊等),並清除 Block Started by Symbol(BSS)。然後呼叫一個叫做 `decompress_kernel` 的 C 函式(在 `./arch/i386/boot/compressed/misc.c` 中)來解壓核心。當核心被解壓到記憶體中之後,就可以呼叫它了。這是另外一個 `startup_32` 函式,但是這個函式在 `./arch/i386/kernel/head.S` 中。 |
|
在這個新的 `startup_32` 函式(也稱為清除程式或程式 0)中,會對頁表進行初始化,並啟用記憶體分頁功能。然後會為任何可選的浮點單元(FPU)檢測 CPU 的型別,並將其儲存起來供以後使用。然後呼叫 `start_kernel` 函式(在 `init/main.c` 中),它會將您帶入與體系結構無關的 Linux 核心部分。實際上,這就是 Linux 核心的 `main` 函式。 |
|
##### 圖 3. Linux 核心 i386 引導的主要函式流程 |
|
![](https://www.ibm.com/developerworks/cn/linux/l-linuxboot/fig3.gif) |
|
透過呼叫 `start_kernel`,會呼叫一系列初始化函式來設定中斷,執行進一步的記憶體配置,並載入初始 RAM 磁碟。最後,要呼叫 `kernel_thread`(在 `arch/i386/kernel/process.c` 中)來啟動 `init` 函式,這是第一個使用者空間程式(user-space process)。最後,啟動空任務,現在排程器就可以接管控制權了(在呼叫 `cpu_idle` 之後)。透過啟用中斷,搶佔式的排程器就可以週期性地接管控制權,從而提供多工處理能力。 |
|
在核心引導過程中,初始 RAM 磁碟( `initrd`)是由階段 2 引導載入程式載入到記憶體中的,它會被複制到 RAM 中並掛載到系統上。這個 `initrd` 會作為 RAM 中的臨時根檔案系統使用,並允許核心在沒有掛載任何物理磁碟的情況下完整地實現引導。由於與外圍裝置進行互動所需要的模組可能是 `initrd` 的一部分,因此核心可以非常小,但是仍然需要支援大量可能的硬體配置。在核心引導之後,就可以正式裝備根檔案系統了(透過 `pivot_root`):此時會將 `initrd` 根檔案系統解除安裝掉,並掛載真正的根檔案系統。 |
|
##### decompress_kernel 輸出 |
|
函式 `decompress_kernel` 就是顯示我們通常看到的解壓訊息的地方: |
|
Uncompressing Linux... Ok, booting the kernel. |
|
`initrd` 函式讓我們可以建立一個小型的 Linux 核心,其中包括作為可載入模組編譯的驅動程式。這些可載入的模組為核心提供了訪問磁碟和磁碟上的檔案系統的方法,併為其他硬體提供了驅動程式。由於根檔案系統是磁碟上的一個 *檔案系統*,因此 `initrd` 函式會提供一種啟動方法來獲得對磁碟的訪問,並掛載真正的根檔案系統。在一個沒有硬碟的嵌入式環境中, `initrd` 可以是最終的根檔案系統,或者也可以透過網路檔案系統(NFS)來掛載最終的根檔案系統。 |
|
## Init |
|
當核心被引導並進行初始化之後,核心就可以啟動自己的第一個使用者空間應用程式了。這是第一個呼叫的使用標準 C 庫編譯的程式。在此之前,還沒有執行任何標準的 C 應用程式。 |
|
在桌面 Linux 系統上,第一個啟動的程式通常是 `/sbin/init`。但是這不是一定的。很少有嵌入式系統會需要使用 `init` 所提供的豐富初始化功能(這是透過 `/etc/inittab` 進行配置的)。在很多情況下,我們可以呼叫一個簡單的 shell 指令碼來啟動必需的嵌入式應用程式。 |
|
## 結束語 |
|
與 Linux 本身非常類似,Linux 的引導過程也非常靈活,可以支援眾多的處理器和硬體平臺。最初,載入引導載入程式提供了一種簡單的方法,不用任何花架子就可以引導 Linux。LILO 引導載入程式對引導能力進行了擴充,但是它卻缺少檔案系統的感知能力。最新一代的引導載入程式,例如 GRUB,允許 Linux 從一些檔案系統(從 Minix 到 Reise)上進行引導。 |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7970627/viewspace-2680246/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux的引導過程與服務控制Linux
- 引導過程與服務控制
- 計算機系統引導過程計算機
- 第十五單元-Linux系統中引導過程及修復Linux
- springboot引導上下文載入過程和配置載入過程Spring Boot
- Caffeinated 6.828:實驗 1:PC 的引導過程
- Linunx系統引導過程及MBR/GRUB故障
- linux引導和服務Linux
- TiDB 技術內幕 - 談排程TiDB
- Linux 開機引導和啟動Linux
- Linux與Windows雙引導風險LinuxWindows
- mysql儲存過程的引數MySql儲存過程
- Linux 啟動過程分析Linux
- linux呼叫儲存過程Linux儲存過程
- 物件導向和麵向過程物件
- android通過MediaProjection獲取螢幕內容AndroidProject
- 通過 Grub 來引導啟動 UBUNTUUbuntu
- 中介軟體的引數解析過程
- Linux系統啟動過程Linux
- Linux核心Kernel啟動過程Linux
- 北航OS課程筆記--二、系統引導筆記
- 在Linux上建立Windows 10可引導USBLinuxWindows
- DG配置過程中的引數解釋
- 詳解Linux 程式編譯過程Linux編譯
- 《深入分析Java Web技術內幕》讀書筆記 - 第1章 深入Web請求過程JavaWeb筆記
- 透過 Chrome 深入理解瀏覽器導航過程Chrome瀏覽器
- 機器學習導圖系列(3):過程機器學習
- Python之物件導向和麵向過程Python物件
- 《妖精的尾巴:魔導少年》UI優化推導全過程UI優化
- Linux 修改核心啟動預設引導順序Linux
- 【Linux】grub命令列引導進入windows系統Linux命令列Windows
- Linux TCP/IP協議棧全過程LinuxTCP協議
- 談談本人學Linux的小過程Linux
- Linux的啟動過程及init程式Linux
- 使用python遠端操作linux過程解析PythonLinux
- 物件導向和麵向過程的區別物件
- .NET WEB API關鍵過程 思維導圖WebAPI
- Git 內幕(一)Git