Stories

Detail Return Return

UEFI 啓動的各階段介紹 - Stories Detail

UEFI啓動的七個階段介紹

系統固件開發學習系列:

一、EDKII環境搭建 & QEMU虛擬機雙平台安裝

二、EDKII工程結構介紹

目錄

一、整體概念

二、SEC 安全初始化階段

三、PEI 預 EFI 初始化階段

四、DXE—驅動執行環境階段

五、BDS—啓動設備選擇階段

六、TSL—瞬態系統加載階段

七、RT 和 AL 階段

一、整體概念

UEFI啓動的七個階段分別為:

  1. SEC (Security),安全初始化階段。
  2. PEI (Pre-EFI Initialization),預EFI初始化階段。
  3. DXE (Driver Execution Envirenment),驅動執行環境階段。
  4. BDS (Boot Device Selection),啓動設備選擇階段。
  5. TSL (Transient System Load),操作系統加載前期階段。
  6. RT (Runtime) ,運行時階段。
  7. AL(After Life):關閉階段(系統關機或重啓)

首先對以上啓動步驟進行一個大概的理解,以便對整個系統有全局性的思考。

SEC 階段,負責處理系統復位、CPU 初始化和臨時內存的搭建,為後續階段奠定安全可信的執行基礎;

緊接着是 PEI 階段,它在資源極度受限的環境中初始化內存控制器等關鍵硬件,並將系統信息通過 HOB 列表傳遞給下一棒;

隨後進入核心的 DXE 階段,大量驅動程序在此被執行,全面初始化平台硬件並構建出豐富的Boot Services與Runtime Services服務框架;

硬件就緒後,BDS階段接管,它初始化控制枱設備、管理啓動項,並依據策略加載操作系統的引導程序(.efi文件);

引導程序開始執行便進入了TSL階段,它作為臨時系統加載環境,依然利用Boot Services進行內核加載等準備工作;

準備就緒後,引導程序調用ExitBootServices(),系統進入RT階段,此時Runtime Services依然可用,但Boot Services已被卸載,操作系統內核開始掌控全局;

最終,當操作系統完全啓動後,若系統進入睡眠或關機狀態,則會在需要時進入AL階段,由固件提供特定的運行時錯誤處理或睡眠恢復支持。

二、SEC—安全初始化階段

2.1 簡介

系統上電後,CPU 處於最原始的硬件狀態(如 x86 的實模式),此時 DRAM(主內存)及外設均未初始化。SEC(Security)階段作為UEFI固件執行的第一個環節,其核心任務就是將CPU從這種不可控的上電狀態,轉變為一個可執行代碼的穩定環境,併為後續的 PEI(Pre-EFI Initialization)階段準備好執行環境,其實也類似於 ARM 嵌入式設備的啓動,start.S 彙編入口文件。

SEC階段的代碼位於主板 SPI Flash 的 Boot Block 區域,體積小(通常幾十 KB)且擁有最高執行權限。其執行流程如下:

絕大多數主板使用 SPI Flash 存儲固件。容量多為8~64MB,速度幾十 MB/s,接口線4根,可擦寫。

  1. 建立臨時執行環境:由於 DRAM 尚未可用,SEC 階段利用 Cache-as-RAM(CAR)技術,將CPU的內部高速緩存配置為臨時的讀寫內存(即棧空間),從而為 C 語言等高級語言的運行建立最基本的執行環境。
  2. 執行核心初始化:使用彙編語言完成 CPU 關鍵寄存器的初始化,確保處理器處於穩定、可預測的狀態。
  3. 安全驗證與交接:在將控制權移交前,SEC 階段會校驗PEI核心鏡像的哈希值,以確保固件代碼的完整性和安全性。
  4. 傳遞控制權:最後,SEC 系統當前狀態、BFV(Boot Firmware Volume)地址以及臨時 RAM 區域等關鍵參數傳遞給 PEI 階段,並跳轉至 PEI 入口點,完成其歷史使命。

實模式:x86 CPU 啓動後的初始狀態。實模式下,CPU能直接訪問的內存空間只有 1MB,使用“段:偏移”的方式尋址,沒有內存保護,並且只能進行單任務處理。實模式目前的主要作用是系統啓動。當你打開電腦時,現代 CPU(即使是 64 位的)會自動進入實模式。這時,BIOS 或 UEFI 固件會進行硬件自檢(POST),然後加載操作系統的引導程序。這個引導程序最初也是在實模式下運行的。一旦操作系統接管,它就會功成身退,讓位於更高級的保護模式或長模式。

2.2 具體步驟

  • 首先進行 CPU 初始化,禁止 CPU 的段寄存器,禁止中斷,清除狀態寄存器,開啓 Cache,關閉不安全的功能(如調試端口)。然後建立臨時棧(Cache-As-RAM, CAR),因為此時 DRAM 還未初始化,而代碼執行又需要棧空間,SEC 階段需要用 CPU Cache 模擬RAM。

    CAR 技術的實現方式是,通過 MSR(Model Specific Register)配置Cache進入“Write-Back”模式。將 Cache 中的一部分地址空間映射成偽地址,在該區域內建立堆棧,此時 CPU 就可以正常執行函數調用,存放臨時變量。

  • 在建立執行環境之後,需要驗證固件的完整性。安全是 SEC 階段名稱的由來,在現代系統中,主板固件是攻擊者的目標之一。固件製造商會在 Flash 中存放公鑰(PK),UEFI 鏡像(PEI Core 及 DXE Core)使用私鑰簽名,SEC 階段計算哈希(SHA256)並驗證簽名,若驗證失敗,立即終止啓動。

    SHA256:一種著名的加密哈希函數。

  • 部分主板允許在 SEC 階段輸出調試信息,例如使用串口輸出 “SEC Start”,提供“Early Debug”功能。在商用系統中通常被關閉。

  • SEC 會判斷當前的啓動屬於哪種情況:正常啓動,冷啓動(斷電重啓),熱啓動(軟重啓(CTRL+ALT+DEL)),S3 恢復(從休眠喚醒),恢復模式(由於錯誤進入 Recovery 路徑)。這些信息會被打包成結構體傳給 PEI Core。

  • 最後,SEC 階段通過一個標準的入口將控制權交給 PEI 核心。

// SecCoreData: SEC 階段生成的系統信息(棧、內存範圍、HOB 起始地址)
// PpiList: 提供給 PEI 的功能接口(如臨時存儲、調試等)
PeiCoreEntryPoint (SecCoreData, PpiList)

SEC 階段重要的數據結構:

/**
 * 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 特性,設備狀態等,完整地傳遞給 DXE 階段。一旦內存初始化完成,HOB 列表構建完畢,PEI 階段的最終任務就是定位並調用 DXE 初始程序加載器的入口函數,將系統控制權徹底移交至 DXE 階段。

3.2 關鍵點 & 執行流程

  • PEI 階段入口。_ModuleEntryPoint()_pei_main(),在 SEC 階段完成之後,會將一些信息傳入 PEI 階段,如臨時內存的基地址和大小,Boot Mode,固件卷基地址,棧頂指針,是否為冷啓動等。

  • 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 使用它來唯一標識:各種模塊(PEIM、PPI、Protocol),各種數據結構(比如 HOB、FV 文件、變量等)

例如:#define EFI_PEI_READ_ONLY_VARIABLE2_PPI_GUID
{ 0x2ab86ef5, 0xecb5, 0x4134, {0xb5, 0x89, 0x39, 0x1e, 0x29, 0x8b, 0xfa, 0x88} }

PEIM之間靠 GUID 來標識和查找接口,而不是靠函數名或文件路徑。

執行流程:

  1. SEC 階段完成 CPU 棧初始化,將臨時內存參數傳給 PEI,跳轉到PeiCore()

  2. 建立臨時內存(棧,全局變量區),CAR。

  3. PEI Core 解析 Firmware Volume,查找 .PEIM 模塊,調用其中的入口函數,執行例如

    • MemoryInitPeim → 初始化 DRAM;

    • CpuInitPeim → 配置 CPU;

    • PchInitPeim → 初始化芯片組;

    • BoardInitPeim → 板級設備配置。

  4. 內存初始化完成之後 PEI Core 會通過 BuildHob() 系列函數創建各種 HOB。記錄系統物理內存佈局、固件卷地址、CPU信息等。

    BuildResourceDescriptorHob(...);
    BuildMemoryAllocationHob(...);
    BuildCpuHob(...);
    
  5. PEI Core 搜索包含 DXE Core 的固件卷,創建一個EFI_HOB_FIRMWARE_VOLUME,將該區域標記為可執行代碼段。

  6. 將堆棧和數據從 Cache 搬到 DRAM,更新指針,釋放臨時 RAM。

  7. 進入 DXE 階段。

典型文件:

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 服務框架,最終為操作系統的加載做好一切準備。

System Table 是總表;
Boot Services 是啓動期間的 API 集合,可供啓動期間的程序調用;
Runtime Services 是 OS 運行期間的 API 集合,在操作系統啓動之後,會為其創建虛擬地址空間映射,仍然可以調用相關函數。

具體介紹見下文。

DEX 在接受 PEI 階段提交的 HOB 列表後,其便在一個功能完備的內存環境中展開。DEX 首先會初始化一系列基礎服務,如驅動程序調度器,句柄數據庫,Protocol 接口管理體系等,為後續驅動程序的有序加載和交互提供基礎設施。隨後,系統會進入一個密集的驅動程序發現與執行期。固件會從多個 Firmware Volume 中掃描加載大量的 DXE 驅動程序,這些程序遵循依賴關係被有序調度,逐一執行,從而完整對所有 CPU 高級功能,芯片組複雜單元,總線控制器,磁盤設備,網絡接口以及輸入輸出設備等平台硬件的深度檢測,初始化和驅動。在此過程中,每個驅動程序通常會將其提供的功能以 Protocol 的形式安裝到系統數據庫中,其他驅動或應用程序可以通過定位這些 Protocol 來使用相應的服務,這種模塊化的設計使得硬件初始化和服務構建高效靈活可擴展。在硬件資源就緒後,DXE 會逐步構建並完善 Boot ServicesRuntime Services,前者為操作系統加載器提供內存管理,協議接口,事件定時等關鍵服務,後者包含在操作系統運行後仍需固件管理的功能。在所有的驅動程序成功加載並執行完畢之後,DXE 階段的核心任務編宣告完成,系統將控制權交給 BDS階段。

4.2 關鍵點介紹

DEX 階段是 UEFI 的“核心操作系統內核”,負責建立完整的驅動執行環境,並初始化所有系統資源,為加載 Bootloader 做準備。

DEX 階段的執行環境:

  • 內存已完全初始化;
  • MMU、Cache 已啓用;
  • 可以使用堆、棧;
  • 支持動態加載 .efi 驅動;
  • 支持中斷(部分架構)。

DEX 階段的核心:

  • 初始化 CPU,內存,總線控制器(從內向外,包括MMU、Cache、PCI、USB、SATA 等);
  • 構建 EFI System Table(建立 UEFI 的核心接口表,供後續驅動,應用調用);
  • 加載 DXE 驅動(從 FV 中解析並執行);
  • 管理協議(Protocol),不同驅動之間通過 GUID 協議通信(類似面向對象接口);
  • 啓動 BDS 階段。

三大核心模塊:

  1. DEX Core:管理驅動加載,協議註冊,服務調度。

    其就像一個迷你的操作系統內核,它建立全局數據結構(EFI_SYSTEM_TABLE, Boot Services, Runtime Services),管理內存分配與頁表,維護“Protocol Database”——所有 GUID 協議的註冊表,提供動態驅動加載,卸載和通信機制。它在 PEI 階段結束時被加載,加載入口由 PEI 階段的 HOB 提供。

  2. DEX Dispatcher:調度器,掃描 FV 中的 DXE 驅動,並按依賴關係執行。

    DXE Dispatcher 像一個動態驅動管理器,掃描固件卷中所有的 DXE Driver文件(.efi),根據文件中的 Dependency Section 判斷依賴關係,按照依賴順序逐個加載,執行驅動,類似於 Linux 中的 modprobe。

  3. DEX Drivers:各種功能驅動模塊PCI、USB、圖形、文件系統、網絡、變量服務等。

    幾乎所有硬件的驅動,服務都在這裏被初始化,如下表所示。每個驅動都是一個獨立的 efi 文件,包含驅動入口函數,一組協議實現(用 GUID 標識),安裝、註冊、回調機制。

    分類 示例
    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 階段的通信機制。先前我們介紹過 PEI 階段的通信機制 PPI,接下來我們對 Protocol 進行簡要説明,以對 DXE 階段的通信有一個初步的理解。

/* 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);

這裏對 PPI 以及 Protocol 的介紹較為簡略,本文主要學習對 UEFI 的啓動過程,細節內容後續學習過程中會陸續補充。

重要的全局結構:

EFI_SYSTEM_TABLEBoot ServicesRuntime Services

系統表:

當 UEFI 應用(如 Bootloader)運行時,會把這個表作為參數傳入efi_main(),讓應用可以訪問 UEFI 服務。

/* 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,它在系統還沒有“交出控制權”給操作系統之前,提供大量的底層服務接口,也就相當於一系列 API,提供上層調用,調用方式如下。

功能類別 示例函數 作用
內存管理 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 不同的是,它提供的服務在操作系統啓動之後仍然存在,這些函數的實現被 OS 的 UEFI 驅動或內核映射進虛擬地址空間。部分服務如下。

功能類別 示例函數 説明
時間日期 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階段的歷史任務宣告完成,系統的控制權正式過渡給操作系統的引導裝載程序。

5.2 關鍵點介紹

BDS 的核心指責是根據系統配置和啓動策略,選擇合適的啓動設備,並執行對應的啓動加載程序。
在 EDK2 中,BDS 階段主要通過以下文件實現:MdeModulePkg/Core/DxeBds/

核心函數入口:

VOID EFIAPI BdsEntry (
  IN EFI_BDS_ARCH_PROTOCOL  *This
)
// 流程包括:
BdsInitialize()				// 初始化控制枱設備;
BdsBootDeviceSelect()		// 啓動設備選擇;
BdsBootViaBootOption()		// 嘗試加載 Boot####;
BdsBootSuccessHandler()		// BdsBootFailHandler():處理成功或失敗結果;
BdsEnterFrontPage()			// 用户交互界面。

具體任務

  1. 創建控制枱設備(Console)。確定系統的輸入輸出設備,鍵盤,顯示器,串口等。建立標準的輸入輸出句柄(ConIn、ConOut、StdErr),使得用户可以看到 BIOS/UEFI 的啓動畫面、輸入命令。

  2. 加載並執行 Boot Manager(引導管理器)。這是 UEFI 規範規定的,系統固件應該包括一個引導管理器,負責引導順序管理。它讀取 Boot OrderBoot Option 等 NVRAM 變量,判斷從哪個設備啓動。

  3. 枚舉所有 Boot Option(啓動選項)。這些選項保存在 UEFI 變量中,如:

    BootOrder       // 啓動順序,例如 [0001, 0003, 0000]
    Boot0000        // 啓動項0,例如 EFI Shell
    Boot0001        // 啓動項1,例如 Windows Boot Manager
    Boot0003        // 啓動項3,例如 UEFI USB Device
    

    每個 Boot Option 包含啓動設備路徑(EFI_DEVICE_PATH)和加載映像文件路徑。

  4. 嘗試加載啓動項中的 EFI 可執行文件。BDS 通過 Boot Services 的 LoadImage()StartImage() 來加載 EFI 應用(例如 bootx64.efi)。通常這些文件存放在 \EFI\BOOT\BOOTX64.EFI,\EFI\Microsoft\Boot\bootmgfw.efi。如果加載失敗,就嘗試下一個 Boot Option。

  5. 處理 Boot Maintenance Manager (BMM)。若所有 Boot Option 均失敗,BDS 會進入 BMM(類似 BIOS Setup 界面)。允許用户修改啓動順序、設置 NVRAM 啓動變量、更新 Boot Option。

  6. 最終移交控制權。成功加載 Bootloader(例如 GRUB、Windows Boot Manager)後:調用 ExitBootServices(),銷燬 Boot Services,把控制權交給 Bootloader,進入操作系統加載階段。

關鍵數據結構

  1. Boot Option(啓動項結構)

    typedef struct {
        UINT32 Attributes;
        UINT16 FilePathListLength;
        CHAR16 Description[];          				// 啓動項名稱(如 "Windows Boot Manager")
        EFI_DEVICE_PATH_PROTOCOL FilePathList[]; 	// 啓動文件路徑
        UINT8 OptionalData[];         				// 啓動時需要傳入的參數
    } EFI_LOAD_OPTION;
    
  2. BootOrder:存儲在 NVRAM 中的啓動順序表。

    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 是瞬態的,它只在交接控制權的瞬間存在。

主要任務

  1. 執行 BootLoader。BDS 階段通過 LoadImage() + StartImage() 啓動 BootLoader,BootLoader 在 UEFI 環境中執行,它是一個標準的 EFI 應用程序。這意味着 BootLoader 也能使用 UEFI 提供的 Boot Services 和 Runtime Services。
  2. 準備加載操作系統內核,BootLoader(例如 GRUB 或 Windows Boot Manager)會解析配置文件,選擇內核映像(kernel image),加載內核到內存,設置命令行參數、RAMDisk、ACPI 表、內存映射等信息,準備 CPU 狀態(模式、分頁、棧等)。
  3. 退出 UEFI 環境。調用 ExitBootServices()。此時,所有 Boot Services 被銷燬,只剩下 Runtime Services
  4. 跳轉到操作系統入口點。

一些關鍵函數

  1. GetMemoryMap()。在調用 ExitBootServices() 之前,BootLoader 必須 先調用這個函數,獲取當前系統的內存佈局,返回一個 MapKey,這個 MapKey 是 ExitBootServices 的憑證(必須匹配當前內存狀態)。
  2. 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 階段是在操作系統已經接過控制權之後,不做過多介紹,簡單説一下此時固件還能作用的 Runtime Services 的相關函數。

功能類別 典型函數 作用
時間服務 GetTime(), SetTime() 獲取/設置系統時間(CMOS時鐘)
虛擬內存服務 SetVirtualAddressMap() 固件映射從物理地址切換到虛擬地址(OS啓用分頁後使用)
變量服務 GetVariable(), SetVariable() 讀取/寫入NVRAM變量(如啓動項、SecureBoot狀態)
重置服務 ResetSystem() 控制系統重啓、關機、S3睡眠等
字符串服務 (已廢棄) 早期版本中用於輸出信息

AL 階段是操作系統關閉電源或重啓前的最後一個階段。其通常在以下情況發生:

  1. 用户執行關機(Shutdown);
  2. 系統執行重啓(Reboot);
  3. 系統進入睡眠/休眠(S3/S4);
  4. 系統掉電(Power Loss)或崩潰。

AL 階段控制權變化:

時間點 控制權歸屬 狀態
OS 正常運行 操作系統 使用 Runtime Services
調用 ResetSystem() 操作系統 → 固件 固件開始復位
重啓/關機完成 固件接管 重新進入 SEC 階段或斷電

結語

本文較為詳細介紹了 UFEI 規範中啓動的主要流程,由於本人是初學者,很多地方理解的不是很深刻,未來學習中會持續修改補充。本文是學習 UEFI 啓動過程的筆記記錄,主要內容源自 AI 搜索整理。


Seriousness is the cornerstone of everything!

Add a new Comments

Some HTML is okay.