UEFI 啟(qi)動(dong)的(de)各階(jie)段介紹
UEFI啟動的七個階段介紹
系統(tong)固件開發(fa)學習系列:
目錄
一、整體概念
UEFI啟動的七(qi)個階段(duan)分(fen)別為(wei):
- SEC (Security),安全初始化階段。
- PEI (Pre-EFI Initialization),預EFI初始化階段。
- DXE (Driver Execution Envirenment),驅動執行環境階段。
- BDS (Boot Device Selection),啟動設備選擇階段。
- TSL (Transient System Load),操作系統加載前期階段。
- RT (Runtime) ,運行時階段。
- AL(After Life):關閉階段(系統關機或重啟)
首先對以(yi)上啟動步驟進行一個大(da)概的(de)理解(jie),以(yi)便對整個系統(tong)有(you)全局性的(de)思(si)考。
SEC 階段,負責處理系統復位、CPU 初始化和臨時內存的搭(da)建,為(wei)后續階段(duan)奠(dian)定安全(quan)可信的執行基礎;
緊接著是 PEI 階段,它在資源極度受限的環境中初始化內存控制器等關鍵硬件,并將系統信息通過 HOB 列表傳遞給下一棒;
隨后進入核心的 DXE 階段,大量驅動程序在此被執行,全面初始化平臺硬件并構建出豐富的Boot Services與Runtime Services服務框架;
硬件就緒后,BDS階段接管,它初始化控制臺設備、管理啟動項,并依據策略加載操作系統的引導程序(.efi文件);
引導程序開始執行便進入了TSL階段,它(ta)作(zuo)為臨時系(xi)統加(jia)載環境,依然利用Boot Services進行內(nei)核加(jia)載等準備工作(zuo);
準備就緒后,引導程序調用ExitBootServices(),系統進入RT階段,此時Runtime Services依然可用,但Boot Services已(yi)被(bei)卸載,操作系統(tong)內核開始(shi)掌(zhang)控全局;
最終,當操作系統完全啟動后,若系統進入睡眠或關機狀態,則會在需要時進入AL階段,由(you)固件提供特定的運行時(shi)錯誤處理(li)或睡眠恢(hui)復(fu)支持。
二、SEC—安全初始化階段
2.1 簡介
系統上電后,CPU 處于最原始的硬件狀態(如 x86 的實模式),此時 DRAM(主內存)及外設均未初始化。SEC(Security)階段作為UEFI固件執行的第一個環節,其核心任務就是將CPU從這種不可控的上電狀態,轉變為一個可執行代碼的穩定環境,并為后續的 PEI(Pre-EFI Initialization)階段準備好執行環境,其(qi)實也類似于 ARM 嵌入式設備的啟動,start.S 匯(hui)編入口文(wen)件(jian)。
SEC階段的代碼位(wei)于主(zhu)板(ban) SPI Flash 的 Boot Block 區域,體(ti)積小(通常幾十 KB)且擁有(you)最高執行權限。其(qi)執行流程(cheng)如下:
絕大多數主板使用 SPI Flash 存儲(chu)固件。容量多為(wei)8~64MB,速度(du)幾(ji)十 MB/s,接口線4根,可擦寫(xie)。
- 建立臨時執行環境:由于 DRAM 尚未可用,SEC 階段利用 Cache-as-RAM(CAR)技術,將CPU的內部高速緩存配置為臨時的讀寫內存(即棧空間),從而為 C 語言等高級語言的運行建立最基本的執行環境。
- 執行核心初始化:使用匯編語言完成 CPU 關鍵寄存器的初始化,確保處理器處于穩定、可預測的狀態。
- 安全驗證與交接:在將控制權移交前,SEC 階段會校驗PEI核心鏡像的哈希值,以確保固件代碼的完整性和安全性。
- 傳遞控制權:最后,SEC 系統當前狀態、BFV(Boot Firmware Volume)地址以及臨時 RAM 區域等關鍵參數傳遞給 PEI 階段,并跳轉至 PEI 入口點,完成其歷史使命。
實(shi)(shi)模(mo)(mo)(mo)(mo)式(shi):x86 CPU 啟動后的(de)初始狀態。實(shi)(shi)模(mo)(mo)(mo)(mo)式(shi)下,CPU能(neng)直接訪問的(de)內存(cun)空間只(zhi)有(you) 1MB,使用“段(duan):偏(pian)移”的(de)方式(shi)尋址,沒(mei)有(you)內存(cun)保(bao)護(hu),并且只(zhi)能(neng)進行(xing)單任務處理。實(shi)(shi)模(mo)(mo)(mo)(mo)式(shi)目前的(de)主要作用是系統(tong)(tong)啟動。當你打開電腦時,現代 CPU(即(ji)使是 64 位的(de))會(hui)自動進入(ru)實(shi)(shi)模(mo)(mo)(mo)(mo)式(shi)。這(zhe)時,BIOS 或 UEFI 固件會(hui)進行(xing)硬件自檢(POST),然后加載操作系統(tong)(tong)的(de)引導(dao)(dao)程序。這(zhe)個引導(dao)(dao)程序最初也是在(zai)實(shi)(shi)模(mo)(mo)(mo)(mo)式(shi)下運行(xing)的(de)。一旦操作系統(tong)(tong)接管,它就會(hui)功成身退(tui),讓位于更高級(ji)的(de)保(bao)護(hu)模(mo)(mo)(mo)(mo)式(shi)或長模(mo)(mo)(mo)(mo)式(shi)。
2.2 具體步驟
-
首先進行 CPU 初始化,禁止 CPU 的段寄存器,禁止中斷,清除狀態寄存器,開啟 Cache,關閉不(bu)安全的功能(如(ru)調試(shi)端口)。然(ran)后建立臨時棧(Cache-As-RAM, CAR),因為(wei)此時 DRAM 還(huan)未初(chu)始(shi)化,而代碼執行又需要(yao)棧空間,SEC 階段需要(yao)用 CPU Cache 模(mo)擬RAM。
CAR 技術(shu)的實現方(fang)式(shi)是,通過 MSR(Model Specific Register)配置Cache進入“Write-Back”模式(shi)。將 Cache 中的一部分地址(zhi)空(kong)間(jian)映(ying)射成偽地址(zhi),在該區域內建立(li)堆棧(zhan),此時 CPU 就可以正常執(zhi)行函數調用,存放臨時變量(liang)。
-
在建立執行環境之后,需要驗證固件的完整性。安全是 SEC 階段名稱的由來,在現代系統中,主板固件是攻擊者的目標之一。固件制造商會在 Flash 中存放公鑰(PK),UEFI 鏡像(PEI Core 及 DXE Core)使用私鑰簽名,SEC 階段計算哈希(SHA256)并驗證簽名,若(ruo)驗證失敗,立即終止啟動。
SHA256:一種(zhong)著名(ming)的加(jia)密哈希函數。
-
部(bu)分主板允許(xu)在(zai) SEC 階(jie)段輸(shu)出(chu)調試(shi)信(xin)息,例(li)如使(shi)用串口輸(shu)出(chu) “SEC Start”,提供“Early Debug”功(gong)能。在(zai)商用系(xi)統中通常被關閉。
-
SEC 會(hui)判斷當前的啟動屬于哪種情況:正(zheng)常啟動,冷啟動(斷電重啟),熱啟動(軟重啟(CTRL+ALT+DEL)),S3 恢復(從休眠(mian)喚醒),恢復模(mo)式(由于錯(cuo)誤(wu)進入 Recovery 路徑)。這些信息會(hui)被打包成結構體傳給(gei) PEI Core。
-
最后,SEC 階段通過一個標準(zhun)的入口(kou)將控制權交(jiao)給 PEI 核(he)心。
// SecCoreData: SEC 階段生成的系統信息(棧、內存范圍、HOB 起始地址)
// PpiList: 提供給 PEI 的功能接口(如臨時存儲、調試等)
PeiCoreEntryPoint (SecCoreData, PpiList)
SEC 階段(duan)重要(yao)的數(shu)據結(jie)構:
/**
* brief: 描述 Cache-As-RAM 區域,棧區,提供固件卷(Firmware Volume, FV)的地址。
*/
typedef struct {
EFI_PHYSICAL_ADDRESS DataSize;
EFI_PHYSICAL_ADDRESS PeiTemporaryRamBase;
EFI_PHYSICAL_ADDRESS PeiTemporaryRamSize;
EFI_PHYSICAL_ADDRESS StackBase;
EFI_PHYSICAL_ADDRESS StackSize;
EFI_PHYSICAL_ADDRESS BootFirmwareVolumeBase;
EFI_PHYSICAL_ADDRESS BootFirmwareVolumeSize;
} EFI_SEC_PEI_HAND_OFF;
在 OVMF 中,SEC 階段的入口文件為OvmfPkg/Sec/Secmain.c。其主要邏輯如下:
VOID
SecMain (
IN UINT32 SizeOfRam,
IN UINT32 StackBase
)
{
InitializeCpu (); // CPU 初始化
InitializeCacheAsRam (); // 建立Cache-As-RAM
VerifyFirmwareIntegrity (); // 固件驗證
DetectBootMode (); // 檢測啟動類型
HandOffToPeiCore (); // 跳轉至PEI階段
}
三、PEI—預 EFI 初始化階段
3.1 簡介
PEI 階段是 UEFI 啟動流程中最關鍵的過渡階段之一,它的任務是讓系統從沒有內存,幾乎什么都不能做的狀態,過渡到可以執行復雜 C 語言代碼,和加載驅動的 DXE 階段。當系統從 SEC 階段過來后,PEI 模塊的入口函數首先會執行,初始化一個稱為 PEI 核心的數據結構,作為 PEI 階段的中樞管理器,負責調度后續所有 PEI 模塊的執行。由于此時 DRAM 還不能使用,CPU 只能訪問 CPU Cache,所有 PEI 模塊都被壓縮存放在固件設備中,由 PEI 核心按需解壓到 Cache 中去運行。PEI 階段的首要任務就是就行內存控制器的初始化。具體來說,PEI 模塊通過硬編碼或從非易失性存儲器中讀取的內存時序參數,逐步配置內存控制器,最終完成物理內存的檢測與初始化。在內存就緒前后,PEI 階段會執行一系列關鍵的硬件初始化操作,包括配置芯片組的基本寄存器,檢測并初始化 BFV 中的其他 PEIM,處理固件中的安全策略,以及構建一份名為 HOB 的 Hand-Off Block 數據結構鏈表。HOB 列表至關重要,其以只讀的方式將 PEI 階段得到的系統硬件信息—內存布局,CPU 特性,設備狀態等(deng),完(wan)(wan)整地傳遞給 DXE 階段。一旦內(nei)存初始(shi)化完(wan)(wan)成,HOB 列表構建完(wan)(wan)畢(bi),PEI 階段的(de)最終任務就是(shi)定位并調(diao)用 DXE 初始(shi)程序加(jia)載器(qi)的(de)入口函數,將系統控制權(quan)徹底(di)移交至(zhi) DXE 階段。
3.2 關鍵點 & 執行流程
-
PEI 階段入口。
_ModuleEntryPoint()或_pei_main(),在 SEC 階段完成之(zhi)后(hou),會將一些(xie)信息傳入(ru) PEI 階段,如(ru)臨時(shi)內存(cun)的基(ji)(ji)地址和(he)大小,Boot Mode,固件卷(juan)基(ji)(ji)地址,棧頂指針(zhen),是否(fou)為冷啟動等。 -
PEI 階段由兩類模塊組成,分別為
PEI Core(PEI Foundation),和PEIMs(PEI Modules)。前者為 PEI 的內核,負責調度 PEIM,創建HOB,加載DXE。后者為各種硬件初始化模塊,如內存控制器,芯片組,I/O 控制器等。PEI Core 會調用一系列PEIM。這些模塊由EFI_PEI_PPI_DESCRIPTOR描述。 -
一些關鍵數據結構。
/** * HOB 用于項 DXE 傳遞硬件資源信息 * 下面是一些常見的 HOB 類型,這些 HOB 最后會被 DXE Core 讀取,用來構建 UEFI 系統表。 */ EFI_HOM_MEMORY_ALLOCATION // 內存分配信息 EFI_HOB_RESOURCE_DESCRIPTOR // 物理內存資源描述 EFI_HOB_GUID_TYPE // 自定義結構(比如SMBIOS、ACPI表等) EFI_HOB_FIRMWARE_VOLUME // 固件卷位置 EFI_HOB_CPU // CPU 信息(寄存器寬度、特性) /** * PPI(PEI-to-PEI Interface) * PEI 階段存在諸多模塊,PPI 用于這些模塊之間的通信 * PEI Core 會根據 GUID 調用這些接口。 */ EFI_PEI_PPI_DESCRIPTOR gMemoryInitPpi = { EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiPeiMemoryInitPpiGuid, &PeiMemoryInitInterface };
GUID(Globally Unique Identifier,全局唯一標識符)是一個 128 位的唯一編號,UEFI 使用它來(lai)唯一(yi)標(biao)識:各(ge)(ge)種模塊(PEIM、PPI、Protocol),各(ge)(ge)種數據(ju)結(jie)構(gou)(比如 HOB、FV 文件、變量(liang)等)
例如:#define EFI_PEI_READ_ONLY_VARIABLE2_PPI_GUID
{ 0x2ab86ef5, 0xecb5, 0x4134, {0xb5, 0x89, 0x39, 0x1e, 0x29, 0x8b, 0xfa, 0x88} }PEIM之(zhi)間靠(kao) GUID 來標識和查找接口,而(er)不是靠(kao)函(han)數名或文件路徑(jing)。
執行流程:
-
SEC 階段完成 CPU 棧初始化,將臨時內存參數傳給 PEI,跳轉到
PeiCore()。 -
建立臨時內(nei)存(棧,全(quan)局變量區(qu)),CAR。
-
PEI Core 解(jie)析 Firmware Volume,查找 .PEIM 模(mo)塊,調用其中(zhong)的入(ru)口函數,執行例(li)如
-
MemoryInitPeim→ 初始化(hua) DRAM; -
CpuInitPeim→ 配(pei)置 CPU; -
PchInitPeim→ 初始化芯片組(zu); -
BoardInitPeim→ 板級(ji)設備配置。
-
-
內存初始化完成之后 PEI Core 會通過
BuildHob()系列函數創(chuang)建各種 HOB。記錄系統物理內存布(bu)局、固件卷地址、CPU信(xin)息(xi)等(deng)。BuildResourceDescriptorHob(...); BuildMemoryAllocationHob(...); BuildCpuHob(...); -
PEI Core 搜索包含 DXE Core 的固件卷,創建一個
EFI_HOB_FIRMWARE_VOLUME,將該區(qu)域(yu)標(biao)記為(wei)可執行代碼(ma)段。 -
將堆(dui)棧和數據從(cong) Cache 搬到 DRAM,更新指針(zhen),釋(shi)放臨時 RAM。
-
進入 DXE 階(jie)段(duan)。
典型文件:
SEC Core MdeModulePkg/Core/Sec/SecMain.c 最早入口
PEI Core MdeModulePkg/Core/Pei/PeiMain.c PEI主循環與調度
MemoryInitPeim MdeModulePkg/Universal/MemoryInitPei/ 內存初始化模塊
HobLib MdePkg/Library/HobLib/ 創建 HOB 的庫函數
PeiServicesLib MdePkg/Library/PeiServicesLib/ 提供 PEIM 注冊、PPI 管理接口
四、DXE—驅動執行環境階段
4.1 簡介
DEX 階段是 UEFI 固件初始化的核心與主體,其核心使命是通過加載大量的驅動程序,來全面初始化處理器,芯片組及各類平臺硬件,并構建出豐富的 Boot Services 與 Runtime Services 服務框架,最終為操作系(xi)統(tong)的加(jia)載(zai)做好一切準備。
System Table 是總表;
Boot Services 是啟動期間的 API 集合,可供啟動期間的程序調用;
Runtime Services 是(shi) OS 運行期間的 API 集合,在操作(zuo)系統(tong)啟動之后,會為其創建虛(xu)擬地址空間映射(she),仍然可以調用相(xiang)關函數。具體介紹見下文。
DEX 在接受 PEI 階段提交的 HOB 列表后,其便在一個功能完備的內存環境中展開。DEX 首先會初始化一系列基礎服務,如驅動程序調度器,句柄數據庫,Protocol 接口管理體系等,為后續驅動程序的有序加載和交互提供基礎設施。隨后,系統會進入一個密集的驅動程序發現與執行期。固件會從多個 Firmware Volume 中掃描加載大量的 DXE 驅動程序,這些程序遵循依賴關系被有序調度,逐一執行,從而完整對所有 CPU 高級功能,芯片組復雜單元,總線控制器,磁盤設備,網絡接口以及輸入輸出設備等平臺硬件的深度檢測,初始化和驅動。在此過程中,每個驅動程序通常會將其提供的功能以 Protocol 的形式安裝到系統數據庫中,其他驅動或應用程序可以通過定位這些 Protocol 來使用相應的服務,這種模塊化的設計使得硬件初始化和服務構建高效靈活可擴展。在硬件資源就緒后,DXE 會逐步構建并完善 Boot Services 與 Runtime Services,前者為(wei)操作系(xi)(xi)統(tong)加載器(qi)提(ti)供內存(cun)管(guan)理(li)(li),協議接口(kou),事件定時等關鍵(jian)服務,后(hou)者包含在操作系(xi)(xi)統(tong)運行后(hou)仍需固件管(guan)理(li)(li)的功能(neng)。在所有的驅動程序(xu)成功加載并執行完畢(bi)之后(hou),DXE 階段的核心任(ren)務編宣告完成,系(xi)(xi)統(tong)將控制(zhi)權交(jiao)給(gei) BDS階段。
4.2 關鍵點介紹
DEX 階段是 UEFI 的“核(he)心(xin)操作系統內核(he)”,負責建立(li)完(wan)整(zheng)的驅動執行環境,并初始(shi)化所有系統資源,為加載 Bootloader 做準備(bei)。
DEX 階段的執行環境:
- 內存已完全初始化;
- MMU、Cache 已啟用;
- 可以使用堆、棧;
- 支持動態加載
.efi驅動; - 支持中斷(部分架構)。
DEX 階段的核心:
- 初始化 CPU,內存,總線控制器(從內向外,包括MMU、Cache、PCI、USB、SATA 等);
- 構建 EFI System Table(建立 UEFI 的核心接口表,供后續驅動,應用調用);
- 加載 DXE 驅動(從 FV 中解析并執行);
- 管理協議(Protocol),不同驅動之間通過 GUID 協議通信(類似面向對象接口);
- 啟動 BDS 階段。
三大核心模塊:
-
DEX Core:管理驅(qu)動加(jia)載,協議注冊(ce),服務調(diao)度(du)。其就像一個迷你的操作系統內核,它建立全局數據結構(EFI_SYSTEM_TABLE, Boot Services, Runtime Services),管理內存分(fen)配與頁表,維(wei)護(hu)“Protocol Database”——所有 GUID 協議的注冊表,提供(gong)動態驅動加載,卸載和(he)通信機制。它(ta)在 PEI 階段結束時被加載,加載入口由 PEI 階段的 HOB 提供(gong)。
-
DEX Dispatcher:調度器,掃描 FV 中(zhong)的 DXE 驅動,并(bing)按依賴關系(xi)執(zhi)行。DXE Dispatcher 像一(yi)個(ge)(ge)動(dong)(dong)態驅動(dong)(dong)管(guan)理(li)器,掃描固件卷中所(suo)有的 DXE Driver文件(.efi),根據文件中的 Dependency Section 判(pan)斷依賴關(guan)系,按(an)照依賴順(shun)序逐個(ge)(ge)加載,執行(xing)驅動(dong)(dong),類似(si)于 Linux 中的 modprobe。
-
DEX Drivers:各種功(gong)能驅動模塊PCI、USB、圖形、文件系統、網(wang)絡(luo)、變量服務等。幾(ji)乎所有硬件的驅(qu)(qu)動(dong),服務都(dou)在(zai)這里被初(chu)始化,如下表所示。每個驅(qu)(qu)動(dong)都(dou)是(shi)一個獨立的 efi 文件,包含驅(qu)(qu)動(dong)入口(kou)函數(shu),一組協議實現(用 GUID 標識),安裝(zhuang)、注冊、回調機制。
分類 示例 CPU/Chipset MTRR、Cache、中斷控制器 內存 內存映射服務 PCI/USB/SATA 總線控制器驅動 圖形 GOP (Graphics Output Protocol) 文件系統 Simple File System Protocol 網絡 PXE Base Code Protocol 變量存儲 Variable Services Protocol 安全 Secure Boot Protocol
Protocol
前面多次提到 Protocol,這是 DXE 階(jie)段的通(tong)信(xin)(xin)機制(zhi)。先前我(wo)們(men)(men)介紹(shao)過(guo) PEI 階(jie)段的通(tong)信(xin)(xin)機制(zhi) PPI,接下來我(wo)們(men)(men)對(dui) Protocol 進行簡要說明,以(yi)對(dui) DXE 階(jie)段的通(tong)信(xin)(xin)有(you)一個(ge)初步的理解。
/* Protocol 的結構: */
typedef struct {
EFI_STATUS (EFIAPI *Start)(...);
EFI_STATUS (EFIAPI *Stop)(...);
...
} EFI_DRIVER_PROTOCOL;
/* 每個協議由一個 GUID 唯一標識 */
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
{ 0x9042a9de, 0x23dc, 0x4a38, {0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a} }
/* 安裝協議 */
gBS->InstallProtocolInterface(Handle, &gEfiGraphicsOutputProtocolGuid, EFI_NATIVE_INTERFACE, &Gop);
/* 查找協議 */
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
這里對(dui) PPI 以及 Protocol 的介(jie)紹(shao)較(jiao)為簡略(lve),本文(wen)主要學(xue)習(xi)對(dui) UEFI 的啟(qi)動過程(cheng),細節內容后續(xu)學(xue)習(xi)過程(cheng)中會陸續(xu)補充(chong)。
重要的全局結構:
EFI_SYSTEM_TABLE,Boot Services,Runtime Services。
系統表:
當 UEFI 應用(如 Bootloader)運行時,會把這個表作為參數傳入efi_main(),讓應用可以訪問(wen) UEFI 服(fu)務。
/* 1. EFI系統表 EFI_SYSTEM_TABLE
* 操作系統啟動后,主要通過系統表與固件交互
*/
typedef struct {
EFI_TABLE_HEADER Hdr; // 表頭信息(簽名、版本、大小)
CHAR16 *FirmwareVendor; // 固件廠商
UINT32 FirmwareRevision;// 固件版本號
EFI_HANDLE ConsoleInHandle; // 控制臺輸入設備句柄
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; // 輸入協議接口(鍵盤輸入)
EFI_HANDLE ConsoleOutHandle;// 控制臺輸出設備句柄
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; // 輸出協議接口(屏幕輸出)
EFI_HANDLE StandardErrorHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; // 標準錯誤輸出
EFI_RUNTIME_SERVICES *RuntimeServices;// 運行時服務表指針
EFI_BOOT_SERVICES *BootServices; // 引導服務表指針
UINTN NumberOfTableEntries;
EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
Boot Services:
它是一個結構體EFI_BOOT_SERVICES,它在系(xi)統還沒有“交出控制權(quan)”給操作系(xi)統之前,提(ti)供(gong)大量的底層(ceng)(ceng)服務接(jie)口,也就相(xiang)當于一系(xi)列 API,提(ti)供(gong)上層(ceng)(ceng)調(diao)用,調(diao)用方式如下。
| 功能類別 | 示例函數 | 作用 |
|---|---|---|
| 內存管理 | AllocatePages() / FreePages() |
分配或釋放物理頁 |
| 事件與定時 | CreateEvent() / WaitForEvent() |
創建、等待事件 |
| 協議操作 | InstallProtocolInterface() / LocateProtocol() |
安裝、查找驅動協議 |
| 句柄操作 | HandleProtocol() / LocateHandle() |
查找設備句柄 |
| 加載執行 | LoadImage() / StartImage() |
加載并執行 EFI 應用或驅動 |
| 設備訪問 | OpenProtocol() / CloseProtocol() |
訪問驅動協議接口 |
| 退出引導服務 | ExitBootServices() |
結束 Boot Services,進入操作系統 |
/* 2. Boot Services
- 提供內存分配,事件、協議管理、句柄操作等功能。
- 在 OS Loader 階段使用;
- 在 ExitBootServices() 調用后失效。
*/
// Boot Services提供接口調用方式舉例
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Addr = 0x100000;
Status = SystemTable->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, &Addr);
Runtime Services:
Runtime Services 同樣是一個結構體 EFI_RUNTIME_SERVICES。與 Boot Services 不同的是,它提供(gong)的服務(wu)在操作系(xi)統啟動之后仍然存(cun)在,這些函數的實現被 OS 的 UEFI 驅動或內(nei)核映射進虛擬地址空間。部分服務(wu)如(ru)下(xia)。
| 功能類別 | 示例函數 | 說明 |
|---|---|---|
| 時間日期 | GetTime() / SetTime() |
獲取或設置系統時間 |
| 變量服務 | GetVariable() / SetVariable() |
訪問 NVRAM 變量 |
| 系統復位 | ResetSystem() |
重啟、關機等操作 |
| 虛擬地址轉換 | SetVirtualAddressMap() |
OS 建立虛擬內存時使用 |
| 固件更新 | UpdateCapsule() |
支持 BIOS/UEFI 更新機制 |
/* 3. Runtime Services
- 提供變量訪問、時間服務、系統重啟等功能;
- 在 OS 運行時仍可使用;
- 駐留在固件中,操作系統通過 SMM 調用。
五、BDS—啟動設備選擇階段
5.1 簡介
BDS 階段是連接平臺硬件初始化完成與操作系統加載器執行的橋梁,核心使命是初始化控制臺設備,管理啟動選項,并依據預設的啟動策略來定位并執行目標操作系統的引導程序。當 DXE 階段將所有必要的硬件驅動和 Boot Services 都準備好之后,系統控制權移交至 BDS,BDS 首先會執行一系列全局性系統初始化,包括圖形控制臺需要的顯卡,鍵盤,鼠標等。隨后,BDS 會加載和執行特定的驅動和應用程序,進一步枚舉和初始化更多的設備,如 USB,網卡等,這些設備在 DXE 階段未被強制初始化,但對于發現啟動項至關重要。在設備就緒后,BDS 核心邏輯會根據 NVRAM 中存儲的 UEFI 啟動變量來搜集和整理所有可用的啟動選項,這些選項可能來自硬盤上的 EFI 系統分區,網絡服務器,光驅或者其他可引導介質。隨后,BDS 會依據啟動策略(例如默認啟動,用戶手動選擇或單一啟動)來嘗試執行這些啟動項。它會按照優先級順序,逐個加載每個啟動項對應的 OS 引導程序至內存中(如Windows的bootmgfw.efi或Linux的grubx64.efi)。一旦某個引導程序被成功加載并執行,BDS階段便將其辛苦構建的整個Boot Services環境移交給該引導程序。至此,BDS階段的歷史任務(wu)宣告完成,系(xi)統(tong)的控制權正式過渡(du)給(gei)操作系(xi)統(tong)的引導裝載程序。
5.2 關鍵點介紹
BDS 的核心指責是根據系統配置和啟動策略,選擇合適的啟動設備,并執行對應的啟動加載程序。
在(zai) EDK2 中,BDS 階段主要通過以下文件實現:MdeModulePkg/Core/DxeBds/
核心函數入口:
VOID EFIAPI BdsEntry (
IN EFI_BDS_ARCH_PROTOCOL *This
)
// 流程包括:
BdsInitialize() // 初始化控制臺設備;
BdsBootDeviceSelect() // 啟動設備選擇;
BdsBootViaBootOption() // 嘗試加載 Boot####;
BdsBootSuccessHandler() // BdsBootFailHandler():處理成功或失敗結果;
BdsEnterFrontPage() // 用戶交互界面。
具體任務
-
創建(jian)控(kong)制臺設備(Console)。確定系統的輸(shu)入輸(shu)出(chu)(chu)設備,鍵盤,顯示(shi)器(qi),串(chuan)口等。建(jian)立標準的輸(shu)入輸(shu)出(chu)(chu)句柄(ConIn、ConOut、StdErr),使得用戶可以看到 BIOS/UEFI 的啟動(dong)畫面、輸(shu)入命令。
-
加載并執行 Boot Manager(引導管理器)。這是 UEFI 規范規定的,系統固件應該包括一個引導管理器,負責引導順序管理。它讀取 Boot Order、Boot Option 等 NVRAM 變量(liang),判(pan)斷從哪個設備啟動(dong)。
-
枚舉所有(you) Boot Option(啟動選項(xiang))。這些選項(xiang)保(bao)存在(zai) UEFI 變量中,如(ru):
BootOrder // 啟動順序,例如 [0001, 0003, 0000] Boot0000 // 啟動項0,例如 EFI Shell Boot0001 // 啟動項1,例如 Windows Boot Manager Boot0003 // 啟動項3,例如 UEFI USB Device每個 Boot Option 包含啟(qi)動設備路(lu)徑(EFI_DEVICE_PATH)和(he)加載映像(xiang)文件路(lu)徑。
-
嘗試加載啟動項中的 EFI 可執行文件。BDS 通過 Boot Services 的
LoadImage()和StartImage()來加載 EFI 應用(例如 bootx64.efi)。通常這些文件存放在\EFI\BOOT\BOOTX64.EFI,\EFI\Microsoft\Boot\bootmgfw.efi。如果加(jia)載失敗,就嘗試下一個 Boot Option。 -
處理 Boot Maintenance Manager (BMM)。若所有 Boot Option 均失敗,BDS 會進入(ru) BMM(類(lei)似 BIOS Setup 界面)。允許(xu)用戶修改啟動順序、設置 NVRAM 啟動變量、更新 Boot Option。
-
最終移交控制權。成功加載 Bootloader(例如 GRUB、Windows Boot Manager)后:調用
ExitBootServices(),銷毀 Boot Services,把控制(zhi)權交給 Bootloader,進入操作(zuo)系(xi)統加載(zai)階段。
關鍵數據結構
-
Boot Option(啟動項結構(gou))
typedef struct { UINT32 Attributes; UINT16 FilePathListLength; CHAR16 Description[]; // 啟動項名稱(如 "Windows Boot Manager") EFI_DEVICE_PATH_PROTOCOL FilePathList[]; // 啟動文件路徑 UINT8 OptionalData[]; // 啟動時需要傳入的參數 } EFI_LOAD_OPTION; -
BootOrder:存儲(chu)在 NVRAM 中的啟動(dong)順序表。
Boot Order 啟動項編號 含義 0001 Windows Boot Manager 啟動 Windows 0003 UEFI USB Device 從 USB 啟動 0000 EFI Shell 啟動到 UEFI Shell
六、TSL—瞬態系統加載階段
6.1 簡介
TSL 是 BDS 階段成功找到并開始執行操作系統引導程序(如.efi文件)后,直到該引導程序將系統控制權正式移交給操作系統內核之前的一個臨時性的過渡執行環境。在此階段,操作系統的引導程序(例如 GRUB 或 Windows Boot Manager)作為 UEFI 環境下的一個特殊應用程序,依然完整地運行在 UEFI Boot Services 所構建的富運行時環境之中,它可以自由地調用 Boot Services 提供的內存管理、協議接口和磁盤I/O等服務,來完成諸如加載操作系統內核、初始化文件系統、解析配置文件等關鍵準備工作;然而,TSL階段的“臨時”性也正體現在此,其核心目標是為最終告別 UEFI 環境并啟動真正的操作系統做準備,因此,一旦引導程序完成了所有必要的加載任務,它就必須主動調用 ExitBootServices() 函數,這個關鍵調用標志著 TSL 階段的終結。系統控制權由此正式移交,從而進入不再依賴UEFI固件的RT階段。
6.2 關鍵點介紹
TSL 是(shi)瞬態(tai)的(de),它只在交接控制(zhi)權(quan)的(de)瞬間存在。
主要任務
- 執行 BootLoader。BDS 階段通過
LoadImage()+StartImage()啟動 BootLoader,BootLoader 在 UEFI 環境中執行,它是一個標準的 EFI 應用程序。這意味著 BootLoader 也能使用 UEFI 提供的 Boot Services 和 Runtime Services。 - 準備加載操作系統內核,BootLoader(例如 GRUB 或 Windows Boot Manager)會解析配置文件,選擇內核映像(kernel image),加載內核到內存,設置命令行參數、RAMDisk、ACPI 表、內存映射等信息,準備 CPU 狀態(模式、分頁、棧等)。
- 退出 UEFI 環境。調用
ExitBootServices()。此時,所有 Boot Services 被銷毀,只剩下 Runtime Services。 - 跳轉到操作系統入口點。
一些關鍵函數
GetMemoryMap()。在調用ExitBootServices()之前,BootLoader 必須 先調用這個函數,獲取當前系統的內存布局,返回一個MapKey,這個MapKey是 ExitBootServices 的憑證(必須匹配當前內存狀態)。ExitBootServices(),退出 UEFI 環境。通知 UEFI 固件釋放所有 Boot Services,停止所有驅動、定時器、中斷等,將內存管理完全交給 BootLoader/OS,僅保留 Runtime Services(例如時間、變量等功能)。
ExitBootServices()調用前后內存映射的變化。- 在
ExitBootServices()之前:所有固件驅動、服務都在運行,Boot Services 負責內存分配、設備管理,內存中存在大量 EFI 類型的區域,如EfiBootServicesData。 - 在
ExitBootServices()之后:固件停止介入,所有 Boot Services 相關區域被標記為 “可重用”,BootLoader 或 OS 內核接管內存管理,僅剩EfiRuntimeServicesCode/Data區域仍被保留,供 OS 使用。
七、RT 和 AL 階段
RT 階段是在(zai)操作系統已(yi)經(jing)接(jie)過控制(zhi)權(quan)之(zhi)后,不做過多介紹,簡單說(shuo)一(yi)下(xia)此時固件還能作用的 Runtime Services 的相(xiang)關函數。
| 功能類別 | 典型函數 | 作用 |
|---|---|---|
| 時間服務 | GetTime(), SetTime() |
獲取/設置系統時間(CMOS時鐘) |
| 虛擬內存服務 | SetVirtualAddressMap() |
固件映射從物理地址切換到虛擬地址(OS啟用分頁后使用) |
| 變量服務 | GetVariable(), SetVariable() |
讀取/寫入NVRAM變量(如啟動項、SecureBoot狀態) |
| 重置服務 | ResetSystem() |
控制系統重啟、關機、S3睡眠等 |
| 字符串服務 | (已廢棄) | 早期版本中用于輸出信息 |
AL 階(jie)段是操作系統(tong)關(guan)閉(bi)電源或重啟前的最后(hou)一個階(jie)段。其(qi)通常在以下情況發生:
- 用戶執行關機(Shutdown);
- 系統執行重啟(Reboot);
- 系統進入睡眠/休眠(S3/S4);
- 系統掉電(Power Loss)或崩潰。
AL 階段控(kong)制權(quan)變化:
| 時間點 | 控制權歸屬 | 狀態 |
|---|---|---|
| OS 正常運行 | 操作系統 | 使用 Runtime Services |
| 調用 ResetSystem() | 操作系統 → 固件 | 固件開始復位 |
| 重啟/關機完成 | 固件接管 | 重新進入 SEC 階段或斷電 |
結語
本文較為詳細介紹了 UFEI 規(gui)范中啟動的主(zhu)要流程,由(you)于本人是初學者,很多地方理(li)解的不(bu)是很深刻,未來學習(xi)中會持續修改(gai)補(bu)充。本文是學習(xi) UEFI 啟動過程的筆記記錄,主(zhu)要內容源(yuan)自 AI 搜索(suo)整理(li)。
Seriousness is the cornerstone of everything!
