1. Linux啟動過程
Linux的啟動過程是在執行多級初始化過程中啟動一個Linux的安裝,它在許多方面類似於BSD和其他Unix風格的引導過程,從中衍生出來。
引導Linux安裝設計多個階段和軟件組成,包括固件初始化,引導加載程序的執行,Linux內核映像的加載和啟動,以及各種腳本和守護程序的執行,對於這些階段和組件中的每一個,存在不同的變化和方法,例如:GRUB
、LILO
、SYSLINUX
或Loadin
可用做引導加載程序,而啟動腳本可以是傳統的init
風格,也可以通過現在的方法代替(如systemd
或upstart
)
2. 啟動過程概述
Linux啟動過程的早期階段很大程度取決於計算機體系結構,IBM PC兼容硬件是Linux常用的一種架構,在這些系統上,BIOS
起着很重要的作用,可能在其他系統上沒有精確的類似物,在以下示例中,假設使用與IBM PC
兼容的硬件:
BIOS
執行特定於實際硬件平台的啟動任務,一旦枚舉硬件並正確初始化引導所需的硬件,BIOS
就會從配置的引導設備加載並執行引導代碼。- 引導加載程序通常向用戶提供一個可能的引導選項菜單,並有一個默認選項,該選項在經過一段時間后被選中,一旦做出選擇,引導加載程序就會將內核加載到內存中,並為其提供一些參數,並賦予其控制權。
- 內核如果被壓縮,將自動解壓縮,然后,它設置系統功能,如基本硬件和內存分頁,並掉調用
start_kernel()
,它執行大部分系統設置(中斷、內存管理和其余部分、設備和驅動程序初始化等),然后它分別啟動空閑進程、調度程序和init
進程,這些進程在用戶空間執行。 init
由shell
(susv,bsd,runit)執行的腳本或二進制組件(systemd,upstart)執行的配置文件組成,init
具有特定的級別(sysv,bsd)或目標(systemd),每個級別都由特定的服務集(守護進程)組成,它們提供何種非操作系統服務和結構,並形成用戶環境,典型的服務器環境啟動Web服務器、數據庫服務和網絡- 典型的桌面環境以一和名為
display manager
的守護程序開始,該守護程序啟動一個圖形環境,該圖形環境由一個提供圖形堆棧的圖形服務器和一個提供輸入憑據和選擇會話的登陸管理器組成, 會話是一組程序,例如UI元素(頁面、桌面、小程序等),這些元素可以一起構成一個完整的桌面環境。
3. 引導加載階段
引導加載程序階段因計算機體系結構而異,由於早期階段並非特定與操作系統,所以在實際模式下執行主引導記錄(MBR
)代碼並加載第一階段引導加載程序時,將考慮啟動x86
和x86-64
體系結構的基於BIOS
的引導過程,在UEFI
系統中,可以直接執行負載,比如Linux內核,因此,不需要引導加載程序,下面是一些流行的引導加載程序的摘要:
GRUB 1
- 包括在運行時讀取公共文件系統以訪問其配置文件的邏輯,這使GRUB 1
能夠從文件系統讀取配置文件,而不是將其嵌入到MBR
中,這允許它在運行時配置並以人類可讀的格式指定磁盤和分區而不是依賴於偏移量,它還包含一個命令接口,如果GRUB
配置錯誤或損壞,它可以更容易地修復和修改GRUB
。GRUB 2
- 不同於GRUB 1
,它有兩個(可選三個)階段,能夠自動檢測各種操作系統和自動配置,第一階段加載程序(stage 1)由BIOS從主引導記錄(MBR)加載和執行,或者由分區引導扇區的另一個引導加載程序加載和執行,它的工作是發現和訪問各種文件系統,稍后可以從這些文件系統讀取配置,可選的中間階段加載器(stage 1.5)由第一階段加載器加載執行,以防第二階段加載器不是連續的,或者文件系統或硬件需要特殊處理才能訪問第二階段加載器,第二階段加載器(stage 2)最后加載,並顯示GRUB啟動菜單,允許用戶選擇操作系統或檢查和編輯啟動參數,選擇菜單項並給出可選參數后,GRUB將內核加載到內存並將控制權遞給它,GRUB 2還能夠鏈式加載另一個引導加載程序
4. 內核階段
Linux內核處理所有操作系統進程,例如內存管理、任務調度、I/O、進程間通信和整個系統控制,它分兩個階段加載,在第一階段,內核(作為壓縮的鏡像文件)被夾在到內存中並解壓縮,然后設置一些基本功能,如基本內存管理,然后最后一次將控件切換到主內核和啟動進程,一旦內核完全運行並且作為啟動的一部分,在加載和執行之后,內核尋找要運行的init進程,它(單獨地)設置用戶空間和用戶環境和最終登陸所需的進程,然后,內核本身被允許空閑,這取決來自其他進程的調用。
4.1 內核加載階段
內核通常以鏡像文件的形式加載,用zlib壓縮成zlmage或bzImage格式,它頭部的一個例程執行少量的硬件設置,將鏡像完全解壓到內存中,並在配置時記錄任何RAM磁盤,然后,它同通過 /arch/ie86/boot/head和startup_32()(用於基於x86的處理器)進程執行內核啟動
4.2 內核啟動階段
內核的啟動函數(也稱為swapper或進程0)建立內存管理(分頁表和內存分頁),檢測CPU的類型和任何附加功能,比如浮點數功能,然后通過調用start_kernel()切換到非體系結構特定的Linux內核功能
start_kernel執行各種初始化函數,他設置中斷處理(IRQ),進一步配置內存,啟動init進程(第一個用戶空間進程),然后同故宮cpu_idle()啟動空閑任務,值得注意的是,內核啟動進程還掛載了初始RAM磁盤("initrd"),該磁盤先前在引導階段作為臨時根文件系統加載,initrd允許直接從內存加載驅動程序模塊,而不依賴其他設置(例如硬盤)和訪問它們所需的驅動程序(例如SATA驅動程序),靜態編譯到內核中的一些驅動程序和initrd加載的其他驅動程序的這種分割允許使用更小的內核,稍后,通過調用pivot_root()切換根文件系統,該調用將卸載臨時根文件系統,並在訪問實際根文件系統之后使用實際根文件系統替換它,然后收回臨時根文件系統使用的內存。
因此,內核初始化設備,將引導加載程序指定的根文件系統安裝為只讀,並運行Init(/sbin/init),它被指定為系統運行的第一個進程(PID=1),內核在安裝文件系統時打印消息,它還可以選擇性地運行initrd,以允許在安裝根文件系統之前處理安裝和設備相關的問題(RAM磁盤之類的)
Red Had認為,這一階段的具體內核過程總結如下:
當內核加載時,它立即初始化和配置計算機的內存,並配置附加到系統上的各種硬件,包括所有處理器,I/O子系統和存儲設備,然后,它在內存中預定的位置查找壓縮后的initrd鏡像,對其進行解壓、掛載並加載所有必要的驅動程序,接下來,在卸載initrd磁盤鏡像並釋放磁盤鏡像占用的所有內存之前,初始化於文件系統相關的虛擬設備,比如LVM或者RAID,然后內核創建一個根分區,以只讀方式掛載根分區,並釋放任何未使用的內存,此時,內核被加載到內存中並可運行,然后,由於沒有用戶應用程序允許對系統進行有意義的輸入,因此無法對其進行太多操作,initramfs風格的引導與之類似,但與所表述的initrd引導不同。
此時,啟動中斷后,調度器可以控制系統的總體管理,提供搶占式的多任務處理,而init進程將繼續在用戶空間引導用戶環境。
5. 早期的用戶空間
initramfs,也成為早期用戶空間,從Linux內核2.5.26版本開始就提供了,其目的是替換以前內核在啟動過程中執行的盡可能更多的功能,早期用戶空間的典型用途是檢測需要哪些設備驅動程序來加載主用戶空間文件系統從臨時文件系統加載它們。
6. 初始化過程
6.1 SysV init
init是系統中所有進程的父進程,由內核執行,負責啟動所有其他進程,它是所有進程的父進程,而init的父進程已經死亡,它負責在這些進程死亡時獲取它們,由init管理的進程成為作業(jobs),由/etc/init目錄中的文件定義
init的任務時在內核完全運行之后“讓所有東西按照應有的方式運行”,本質上,它建立並操作整個用戶空間,這包括檢查和掛載文件系統,啟動必要的用戶服務,並最終在系統啟動完成時切換到用戶環境,它類似於Unix和BSD的init進程,但在某些情況下,它已經分化或定制了初始化進程。在一個標准的Linux系統中,init是用一個名為runlevel的參數執行的,該參數的值從0到6不等,該參數決定哪些子系統是可操作的,每個運行級別都有自己的腳本,這些腳本將設置或離開給定的運行級別時涉及的各種過程進行編碼,引導過程中需要引用這些腳本,init腳本通常保存在名稱為"/etc/rc..."的目錄中,init的頂層配置文件位於/etc/inittab
在系統引導期間,它檢查是否在/etc/inittab中指定了默認運行級別,如果沒有,則請求運行級別通過系統控制台進入,然后,它繼續為給定的運行級別運行所有相關的引導腳本,包括加載模塊、檢查根文件系統的完整性(根文件系統是只讀掛載的)。然后重新掛載它以實現完全的讀寫訪問,並設置網絡。
在生成指定的所有進程之后,init進入休眠狀態,並等待發生以下三種時間之一:開始結束或死亡的過程、電源故障信號或通過/sbin/telinit請求進一步更改運行級別。
6.2 Systemd
systemd的開發人員旨在替換從UNIX System V和Berkeley Software Distribution(BSD)操作系統繼承而來的Linux init系統,與init一樣,systemd也是一個守護進程,它管理其他守護進程,包括systemd,都是后台進程,Systemd是第一個啟動的守護進程(在引導期間),也是最后一個終止的守護進程(在關閉期間)
最初開發systemd的軟件工程師Lennart Poettering和Kay Sievers視圖在幾個方面超越init守護的效率,它們希望改進表示依賴關系的軟件框架,允許在系統啟動期間並行地進行更多處理,並減少shell的計算開銷。
每個守護進程的Systemd初始化指令都記錄在聲明性配置文件中,而不是shell腳本中,對於進程間通信,systemd使Unix域套接字和D-Bus對正在運行的守護進程可用,Systemd還能夠主動並行化。
以上資源摘自Wiki百科:https://en.wikipedia.org/wiki/Linux_startup_process
7. 詳細的了解
要想通透的了解linux的啟動過程,以下是必須了解的理論知識:
BIOS
(Basic Input/Output System)基本輸入輸出系統,也被稱為System BIOS,ROM BIOS或PC BIOS,是非易失性的固件使用在開機過程中執行硬件的初始化(開機啟動),並為操作系統和程序提供運行時服務。BIOS固件預安裝在個人計算機的系統板上,是第一個打開電源時運行的軟件。
大多數BIOS實現專門設計用於與特定計算機或主板模型一起使用,通過與構成互補系統芯片組的各種設備連接。最初,BIOS固件存儲在PC主板上的ROM芯片中。在現代計算機系統中,BIOS內容存儲在閃存中,因此可以在不從主板上移除芯片的情況下重寫它。這允許對BIOS固件進行簡單的最終用戶更新,從而可以添加新功能或修復錯誤,但這也會使計算機感染BIOS rootkit。
FIRMWARE
固件,就是寫入只讀存儲器中(ROM)的程序,例如計算機主板上的基本輸入/輸出系統BIOS,專業人士都叫他固件。由於早期固件芯片采用ROM設計,所以無法更改,隨着技術的不斷發展,可以使用EPROM(可擦寫可編程只讀存儲器)或EEPROM(帶電可擦可編程只讀存儲器)進行修改或升級。
POST
(Power-On Self-Test)加電自檢是在計算機或其他數字電子設備開機后立即通過固件或軟件程序執行的過程。POST的結果可以顯示在作為設備一部分的面板上,輸出到外部設備,或者存儲以供將來通過診斷工具檢索,例如自檢可能檢測到顯示器不起作用,因此可以提供指示燈或揚聲器以將錯誤代碼顯示為一系列閃爍、蜂鳴聲或嗶嗶聲...。在計算機的情況下,POST是設備的於啟動序列的一部分,如果它們成功完成,則調用引導加載程序代碼以加載操作系統。(POST是BIOS功能的一個主要部分)
Bootstrapping
(Booting)引導,是啟動計算機的過程,特別是在啟動其軟件方面,該過程涉及一系列階段,其中在每個階段加載更小,更簡單的程序,然后執行下一階段更大、更復雜的程序,引導是一系列事件。例如,當計算機開機時,計算機首先執行一個存儲在只讀存儲器(ROM)中相對小的程序,以及少量所需的數據,以訪問RAM或磁盤,並將磁盤中的"操作系統"和"數據"加載到RAM中,以進行后續的操作。啟動此序列的小程序被稱為"引導加載程序"或"引導程序",這個小程序的唯一工作是加載其他數據和程序,然后從RAM中執行。
ROM
(Read-Only Memory)只讀存儲器,是計算機和其他電子設備中使用的一種非易失性存儲器,存儲在ROM中的數據只能慢慢修改,比較困難,或者根本不可能更改,因此它主要用來存儲固件(不會經常更新的軟件)。嚴格來說,只讀存儲器是指硬連接的存儲器,制造后不能改變,在許多應用程序中,這樣的內存永遠無法更改是一個缺點,因為錯誤和安全的問題無法修復,並不能添加新特性。每個存儲程序計算機可以使用一種非易失性存儲的形式(即,在移除電源時保留其數據的存儲器)來存儲在通電時運行的初始程序(成為引導Bootstrapping)
RAM
(Random-access memory)隨機存取存儲內存,易失性存儲器:當計算機關閉時,RAM磁盤會丟失存儲的數據,除非將內存安排為備用電池電源。所謂隨機存取,旨的是存儲器中的數據被讀取或寫入時,所需要的時間與這段信息所在的位置或所寫入的位置無關,相對的,讀取或寫入順序訪問(Sequential Access)存儲設備中的信息時,其所需要的時間與位置就會有關系。它主要用來存放操作系統、各種應用程序、數據等。
根據存儲單元的工作原理不同,RAM分為靜態RAM和動態RAM。
靜態隨機存儲器(SRAM)
特點是工作速度快,只要電源不撤除,寫入SRAM的信息就不會消失,不需要刷新電路,同時在讀出時不破壞原來存放的信息,一經寫入可多次讀出,但集成度較低,功耗較大。SRAM一般用來作為計算機中的高速緩沖存儲器(Cache)
動態隨機存儲器(DRAM)
它將每一位數據存儲在集成電路內的單獨的微小電容器中。電容器可以充電或放電; 取這兩種狀態來表示的比特的兩個值,通常稱為0和1的電荷在電容器慢慢泄漏掉,所以無需干預,芯片上的數據會很快丟失,為防止這種情況,DRAM需要外部存儲器刷新電路周期性地重寫電容器中的數據,將它們恢復到原來的電荷。與不需要刷新數據的靜態隨機存取存儲器(SRAM)相比,該刷新過程是動態隨機存取存儲器的定義特征。
MBR
(Master Boot Record)主引導記錄,是一種特殊類型的引導扇區,在一開始就被划分出來,在512字節的主引導扇區中,MBR只占用了其中的446個字節,另外的64個字節交給了 DPT(Disk Partition Table硬盤分區表),最后兩個字節“55,AA”是分區的結束標志。MBR扇區可能包含用於定位活動分區並調用其卷引導記錄的代碼。MBR保存有關如何在該介質上組織包含文件系統的邏輯分區的信息,MBR還包含可執行代碼用作已安裝操作系統的加載程序。通常是將控制權交給GRUB等其他引導加載程序,或者與每個分區的卷引導記錄(VBR)一起使用。此MBR通常成為引導加載程序。MBR中分區表的組織將磁盤的最大可尋址存儲空間限制為2TiB(232x512字節),由於這種限制,基於MBR分區方案正在被新計算機中的GUID分區表(GPT)方案取代,GPT可以與MBR共存,以便為舊系統提供某種有限形式的向后兼容性。MBR不存在於非分區媒體上,例如,軟盤或閃存之類的其他存儲設備,因為這樣的媒體被視為單個分區。
GTP
(GUID Partition Table)GTPS是用於布局的標准分區表的物理計算機存儲設備,諸如硬盤驅動器或固態驅動器,使用全球唯一標識符(GUID),由於主引導記錄(MBR)分區表的限制性,它構成了同意擴展固件接口(UEFI)標准的一部分。但它也用於某些BIOS系統,它使用32位進行邏輯塊尋址(LBA)傳統的512字節磁盤扇區。
所有現代個人計算機操作系統都支持GPT。一些(包括x86架構上的macOS和Microsoft Windows)僅支持在具有EFI固件的系統上從GPT分區啟動,但FreeBSD和大多數Linux發行版可以從具有舊版BIOS固件接口和EFI的系統上的GPT分區啟動。
VBR
(Volume Boot Record)卷引導記錄,(也稱為卷引導扇區,分區引導記錄或分區引導扇區),它可以在分區數據存儲設備(如硬盤)或為分區設備(如軟盤)上找到,並包含存儲在設備其他部分的引導程序(通常,但不一定是操作系統)的機器碼。是尚未分區的數據存儲設備的第一個扇區。或在已分區設備上,它是設備上單個分區的第一個扇區,整個設備的第一個扇區是包含分區表的主引導記錄(MBR)。卷引導記錄中的代碼可以由機器的固件直接調用,也可以通過主引導記錄(MBR)或引導管理器(GRUB)中的代碼間接調用,MBR和VBR中的代碼本質上以相同的方式加載。
通過引導管理器調用VBR稱為鏈加載,將各個操作系統安裝的引導代碼的副本從VBR中復制,並存儲在硬盤文件中,在引導加載程序詢問用戶引導哪個操作系統后,從文件加載相關的VBR內容。
擴展:Windows與Linux
例如一些雙啟動系統,流行的Linux和Windows操作系統,每個都包含在自己的分區中,Windows不支持多引導系統。但是大多數的Linux安裝程序都適用於雙啟動(盡管需要一些分區知識)。但是在重新啟動時,引導加載程序將僅識別兩個操作系統中的一個,
安裝Linux引導管理器/加載程序(通常是GRUB)作為主引導記錄指向的主引導加載程序有一些優點,正確安裝Linux引導加載程序可以找到Windows操作系統,但是Windows引導管理器無法識別Linux安裝(Windows也不會與Linux文件系統交互)。
所以,通常建議將Windows安裝到第一個主分區,Windows和Linux的引導加載程序通過計算分區來識別帶有數字的分區,(注意,Windows和Linux都根據分區表中分區的順序來計算分區,這可能與磁盤上分區的順序不同)在硬盤末端添加或刪除分區將對它之前的任何分區都沒有影響,但是如果在硬盤驅動器的開頭或中間添加或和刪除分區,則后續分區的編號可能會更改,如果系統分區的編號發生更改,則需要重新配置引導加載程序,以便操作系統引導並正常進行。
必須將Windows安裝到主分區(必須是第一個分區),Linux可以安裝在硬盤驅動器上任何位置的分區中,也可以安裝到邏輯分區(擴展分區內),如果Linux安裝在擴展分區內的邏輯分區中,則它不受主分區中的更改影響。
GRUB2
GNU GRUB (GNU GRand Unified Bootloader, 通常稱為GRUB)是GNU Project的一個引導加載程序包。GRUB是參考實現了的自由軟件基金會的多引導規范,它提供了用戶的選擇來引導多個操作系統安裝在計算機上,或者選擇一個特定的內核在一個特定的操作系統的分區可用的配置。打開計算機是,BIOS會找到已配置的主要可引導設備,並從主引導記錄(MBR)加載並初始引導程序(引導加載器,即GRUB)。
GRUB的兩個主要版本是常用的:
- GRUB版本1,稱為GRUB,只在Linux發行版,其中一些仍然在使用,並支持老版本的流行,例如CentOS的 5 。
- GRUB 2是從頭開始編寫和旨在取代其前身,現在被大多數Linux發行版使用。
拿CentOS7舉例,這是我個人理解的啟動過程:
(1)引導階段
第一步:打開電源后(開機),計算機相對較笨,只能讀取部分存儲空間(ROM),由於ROM的特性,這時CPU處於只讀模式。在ROM中,存儲了一個稱為固件的小程序(BIOS),它進行加電自檢,檢測硬件等(POST),最主要的是,允許訪問其他類型的內存(硬盤或RAM)。BIOS存儲了磁盤的啟動順序,BIOS按照順序去找MBR。找到后會將MBR中的引導代碼復制到RAM中(是一個446字節的boot.img鏡像)。並轉移控制權(CPU)。MBR本身還包含一個64字節的分區表,描述了分區的大小和其他屬性。剩余的2字節用於磁盤簽名。
(此步驟稱為階段1)
第二步:由於MBR引導程序不能理解文件系統的結構,因此它必須定位core.img然后加載到RAM中,並轉移控制權。core.img代碼必須位於MBR和第一個分區之間的位置,由於歷史技術原因,第一個分區的扇區開始位置是63
,可以計算(一個扇區為512bytes),62*512=31744
,然后減去MBR占用的一個扇區31744-512=31232
,而一個core.img的大小也就26676
左右。在此注意,還有一個diskboot.img,它是core.img的第一個扇區(即整個磁盤的第二個扇區),其唯一目的是加載core.img中通用的文件系統的驅動,例如FAT,NTFS,EXT等。,這時就可以直接訪問文件系統了(/boot文件)。(此步驟為階段1.5)
第三步:core.img進入32位保護模式,然后加載/boot/grub2/i386-pc/normal.mod
,normal.mod用於解析/boot/grub2/grub.cfg
文件,可選擇加載模塊(例如,用於圖形UI)並顯示菜單。然后通過用戶的選擇(或者默認)將指定的內核加載到RAM中。並將控制權交給內核(此步驟為階段2)
(2)內核階段
加載階段:內核同通常以鏡像文件的形式加載,用zlib壓縮成zImage或bzImage格式,內核作為壓縮的鏡像文件,將解壓縮自身。
啟動階段:內核會立即初始化和配置計算機內存,並配置附加到系統上的各種硬件,包括所有處理器,I/O子系統和存儲設備。然后它在內存中預定的位置查找壓縮后的initrd(臨時根文件系統),對其進行解壓,然后內核啟動虛擬內存交換器(它是一個內核進程)並創建一個根分區,以只讀方式掛載,該initrd中包含各種可執行程序和驅動程序。然后內核創建初始用戶空間進程執行/sbin/init,這里的init其實就是/usr/lib/systemd的鏈接文件(即調用systemd,其PID為1)。等待systemd將實際的根文件系統掛載后,再將initrd這個臨時的根文件系統卸載。
在Centos7的/boot文件中有一個initrd-plymouth.img鏡像文件,你可以解壓看看:
[root@www ~]# cp /boot/initrd-plymouth.img ./initrd.img.gz [root@www ~]# gunzip initrd.img.gz [root@www ~]# cpio -i -d < initrd.img 2663 blocks [root@www ~]# ls bin etc initrd.img lib64 sbin usr
(3)初始化階段
systemd是所有進程的父進程。也是一個守護進程,它管理其他守護進程。包括systemd,都是后台進程,systemd是第一個啟動的守護進程(在引導期間),也是最后一個終止的守護進程(在關閉期間)。
首先systemd按照/etc/fstab文件中的配置進行掛載。再根據運行級別(通過/etc/systemd/system/default.target
鏈接文件得知運行級別)然后啟動該運行級別的一系列的依賴(詳細的啟動順序可使用命令systemd-analyze plot > boot.html
然后用瀏覽器查看)。最后執行getty.target啟動終端和登陸程序。至此,整個過程結束。
以上是我個人理解,但還是有很多問題,例如最后,getty.target開啟了終端,那么它是調用/bin/login還是getty.target本身就和/bin/login一樣,這里還是很迷。