UEFI的启动流程
前言
UEFI的启动共有7个阶段,分别是:SEC->PEI->DXE->BDS->TSL->RT->AL,下面以UDK代码的形式记录下整个流程。
SEC 阶段
SEC是UEFI启动流程的第一个阶段,此阶段又可分为前后两部分,前部分为Pre-SEC,后部分为SEC入口。
1.Pre-SEC
在CPU发出RESET信号后,开始执行第一行代码,x86的架构定义的第一行代码地址是0xFFFF FFF0,位于UefiCpuPkg\ResetVector\Vtf0\Ia16\ResetVectorVtf0.asm中,如下:
resetVector: ; ; Reset Vector ; ; This is where the processor will begin execution ; nop nop jmp EarlyBspInitReal16
X86的机器可以用RW查看0xFFFF FFF0处的内存,如下:
这里所看到的是机器码,90 表示汇编中的nop空操作,E9表示汇编指令中的Jmp,后是跳转的地址。在IA-32架构中,SEC文件只有16个byte的空间在0xFFFF FFF0处作为入口点(Ref1)。
通过跟踪EarlyBspInitReal16可定位到文件UefiCpuPkg\ResetVector\Vtf0\Main.asm中:
;------------------------------------------------------------------------------ ; @file ; Main routine of the pre-SEC code up through the jump into SEC ; ; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.<BR> ; This program and the accompanying materials ; are licensed and made available under the terms and conditions of the BSD License ; which accompanies this distribution. The full text of the license may be found at ; http://opensource.org/licenses/bsd-license.php ; ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ; ;------------------------------------------------------------------------------ BITS 16 ; ; Modified: EBX, ECX, EDX, EBP ; ; @param[in,out] RAX/EAX Initial value of the EAX register ; (BIST: Built-in Self Test) ; @param[in,out] DI 'BP': boot-strap processor, or ; 'AP': application processor ; @param[out] RBP/EBP Address of Boot Firmware Volume (BFV) ; @param[out] DS Selector allowing flat access to all addresses ; @param[out] ES Selector allowing flat access to all addresses ; @param[out] FS Selector allowing flat access to all addresses ; @param[out] GS Selector allowing flat access to all addresses ; @param[out] SS Selector allowing flat access to all addresses ; ; @return None This routine jumps to SEC and does not return ; Main16: OneTimeCall EarlyInit16 ; ; Transition the processor from 16-bit real mode to 32-bit flat mode ; OneTimeCall TransitionFromReal16To32BitFlat BITS 32 ; ; Search for the Boot Firmware Volume (BFV) ; OneTimeCall Flat32SearchForBfvBase ; ; EBP - Start of BFV ; ; ; Search for the SEC entry point ; OneTimeCall Flat32SearchForSecEntryPoint ; ; ESI - SEC Core entry point ; EBP - Start of BFV ; %ifdef ARCH_IA32 ; ; Restore initial EAX value into the EAX register ; mov eax, esp ; ; Jump to the 32-bit SEC entry point ; jmp esi %else ; ; Transition the processor from 32-bit flat mode to 64-bit flat mode ; OneTimeCall Transition32FlatTo64Flat BITS 64 ; ; Some values were calculated in 32-bit mode. Make sure the upper ; 32-bits of 64-bit registers are zero for these values. ; mov rax, 0x00000000ffffffff and rsi, rax and rbp, rax and rsp, rax ; ; RSI - SEC Core entry point ; RBP - Start of BFV ; ; ; Restore initial EAX value into the RAX register ; mov rax, rsp ; ; Jump to the 64-bit SEC entry point ; jmp rsi %endif
该文件主要完成几个任务:
1).从16位Real Mode切换到32 Flat Mode(通过该模式可以访问代码,数据和堆栈的处理器的整个地址范围,是PEI入口的先决条件之一,Ref2)
2).查找Boot Firmware Volume (BFV,存放PEI相关代码部分,Ref3)
3).查找SEC入口点
4).初始化临时内存(Cache As Ram)
5).若是64位系统,则切换到64位Flat Mode
6).调用SEC入口SecStartup
; ; Pass entry point of the PEI core ; mov edi, 0FFFFFFE0h push DWORD PTR ds:[edi] ; ; Pass BFV into the PEI Core ; mov edi, 0FFFFFFFCh push DWORD PTR ds:[edi] ; ; Pass stack size into the PEI Core ; mov ecx, [ebp - 4] mov edx, [ebp - 8] push ecx ; RamBase sub edx, ecx push edx ; RamSize ; ; Pass Control into the PEI Core ; call SecStartup
2.SEC入口
位于UefiCpuPkg\SecCore\SecMain.c中
1.从BFV中找到PEI入口(SecStartup -> SecStartupPhase2 -> FindAndReportEntryPoints)
2.将初始化的临时内存地址及BFV地址等数据传递给PEI入口((*PeiCoreEntryPoint) (SecCoreData, PpiList)),SecCoreData定义如下:
/// /// EFI_SEC_PEI_HAND_OFF structure holds information about /// PEI core's operating environment, such as the size of location of /// temporary RAM, the stack location and BFV location. /// typedef struct _EFI_SEC_PEI_HAND_OFF { /// /// Size of the data structure. /// UINT16 DataSize; /// /// Points to the first byte of the boot firmware volume, /// which the PEI Dispatcher should search for /// PEI modules. /// VOID *BootFirmwareVolumeBase; /// /// Size of the boot firmware volume, in bytes. /// UINTN BootFirmwareVolumeSize; /// /// Points to the first byte of the temporary RAM. /// VOID *TemporaryRamBase; /// /// Size of the temporary RAM, in bytes. /// UINTN TemporaryRamSize; /// /// Points to the first byte of the temporary RAM /// available for use by the PEI Foundation. The area /// described by PeiTemporaryRamBase and PeiTemporaryRamSize /// must not extend outside beyond the area described by /// TemporaryRamBase & TemporaryRamSize. This area should not /// overlap with the area reported by StackBase and /// StackSize. /// VOID *PeiTemporaryRamBase; /// /// The size of the available temporary RAM available for /// use by the PEI Foundation, in bytes. /// UINTN PeiTemporaryRamSize; /// /// Points to the first byte of the stack. /// This are may be part of the memory described by /// TemporaryRamBase and TemporaryRamSize /// or may be an entirely separate area. /// VOID *StackBase; /// /// Size of the stack, in bytes. /// UINTN StackSize; } EFI_SEC_PEI_HAND_OFF;
PEI 阶段
PEI阶段的入口函数是PeiCoreEntry:
/** This routine is invoked in switch stack as PeiCore Entry. @param SecCoreData Points to a data structure containing information about the PEI core's operating environment, such as the size and location of temporary RAM, the stack location and the BFV location. @param Private Pointer to old core data that is used to initialize the core's data areas. **/ VOID EFIAPI PeiCoreEntry ( IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, IN PEI_CORE_INSTANCE *Private ) { // // Entry PEI Phase 2 // PeiCore (SecCoreData, NULL, Private); }
PeiCoreEntry又调用PeiCore,位于文件:MdeModulePkg\Core\Pei\PeiMain\PeiMain.c中,此函数主要初始化Pei Core Service,然后再调用PeiDispatcher调度PEI Module(PEIM),每个PEIM都是一个独立的模块,负责初始化相应的某一功能,如初始化CPU,内存控制器及其它IO控制器等,并把相关数据存储在HOB中。
PEIM调度完毕,真正的内存便可以使用了,此时PeiCore会重新调用一次,将初始化的数据从临时内存迁移到新的内存中。接着创建HOB List(HOB,一种内存中的数据存储机制,用来传递PEI阶段信息到DXE阶段),然后再通过一个特殊的PPI (DXE IPL PPI)调用并将HOB List传递给DXE入口,进入下一阶段。
Hob list视图(图源Beyond BIOS)
// // Lookup DXE IPL PPI // Status = PeiServicesLocatePpi ( &gEfiDxeIplPpiGuid, 0, NULL, (VOID **)&TempPtr.DxeIpl ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { // // Report status code to indicate DXE IPL PPI could not be found. // REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MAJOR, (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND) ); CpuDeadLoop (); } // // Enter DxeIpl to load Dxe core. // DEBUG ((EFI_D_INFO, "DXE IPL Entry\n")); Status = TempPtr.DxeIpl->Entry ( TempPtr.DxeIpl, &PrivateData.Ps, PrivateData.HobList );
DXE 阶段
DXE阶段的入口是DxeMain,位于MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c中。
首先根据HOB List初始化各种Sevices:
接着像PEI阶段调度PEIM一样,通过CoreDispatcher初始化平台相关的驱动,如PS2设备驱动,SATA设备驱动,USB设备驱动,PCIE设备驱动等(注意此时的Driver只是注册到系统中,并未执行),初始化完之后UEFI的基本环境已经准备完成了,然后调用BDS入口进入下一阶段。
BDS 阶段
BDS的入口是BdsEntry,位于MdeModulePkg\Universal\BdsDxe\BdsEntry.c中,这个阶段的主要任务是:
1.调用BdsLibConnectAll()执行(Connect)平台所需的Driver
2.找到可引导设备并调用gBS->LoadImage加载设备中的efi boot loader文件,此文件存放的路径是固定的,位于磁盘中efi/boot/目录,boot loader的命名一般为bootXX.efi,XX表示平台类别,如x86 64位则为bootx64.efi,MIPS平台则为bootmips.efi。加载成功则进入下一阶段。
TSL 阶段
此阶段是bootloader运行的阶段,它将调用ExitBootService释放EFI的资源,如DXE driver,但会保留一些必要的Run Time Service用来与OS交互,然后再启动OS。
RT 阶段
即OS运行阶段
AL 阶段
在OS运行期间发生灾难性错误,系统固件要进行错误处理和恢复时的阶段称为AL。
参考文档
Ref1:[VOLUME 1: Platform Initialization Specification] -> 5.1.2.4章节
Ref2:[VOLUME 1: Platform Initialization Specification] -> 5.1.2.1章节
Ref3:[VOLUME 1: Platform Initialization Specification] -> 5.1.1章节
版权声明:
作者:bin
链接:https://ay123.net/mystudy/uefi/955/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论