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/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
UEFI的启动流程
前言 UEFI的启动共有7个阶段,分别是:SEC->PEI->DXE->BDS->TSL->RT->AL,下面以UDK代码的形式记录下整个流程。 SEC 阶段 SEC是UEFI启动流……
<<上一篇
下一篇>>