Linux系統啓動

本文主要介紹了Linux系統啓動流程相關內容

一、概覽

開機實際上是一件很複雜的事情,該動作的主要目的就是讓冷冰冰的機器幫助我們完成需要的工作。本文所介紹的,只是Linux系統的大致啓動過程

需要說明的是,近年來從底層的BIOS到上層的init程序都有了一些變化,而系統啓動的大致原理依舊,本章節先以“BIOS”來表示Legacy BIOS與UEFI,以GRUB表示引導程序,以INIT來表示各init程序……,大致說明系統啓動過程,後面的章節將分別介紹之

Linux啓動大致過程如下

BIOS
Boot Loader
Kernel
INIT

我們知道,計算機只有在CPU加載到指令後才能根據指令完成工作,而其加載的指令存在於RAM(Random Access Memory,隨機訪問存儲器),即我們當前用作內存的介質,而該設備斷點後將無法保存數據,那麼此時指令從何而來?

Linux系統初識-計算機體系結構中有介紹過,我們需要外部存儲設備來幫助持久保存數據。該設備即外存或輔儲,一般使用HDD或SSD爲介質

而這就需要在開機時將外存中的指令讀取到內存,而後加載到CPU,而這個動作本身,也是需要指令來完成的!這該如何進行?

這就需要計算機有“自舉”能力,現代計算機的設計中,在我們按下電源鍵後,主板將會把一段存儲在特殊存儲器上的代碼傳入CPU中,注意,該動作使用硬件邏輯完成的,不需要指令的參與,就像我們打開電燈開關,燈就會亮一樣

這段代碼我們將其稱之爲BIOS(Basic Input/Output System,基本輸入輸出系統),他主要負責探測硬件(POST(Power On Self Test,加電自檢))、選擇啓動設備

當上述操作無誤後,BIOS將選擇的設備中的代碼載入CPU,即Boot Loader,用於引導分區上的操作系統,在此處由於分區表類型不同稍有差異

對於完全支持UEFI引導:
UEFI
Boot Loader
Kernel
INIT
對於BIOS引導:
BIOS
Boot Loader
Grub
Kernel
INIT

由於BIOS本身不能識別文件系統,故要使用其他機制輔助,事實上,上圖對於BIOS的引導中,Boot Loader代碼也屬於Grub程序,而使用UEFI的引導中,Boot Loader即Grub,不同之處下文將詳細介紹,爲了方便敘述,本文的章節劃分按照上圖BIOS引導的架構

而後通過Grub實現從當前物理存儲設備選擇所啓動的操作系統,以及內核所在位置與相關啓動特性

上述操作完成後,根據Grub中指定的內核與相關參數啓動Kernel,在Kernel中啓動用戶空間的第一個進程,即init程序,至此,系統啓動完成

事實上init程序啓動後,還會有一些相關配置,此處沒有列出,下文將詳細介紹

二、BIOS

該過程是計算機加電之後運行的第一段程序,如今,UEFI即將全面取代BIOS,通常,我們將該程序稱爲固件(Firmware),負責硬件檢測,以及爲操作系統提供運行時服務

1. BIOS

BIOS(Basic Input/Output System,基本輸入輸出系統)固件安裝在PC的主板(Motherboard)上的獨立存儲器中,早期位於ROM(Read Only Memory,只讀存儲器)中,不可更改,後來位於閃存(Flash Memory)中(常爲EEPROM),帶來的好處是可以在不從主板上移除芯片的情況下重寫它,這允許對BIOS固件進行簡單的最終用戶更新,從而可以添加新功能或修復錯誤

通常,我們也將存儲BIOS的儲存器稱爲BIOS芯片

主要功能

  1. BIOS中斷服務程序實質上是軟件與硬件之間的一個可編程接口,主要用於程序軟件功能與硬件之間連接。例如,系統對光驅、硬盤等管理,中斷的設置等

  2. BIOS系統設置程序:BIOS提供一個“系統設置程序”,主要來設置系統底層的各項參數,如系統的基本情況、CPU特性、軟硬盤驅動器等部件的信息,該程序在開機時按某個鍵就可進入設置狀態

  3. POST:接通電源後,系統首先由POST(Power On Self Test,加電自檢)程序來對內部各個設備進行檢查。通常完整的POST自檢將包括對CPU、640K基本內存、1M以上的擴展內存、ROM、等進行測試,一旦在自檢中發現問題,系統將給出提示信息或鳴笛警告,其測試流程如下1

    引導系統重置REST引導CPU。
    CPU指向BIOS自我測試的地址FFFFOH並打開CPU運行第一個指令。
    CPU內部寄存器的測試。
    CMOS 146818 SRAM檢查。
    ROM BIOS檢查碼測試。
    8254計時/計數器測試。
    8237 DMA控制器測試。
    74612頁寄存器測試。
    REFRESH刷新電路測試。
    8042鍵盤控制器測試。
    DRAM 64KB基本存儲器測試。
    CPU保護模式的測試。
    8259中斷控制器的測試。
    CMOS 146818電力及檢查碼檢查。
    DRAM IMB以上存儲器檢查。
    顯卡測試。
    NMI強制中斷測試。
    8254計時/計數器聲音電路測試。
    8254計時/計數器計時測試。
    CPU保護模式SHUT DOWN測試。
    CPU回至實模式(REAL MODE)。
    鍵盤鼠標測試。
    8042鍵盤控制器測試。
    8259中斷控制器IRQ0至IRQ18建立。
    磁盤驅動器及界面測試。
    設置並行打印機及串列RS232的界面。
    檢查CMOS IC時間、日期。
    檢查完成

  1. BIOS系統啓動自舉程序:系統完成POST自檢後,BIOS就首先按照系統CMOS設置中保存的啓動順序搜索軟硬盤驅動器及CD-ROM,網絡服務器等有效地啓動驅動器,讀入操作系統引導記錄,然後將系統控制權交給引導記錄,並由引導記錄來完成系統的順序啓動

CMOS與BIOS

很多人對二者傻傻分不清,這裏說明一下

BIOS是一段程序,存位於EEPROM(Electrically-Erasable Programmable Read-Only Memory,電可擦除可編程只讀存儲器),是一種可以通過電子方式多次複寫的半導體存儲設備,可以用特定的電壓,來抹除芯片上的信息,以便寫入新的數據(注意,早期的BIOS並非如此,上文有介紹)

而BIOS設置的配置記錄放在CMOS(Complementary Metal Oxide Semiconductor,互補金屬氧化物半導體)芯片中,該芯片屬於RAM,斷點後數據將丟失

故主板上有一塊電池,爲該存儲器供電,若取出電池,則可重置這些信息,如BIOS密碼、啓動次序、時間等

Boot Sequence

在BIOS提供的配置頁面中,提供了讓用戶選擇啓動次序(Boot Sequence)的接口,如下圖

Boot_Sequence

上圖爲VMware Workstation 15的BIOS界面,實際界面樣式因不同主板或BIOS程序而異,然意義相同

配置啓動設備後,BIOS工作完成後將根據這裏配置的順序從對應設備中尋找啓動代碼,即查看該設備首512字節是否是以0x55 0xAA結尾,若不是,則認爲該設備無啓動能力,繼續尋找下一個設備,否則加載該代碼,控制權移交至該代碼,BIOS工作完成

可參看Linux存儲管理相關內容

2. UEFI

UEFI(Unified Extensible Firmware Interface,統一可擴展固件接口)是一種個人計算機系統規格,用來定義操作系統與系統固件之間的軟件界面,作爲BIOS的替代方案

概述

UEFI的前身是Intel在1998年開始開發的Intel Boot Initiative,後來被重命名爲可擴展固件接口(Extensible Firmware Interface,縮寫EFI)。Intel在2005年將其交由統一可擴展固件接口論壇(Unified EFI Forum)來推廣與發展,爲了凸顯這一點,EFI也更名爲UEFI(Unified EFI)。UEFI論壇的創始者是11家知名計算機公司,包括Intel、IBM等硬件廠商,軟件廠商Microsoft,及BIOS廠商AMI(英語:American Megatrends)、Insyde及Phoenix

目前的最新版本爲UEFI-2.7A2

UEFI在概念上非常類似於一個小型的操作系統,並且具有操控所有硬件資源的能力,而其一些特性與操作系統有着本質區別

  • 它只是硬件和預啓動軟件間的接口規範

  • UEFI環境下不提供中斷的機制,也就是說每個EFI驅動程序必須用輪詢(polling)的方式來檢查硬件狀態,並且需要以解釋的方式運行,較操作系統下的機械碼驅動效率更低

  • UEFI系統不提供複雜的緩存器保護功能,它只具備簡單的緩存器管理機制,具體來說就是指運行在x64或x86處理器的64位模式或保護模式下,以最大尋址能力爲限把緩存器分爲一個平坦的段(Segment),所有的程序都有權限訪問任何一段位置,並不提供真實的保護服務

UEFI

UEFI的組成

x64計算機平臺的UEFI通常包含以下幾個部分:3

  • Pre-EFI初始化模塊
  • EFI驅動程序執行環境(DXE)
  • EFI驅動程序
  • 兼容性支持模塊(CSM)
  • EFI應用程序
  • GUID磁盤分區表

在實現中,統一可擴展固件接口(UEFI)初始化模塊和驅動執行環境通常被集成在一個只讀存儲器中(多爲NVRAM

Pre-EFI初始化程序在系統開機的時候最先得到執行,完成存儲器的初始化工作,然後加載UEFI DXE(驅動程序執行環境)

當DXE被加載運行時,系統便具有了枚舉並加載其他UEFI驅動程序的能力。在基於PCI Express架構的x64計算機系統中,系統會加載UEFI內置的驅動程序模塊,完成UEFI固件、CPU、存儲器、芯片組及主板的進一步初始化,然後初始化各PCIe控制器、PCIe適配器(如RAID擴展卡或顯卡)及芯片組內置PCIe適配器(如芯片組內置的SATA、USB、網卡等功能)並加載這些PCIe設備的UEFI驅動程序(如果有的話,也有可能是加載PCIe設備的Legacy Option ROM)

UEFI驅動程序不僅可以包含在PCIe適配器的ROM中(作爲PCIe設備的UEFI Option ROM),還可以以.EFI文件的形式被方便的加載

在UEFI規範中,一種突破傳統MBR磁盤分區結構限制的GUID磁盤分區系統(GPT)被引入,新結構中,磁盤的主分區數不再受限制(在MBR結構下,只能存在4個主分區),另外UEFI+GPT磁盤分割表結合還可以支持2.1 TB以上硬盤,並且分區類型將由GUID來表示

GPT磁盤分區表的硬盤可包含EFI系統分區(ESP),EFI系統分區(ESP)可以被UEFI固件訪問,可用於存放操作系統的引導程序、EFI應用程序(如OEM的備份程序和硬件診斷程序)等等

EFI系統分區採用FAT文件系統,在Windows操作系統下默認在“本機”中隱藏。UEFI固件通過運行EFI系統分區中的引導程序文件(擴展名爲.EFI的UEFI應用程序)引導操作系統。CSM是在x86平臺UEFI系統中的一個特殊的模塊,它將爲不具備UEFI引導能力的操作系統以及16位的傳統Option ROM(即非EFI的Option ROM)提供類似於傳統BIOS的系統服務

Secure Boot功能要求原生UEFI(即關閉CSM),因此在UEFI固件設置中打開CSM前,需要在UEFI固件設置中關閉Secure Boot

下圖爲

UEFI

引導

UEFI啓動

與BIOS不同,UEFI不依賴於引導扇區,而是將引導管理器定義爲UEFI規範的一部分。當計算機啓動時,啓動管理器會檢查啓動配置並根據其設置加載到內存中,然後執行指定的OS加載程序或操作系統內核。引導配置由存儲在NVRAM中的變量定義,包括指示OS加載器和OS內核的文件系統路徑的變量

UEFI可以自動檢測OS加載程序,從而可以從USB閃存驅動器等可移動設備輕鬆啓動。這種自動檢測依賴於到OS加載器的標準化文件路徑,路徑根據計算機體系結構而變化

從GPT分區磁盤引導UEFI系統通常稱爲UEFI-GPT引導。儘管UEFI規範要求完全支持MBR分區表[28],但某些UEFI固件實現會立即切換到基於BIOS的CSM引導,具體取決於引導磁盤分區表的類型,從而有效防止UEFI引導從MBR分區磁盤上的EFI系統分區。這樣的引導方案通常被稱爲UEFI-MBR

引導管理器通常具有文本用戶界面,因此用戶可以從可用引導選項列表中選擇所需的OS(或系統實用程序)

CSM啓動

爲了確保向後兼容性,PC級機器上的大多數UEFI固件實現還支持從MBR分區磁盤通過傳統BIOS模式啓動,通過提供傳統BIOS兼容性的兼容性支持模塊(CSM)。在這種情況下,通過忽略分區表並依賴引導扇區的內容,以與基於BIOS的傳統系統相同的方式執行引導

從MBR分區磁盤啓動BIOS樣式通常稱爲BIOS-MBR,無論是在UEFI還是基於BIOS的傳統系統上執行。此外,還可以從GPT磁盤啓動傳統的基於BIOS的系統,並且這種啓動方案通常稱爲BIOS-GPT

在兼容性支持模塊允許傳統的操作系統和一些選項ROM仍然使用不支持UEFI。它還提供了所需的傳統系統管理模式(SMM)功能,稱爲CompatibilitySmm,作爲UEFI SMM提供的功能的補充。這是可選的,高度芯片組和平臺特定。這種傳統SMM功能的一個示例是通過模擬其經典的PS / 2對應物,爲鍵盤和鼠標提供USB傳統支持

該方案作爲目前UEFI與BIOS的過度階段的緩衝,英特爾宣佈計劃到2020年逐步停止對CSM的支持

UEFI與BIOS在啓動過程上的區別

UEFI啓動過程

UEFI_Boot

對應到UEFI個模塊爲,如下圖。事實上,左半部分中,SEC,PEI,DXE稱之爲PI(Platform Initialization)規範,UEFI純粹地是一個接口規範,它不會具體涉及平臺固件是如何實現的。“如何實現”這一內容是PI要解決的問題

BDS,TSL,和RT一起,屬於UEFI規範

UEFI_Boot

SEC階段
SEC階段內存尚未被初始化,故UEFI將CPU緩存作爲內存使用,即Cache As RAM
PEI階段
和BIOS的初始化階段類似,PEI階段用以喚醒CPU及內存初始化。PEI用SEC設置好的Cache As RAM,執行一些PEIM(初始化模塊),用於初始化一些硬件
DXE階段:
DXE的主要功能在加載驅動。此階段所有的內存、CPU、PCI、USB、SATA和Shell等都會被初始化
BDS階段:
在BDS(引導設備選擇)階段,它負責執行所有符合UEFI驅動模型(UEFI driver model)的驅動。這是一個發現並一個個連接的過程,一個個啓動設備被發現,其設備路徑(device path)也被連接起來。在萬事俱備後,一個界面被顯示出來(嵌入式系統上可以沒有),供用戶進行設置和選擇啓動設備,這就是大家熟悉的BIOS界面,用戶可以自開機管理者程序頁,選擇要從哪個偵測到的開機設備來啓動
TSL階段:
然後進入TSL(短暫系統載入)階段,由操作系統接手開機。除此之外,也可以在BDS階段選擇UEFI Shell,讓系統進入命令列,進行基本診斷和維護

BIOS啓動過程

BIOS啓動過程較爲簡單,一下做大致介紹

  1. 初始化

    系統加電,CPU會自行重置爲初始狀態。BIOS boot block初始化階段啓動,此時內存尚未初始化,沒有內容可以執行,所以廠商讓CPU去尋找系統BIOS ROM中的reset vector(重置向量) :用一個固定的位置來啓動所謂的BIOS boot program

    一般來說程序會在內存的FFFF0h處,也就是在UMA(上層記憶區域)靠結尾的地方。爲避免ROM大小改變造成兼容問題,所以一般會選擇放這裏。它的內容只有一個jump指令,進一步跳到真正的BIOS啓動程序

    各家IBV (independent BIOS vender;獨立BIOS供應商)可以放在不同的位置,只要通過jump來指定即可

    在該階段,系統的CPU、芯片組、Super I/O和USB只有部分初始化,僅獲取足夠信息來應付萬一BIOS開機失敗,可以利用其他儲存設備來救援BIOS的boot block

  2. POST

    然後BIOS開始施行POST,它通常被放在內存C0000h處,作用是顯卡的初始化,而大部分的顯示卡都會在顯示器上顯示其相關訊息。這就是爲何各位在開機的時候,首先會在顯示器的畫面左上角出現有關顯示卡訊息的原因。

    下一步BIOS會顯示啓動畫面,並開始更深入的檢測,如果這時候遇到任何錯誤,就會在畫面上顯示錯誤消息

  3. 記錄系統的配置

    此時BIOS會對系統進行進一步的確認,看看你的電腦究竟安裝了那些系統資源或設備。有些電腦會逐步顯示這些被偵測到的設備,例如BIOS支持隨插即用,那它將會偵測和配置隨插即用裝置,並顯示由BIOS偵測到的隨插即用設備

    在這些檢測結束後,BIOS會打出一個總結表於畫面上。而這個總結表在部分IBV的設定中是可以讓使用者開啓或關閉的。當然也有些IBV爲加速開機把這一步直接隱藏省略

  4. 提供常駐程序
    提供操作系統或應用程序調用的中斷向量,如INT 10h(VGA圖形及文字輸出中斷)等
  5. 加載系統
    到這裏是系統檢測的部分,接下來BIOS便開始尋找引導設備,用戶可以通過在BIOS的設定來決定搜尋順序

總結

此處將UEFI與BIOS的引導方式總結如下

BIOS

BIOS只認識設備,不認識分區、不認識文件

啓動過程:根據CMOS中保存的順序,查看存儲設備,其前512字節是不是以0x55 0xAA結尾?若是則執行這段代碼,完成

UEFI

UEFI認識設備,還認識設備ROM,還認識分區表、認識文件系統以及文件

啓動過程:經過一系列初始化後,按照設置裏的順序尋找啓動項,一般有兩種類型

  • 文件啓動項,大約記錄的是某個磁盤的某個分區的某個路徑下的某個文件。對於文件啓動項,固件會直接加載這個EFI文件,並執行
  • 設備啓動項,大約記錄的就是“某個U盤”、“某個硬盤”。(此處只討論U盤、硬盤)對於設備啓動項,UEFI標準規定了默認的路徑“\EFI\Boot\bootX64.efi”。UEFI會加載磁盤上的這個文件。文件不存在則失敗

UEFI-2以後,新增了SecureBoot功能。開了SecureBoot之後,主板會驗證即將加載的efi文件的簽名,如果開發者不是受信任的開發者,就會拒絕加載

三、Boot Loader

事實上在UEFI+GPT的引導方式下無需該步驟,從上文可看出,若使用該方式引導,由於UEFI可直接識別文件系統,在BDS階段選擇操作系統後即可進入下一步

本章主要介紹沒有使用GPT分區表或GPT分區表不被識別的情況,如

  • BISO+MBR
  • UEFI+MBR
  • BIOS+GPT

此處糾正一個問題,很多人認爲BIOS+GPT無法引導,其實是可以的,上文已有介紹,GPT分區中LBA0位MBR兼容區。只是由於微軟在默認情況下不允許Windows操作系統通過BIOS引導GPT分區而已

然而我們也可以經過配置是的Windows在BIOS+GPT方式下啓動,chainloader指定ESP中的bootmgfw.efi即可

故對於BIOS與UEFI、BMR與GPT,其各種組合都是可以引導的,即

  • BISO+MBR
  • UEFI+MBR
  • BIOS+GPT
  • UEFI+GPT

若使用UEFI+MBR,則需要使用CSM,即打開兼容性支持模塊,如此,UEFI將會讀取MBR中的代碼,這段過程與BIOS+MBR基本無異

當BIOS(或使用SCM的UEFI)選擇到指定的啓動設備後,由於它不能識別文件系統,故將讀取選擇設備的首部446字節,這是一段代碼,即Boot Loader(引導加載器),由於代碼較爲簡短,無法執行復雜功能,故其主要用於將執行流執行另一部分

前面已經提及,Boot Loader爲Grub的一部分(第一部分),而上面指向的另一部分即Grub的第二部分

可參考Linux存儲管理-MBR相關內容

四、GRUB

1. Boot Loader

嚴格來講,該章節應該交Boot Loader,而由於上一章MBR中佔用,且如今Grub爲最著名的Boot Loader程序,此處將其命名爲GRUB

這裏對Boot Loader程序做簡要說明,該程序用於接管BIOS/UEFI交過來的控制系統權,用於加載系統內核

對於Windows,該程序爲ntloader,nt即New Technology,而Windows中更新的Boot Loader程序爲Windows Boot Manager

對於Linux平臺,有兩種較爲常見

  • LILO,即LInux,LOader,Linux加載器,不能引導1024柱面(Cylinder)以後分區上的內核,故不支持大硬盤,常用於嵌入式平臺

  • GRUB,即GRand Unified Bootloader

    • Grub 0.x:Grub Legacy
    • Grub 2

2. Grub概述

事實上,我們所謂的Grub應該被稱爲GNU Grub(就像我們每次說的Linux,Stallman先生都會強調:應該是GNU Linux!)

Grub 2引入了一些更爲有效的能力:

  • 支持多種文件系統,如ext4、xfs、ntfs等

  • Grub 2可以訪問已經安裝的設備上的數據,可以直接從LAM和RAID中讀取數據

  • Grub 2使用了模塊機制,引入很多模塊,通過動態加載模塊來擴展功能,這樣允許core鏡像足夠小。

  • 支持自動解壓

  • 支持腳本語言,包括簡單的語法,如條件判斷,循環,變量和函數

  • 國際化語音,包括支持非ASCII的字符集和類似gettext的消息分類,字體,圖形控制檯等

  • 支持rescue模式,可用於系統無法引導的情況

  • Grub 2有更可靠的方法在磁盤上有多個文件系統時發現文件和目標內核,可以用命令發現系統設備編號或者是UUID

  • 有一個靈活的命令接口。如果沒有配置文件的存在,grub2會自動進入命令模式

傳統Grub在運行時由三個階段

  • Stage 1:位於MBR,用於引導Stage 2
  • Stage 1_5:位於MBR之後的扇區,爲識別內核文件所在的文件系統提供文件系統識別擴展
  • Stage 2:位於/boot分區,主要的引導工作在此完成

其中Stage 1_5非必要

3. Grub的安裝位置

這裏需要說明的文件爲

  • Boot.img:Stage 1對應的文件,MBR分區格式的磁盤中,放在MBR裏; GPT分區格式的磁盤中,放在Protective MBR中

  • Core.img:Stage 1_5對應的文件,32256字節大小。MBR分區格式的磁盤中,放在緊鄰MBR的若干扇區中;GPT分區格式的磁盤中,則放在34號扇區開始的位置(第一個分區所處的位置),而對應的GPT分區表中的第一個分區的entry被置空

  • /boot/grub:步驟2對應的文件目錄,放在系統分區或者單獨的Boot分區中

Grub程序各部分安裝的位置如圖
  • MBR分區表:
    Grub_MBR
  • GPT分區表
    GRUB_GPT

4. 啓動Kernel前的準備

在Grub加載Kernel後,Kernel將啓動init程序,以下爲./linux.init/main.c部分代碼:

static int __ref kernel_init(void *unused)
{
	kernel_init_freeable();
	/* need to finish all async __init code before freeing the memory */
	async_synchronize_full();
	free_initmem();
	mark_rodata_ro();
	system_state = SYSTEM_RUNNING;
	numa_default_policy();

	flush_delayed_fput();

	if (ramdisk_execute_command) {
		if (!run_init_process(ramdisk_execute_command))
			return 0;
		pr_err("Failed to execute %s\n", ramdisk_execute_command);
	}

	/*
	 * We try each of these until one succeeds.
	 *
	 * The Bourne shell can be used instead of init if we are
	 * trying to recover a really broken machine.
	 */
	if (execute_command) {
		if (!run_init_process(execute_command))
			return 0;
		pr_err("Failed to execute %s.  Attempting defaults...\n",
			execute_command);
	}
	if (!run_init_process("/sbin/init") ||
	    !run_init_process("/etc/init") ||
	    !run_init_process("/bin/init") ||
	    !run_init_process("/bin/sh"))
		return 0;

	panic("No init found.  Try passing init= option to kernel. "
	      "See Linux Documentation/init.txt for guidance.");
}

內核會從三出搜索該程序,若依然沒有找到,則啓動一個shell,這些程序位於/(根)下,故而此時Kernel需要有加載根文件系統的能力,而/的文件系統與/boot可以位於不同分區,加之Kernel中不可能將所有文件系統的驅動都包含,而此時需要如何訪問/

我們知道,Boot Loader程序有時需要藉助Stage 1_5階段來加載/boot所在分區的相應驅動

同樣的,將相關文件系統的驅動做成一個特定文件,在Kernel訪問/之前,先加載該文件即可

顯然,該文件需要內核能直接訪問,故其在/boot中,在CentOS 5中,該文件爲ramdisk,對應文件名一般爲initrd,而在CentOS 6之後,該文件爲ramfs,對應文件名一般爲initramfs

從名稱上可以看出,CentOS 5中通過將RAM模擬爲塊設備,而Linux的緩存機制導致將可能再次在RAM中緩存該內容,造成不必要的浪費,而ramfs本身就是一個tmpfs的內存盤,擁有最小化的設計,繞過了緩存機制,也消除了多餘的內存佔用

因此,Kernel與initrd(或initramfs)必須存儲在Boot Loader程序可以訪問的位置,並且需要將initrd(或initramfs)加載後傳遞其地址給Kernel,如此,內核即可訪問根文件系統

5 .Grub Legacy

功能

  1. 提供菜單,選擇要啓動時的內核或系統;

    • 允許傳遞參數給內核
    • 可以隱藏選擇界面
  2. 提供交互式接口

    • e:編輯模式,用於編輯菜單
    • c:命令模式,交互式接口
  3. 基於密碼的保護

    • 啓用內核映像,定義在相應的title
    • 傳遞參數,即進入編輯模式,定義在全局段中

配置文件

配置文件的讀取主要在Stage 2完成,其配置文件爲/etc/grub.conf,該文件指向/boot/grub/grub.conf,如下爲RHEL 5中的一個實例,以之爲例說明個字段意義

default=0  # 設定默認啓動的title的編號,從0開始

timeout=5  # 等待用戶選擇的內核或OS超時時長,單位:秒

splashimage=(hd0,0)/grub/splash.xpm.gz
	# 指定grub的背景圖片,gimp工具可以編輯圖片,要保存爲.xpm格式,然後使用gzip壓縮(.gz)

hiddenmenu # 隱藏菜單

password redhat # grub的密碼(明文),菜單編輯密碼

password --md5 $1$HKXJ51$B9Z8A.X//XA.AtzU1.KuG.
	# grub加密密碼,可以使用grub-md5-crypt命令來計算密碼

title Red Hat Enterprise Linux Server (2.6.18-308.el5)
	# 內核標題,或操作系統名稱,字符串,可自由修改
	root (hd0,0)
		# 內核文件所在的設備;對grub而言,所有類型硬盤一律hd,格式爲
		(hd#,N);
		# hd#, #表示第幾個磁盤;從0開始編號
		# N表示對應磁盤的分區;從0開始編號

	kernel /vmlinuz-2.6.18-308.el5 ro root=/dev/vol0/root rhgb quiet
		# 內核文件路徑,及傳遞給內核的參數,參數即/proc/cmdline中的內容

		# 參數: ro root=/path/to/DEVICE
			# 將/path/to/DEVICE所代表的設備當做內核啓動時的根,以只讀方式掛載
			# quiet:靜默模式, 內核初始化的信息不再輸出

	initrd /initrd-2.6.18-308.el5.img
		# 文件:通常爲cpio歸檔,並使用gzip壓縮,通常以.img作爲擴展名
		# ramdisk文件路徑,即臨時的根,是一個完整意義上的Linux
		# 注意:以上兩項顯示根下的文件是由於文件位於/boot/目錄,該目錄是單獨的分區,而此時沒有文件系統,遂grub直接訪問該分區
		# 若/boot沒有單獨分區,則會正常顯示

	password --md5 $1$HKXJ51$B9Z8A.X//XA.AtzU1.KuG. # 將該字段放置於所有title上面,爲全局密碼,放在某一title中,爲內核啓動密碼
title Install Red Hat Enterprise Linux 5
	root (hd0,0)
	kernel /vmlinuz-5 ks=http://172.16.0.1/workstation.cfg ksdevice=eth0 noipv6
	initrd /initrd-5
	password --md5 $1$FSUEU/$uhUUc8USBK5QAXc.BfW4m.

命令行

help:獲取幫助列表
	help KEYWORD:命令詳細幫助
	
find:查找文件
	find (hd#,N)/PATH/TO/SOMEFILE
	設定根設備後可省略設備
	
root:設定根設備
	root (hd#,N)
	
kernel:指定本次啓動使用的kernel
	kernel /PATH/TO/KERNEL_FILE
	
	額外可添加內核支持使用的cmdline參數
		init=/PATH/TO/INIT
		selinux=0
		root=/PATH/TO/ROOT
		…
	
initrd:爲選定的內核提供額外文件的ramdisk
	initrd /PATH/TO/INITRAMFS_FILE
	該文件版本需要與kernel版本完全匹配
	
boot:引導啓動選定的內核

安裝grub

可使用grub-install命令安裝grub,使用方式爲

grub-install --root-directory=DIR /dev/DISK

還可以在grub交互界面安裝:

grub> root (hd#,#)
grub> setup (hd#)
grub指定設備的方式
hd(#,#)
hd#: 磁盤編號,用數字表示;0開始編號
#: 分區編號,用數字表示; 0開始編號

手動在grub命令行接口啓動系統

grub> root (hd#,#)
grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
grub> initrd /initramfs-VERSION-RELEASE.img
grub> boot

6. Grub 2

Grub 2的軟件包名即grub2,他與Grub Legacy的區別上文已有介紹

配置文件

  • /boot/grub2/grub.cfg:啓動項配置,可由grub2-mkconfig生成

  • /etc/default/grubgrub2-mkconfig工具生成配置時的參考信息

  • /etc/grub.d/*:該目錄下主要爲一些腳本,分別配合對應grub.cfg上的各個部分

應用

查看當前默認啓動項
grub2-editenv list
設置默認啓動項
方式一:grub2-set-default
方式二:修改/etc/default/grub,修改GRUB_DEFAULT=##:該數字爲grub菜單中各啓動項的順序),而後使用grub2-mkconfig -o /boot/grub2/grub.cfg生成配置文件
安裝grub2
grub2-install [--root-directory=/PATH/TO/ROOT] [DEVICE]
	若爲UEFI,則DEVICE可省略
生成新的grub.cfg文件
grub2-mkconfig -o /boot/grub2/grub.cfg

五、Kernel

Grub工作完成後,Kernel接管控制權,在此其主要工作爲:

  1. 設備探測
  2. 驅動初始化(可能會從initrd(在redhat6中叫做initramfs)文件中裝載驅動模塊)
  3. 以只讀方式掛載根文件系統(稍後init會重新掛載文件系統)
  4. 裝載第一個進程init(PID: 1)

grub中指定的initrd(或initramfs)在此處將會用到,另外,第一個進程在CentOS 7中稱爲systemd,下一章將介紹

內核的實現中,我們介紹了當前操作系統內核實現的兩種主流方式

  • 微內核將通過各內核子系統實現管理工作,如Windows,Solaris
  • 宏內核將各種功能集於一身,Linux內核就是這種設計方式

理論上講,微內核的設計思想更爲先進,而事實上要協調好各個子系統去實現複雜管理任務,這本身也是一個非常複雜的工作

Linux內核通過將個功能分爲不同的模塊,按需動態裝卸載,這些模塊在Kernel 2.6版本以後本稱爲Kernel Object,文件名後綴爲.ko(之前爲.o

BTW,在Linux中共享庫爲Shared Object(.so 共享對象,在Windows中爲Dynamic Link Library(.dll 動態鏈接庫

Linux內核文件一般位於/boot/vmlinuz-VERSION-RELEASE,而其模塊文件爲/lib/modules/VERSION-RELEASE/,而上文介紹的ramdisk,在CentOS 5中位於/boot/initrd-VERSION-RALEASE.img,而在CentOS 6之後的版本爲/boot/initramfs-VERSION-RELEASE.img

[root@localhost ~]# ll /boot/vmlinuz-`uname -r` -h
-rwxr-xr-x. 1 root root 4.8M Mar  6  2015 /boot/vmlinuz-3.10.0-229.el7.x86_64
[root@localhost ~]# ll /lib/modules/`uname -r` -h
total 2.6M
lrwxrwxrwx.  1 root root   38 Dec 20 04:15 build -> /usr/src/kernels/3.10.0-229.el7.x86_64
drwxr-xr-x.  2 root root    6 Mar  6  2015 extra
drwxr-xr-x. 11 root root 4.0K Dec 20 04:15 kernel
-rw-r--r--.  1 root root 668K Dec 20 04:22 modules.alias
-rw-r--r--.  1 root root 644K Dec 20 04:22 modules.alias.bin
-rw-r--r--.  1 root root 1.3K Mar  6  2015 modules.block
-rw-r--r--.  1 root root 5.8K Mar  6  2015 modules.builtin
-rw-r--r--.  1 root root 7.5K Dec 20 04:22 modules.builtin.bin
-rw-r--r--.  1 root root 209K Dec 20 04:22 modules.dep
-rw-r--r--.  1 root root 304K Dec 20 04:22 modules.dep.bin
-rw-r--r--.  1 root root  339 Dec 20 04:22 modules.devname
-rw-r--r--.  1 root root  108 Mar  6  2015 modules.drm
-rw-r--r--.  1 root root  108 Mar  6  2015 modules.modesetting
-rw-r--r--.  1 root root 1.5K Mar  6  2015 modules.networking
-rw-r--r--.  1 root root  82K Mar  6  2015 modules.order
-rw-r--r--.  1 root root  165 Dec 20 04:22 modules.softdep
-rw-r--r--.  1 root root 285K Dec 20 04:22 modules.symbols
-rw-r--r--.  1 root root 356K Dec 20 04:22 modules.symbols.bin
lrwxrwxrwx.  1 root root    5 Dec 20 04:15 source -> build
drwxr-xr-x.  2 root root    6 Mar  6  2015 updates
drwxr-xr-x.  2 root root   91 Dec 20 04:15 vdso
drwxr-xr-x.  2 root root    6 Mar  6  2015 weak-updates
[root@localhost ~]# ll /boot/initramfs-`uname -r`.img -h
-rw-------. 1 root root 20M Jan 18 13:06 /boot/initramfs-3.10.0-229.el7.x86_64.img

在RHEL系列發行版中,/lib/modules/VERSION-RELEASE/中有對應內核所需的各種外圍模塊,依賴關係由內核(依賴關係文件modules.dep)處理

kernel目錄中的內容爲內核主要模塊:

目錄 說明
arch 平臺相關,驅動CPU
crypto 加密解密
drivers 驅動
fs 文件系統
kernel 內核自身的額外功能
lib
mm Memory Management,內存管理
net 網絡(不是驅動,而是網絡協議棧的實現)
sound 聲卡

另外,ramdis由於取藥提供文件系統支持,而用戶的情況有各不相同,故該文件在安裝操作系統時生成,我們亦可自行使用工具生成之:

  • CentOS 5:mkinitrd
  • CentOS 6+:mkinitrddracut

六、init

內核初始化的最後一步就是啓動 pid 爲 1 的 init 進程。這個進程是系統的第一個進程。它負責產生其他所有用戶進程

init 以守護進程方式存在,是所有其他進程的父進程

Init 系統能夠定義、管理和控制 init 進程的行爲。它負責組織和運行許多獨立的或相關的始化工作(因此被稱爲 init 系統),從而讓計算機系統進入某種用戶預訂的運行模式

僅僅將內核運行起來是毫無實際用途的,必須由 init 系統將系統代入可操作狀態。比如啓動外殼 shell 後,便有了人機交互,這樣就可以讓計算機執行一些預訂程序完成有實際意義的任務。或者啓動 X 圖形系統以便提供更佳的人機界面,更加高效的完成任務。這裏,字符界面的 shell 或者 X 系統都是一種預設的運行模式

大多數 Linux 發行版的 init 系統是和 System V 相兼容的,被稱爲 sysvinit。這是人們最熟悉的 init 系統。一些發行版如 Slackware 採用的是 BSD 風格 Init 系統,這種風格使用較少,本文不再涉及。其他的發行版如 Gentoo 是自己定製的。Ubuntu 和 RHEL 採用 upstart 替代了傳統的 sysvinit

,啓動系統的第一個進程,在RHEL系列的各個發行版中,該程序亦各不相同

  • CentOS5
    SysV init,進程串行啓動
    配置文件:/etc/inittab
  • CentOS6
    Upstart,採用D-Bus、事件驅動模型等新機制4
    配置文件:/etc/inittab, /etc/init/*.conf
  • CentOS7

    Systemd

    配置文件:/usr/lob/systemd/system/etc/systemd/system

    完全兼容SysV腳本機制,service命令依然可用,建議使用systemctl命令來控制服務5

在 Linux 主要應用於服務器和 PC 機的時代,SysVinit 運行非常良好,概念簡單清晰。它主要依賴於 Shell 腳本,這就決定了它的最大弱點:啓動太慢。在很少重新啓動的 Server 上,這個缺點並不重要。而當 Linux 被應用到移動終端設備的時候,啓動慢就成了一個大問題。爲了更快地啓動,人們開始改進 sysvinit,先後出現了 upstart 和 systemd 這兩個主要的新一代 init 系統

1. SysV init

2. Upstart init

3. systemd

七、初始化


  1. 引用自 https://zh.wikipedia.org/wiki/加電自檢 ↩︎

  2. 相關規範:http://down.51cto.com/data/2459500 ↩︎

  3. 內容來自 https://zh.wikipedia.org/wiki/統一可延伸韌體介面 ↩︎

  4. 參考資料:https://en.wikipedia.org/wiki/D-Bus ↩︎

  5. 服務相關內容後續將做介紹 ↩︎

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