UEFI系统的启动遵循UEFI平台初始化标准。UEFI系统从上电到关机可以分为以下7个阶段:
SEC(安全验证)→PEI(EFI前期初始化)→DXE(驱动执行环境)→BDS(启动设备选择)→TSL(操作系统加载前期)→RT(Run Time)→AL(系统灾难恢复期)
下图展示了UEFI系统从加电到关机的7个阶段(以图中竖线为界)。前三个阶段是UEFI初始化阶段,DXE阶段结束后UEFI环境已经准备完毕。BDS和TSL是操作系统加载器作为UEFI应用程序运行的阶段。操作系统加载器调用ExitBootServices()服务后进入RT阶段,RT阶段包括操作系统加载器后期和操作系统运行期。当系统硬件或操作系统出现严重错误不能继续正常运行时,固件会尝试修复错误,这时系统进入AL期。但PI规范和UEFI规范都没有规定AL期的行为。“?”表示其行为由系统供应商自行定义。
一、SEC(Security Phase)安全验证阶段
SEC作为整个系统的起点,可能会遇到各种异常,就需要设置IDT,有了中断描述符表接收异常,就能让系统遭遇意外的情况时不会崩溃,同时它还为PEI阶段的代码设置临时内存的基地址和长度,并传给PEI,最后找到PEI代码入口点,移交控制权,并且处理临时内存。SEC是平台初始化的第一个阶段,计算机加电后首先进入这个阶段。它主要做以下4件事情:
- 接收和处理系统的启动、重启、异常信号。
- SEC phase特色功能”Cache As RAM(CAR)”,在Cache上开辟一片空间作为内存使用。(原因:因为此时内存还没有被初始化,C语言运行时需要内存和栈空间)
- SEC阶段作为可信系统的根。
- 传递系统参数给PEI phase。
(一)SEC阶段的功能
- 接收并处理系统启动和重启的信号,系统加电信号、重启信号、运行过程的异常信号。
- 在SEC阶段时,仅有CPU和CPU内部资源被初始化,而各种外部设备和内存都没有被初始化。因此系统需要一部分临时的内存用于代码和数据的存储,一般称为临时RAM,此时它只能位于CPU内部。最常用的临时RAM是Cache,将它作为初始化临时存储区域。
- 只有SEC phase被系统信任,下面的各个阶段才有被信任的基础。
- SEC phase移交控制权给PEI phase,SEC phase给PEI phase传递的参数如下:
- 栈的地址和大小
- 系统当前的状态
- 可启动固件的地址和大小
- 临时RAM区域的地址和大小
(二)SEC阶段的执行流程
根据临时RAM是否初始化为界限,SEC阶段分为两部分:临时RAM初始化前称为Reset Vector阶段;临时RAM初始化后调用SEC入口函数进入SEC功能区。

1、Reset Vector的执行流程如下:
A)进入固件入口
B)从实模式转换为32位平坦模式
C)定位固件中的BFV
D)定位BFV中的SEC映像
E)若是64位系统,要从32位模式转换为64位模式
F)调用SEC入口函数
2、进入SEC功能区
进入功能区后,首先利用CAR技术初始栈,初始化IDT,初始化EFI_SEC_PEI_HAND_OFF,将控制权交给PEI,并将EFI_SEC_PEI_HAND_OFF传递给PEI。
EFI_SEC_PEI_HAND_OFF结构体很重要,具体如下:
/// /// 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;
讯享网
EFI_SEC_PEI_HAND_OFF结构体中保存了PEI core的运行环境信息,如临时RAM的位置大小、堆栈位置和BFV位置。
1)数据结构的大小。
讯享网 /// /// Size of the data structure. /// UINT16 DataSize;
2)指向BFV的第一个字节,PEI Dispatcher应该搜索PEI模块。
/// /// Points to the first byte of the boot firmware volume, /// which the PEI Dispatcher should search for /// PEI modules. /// VOID *BootFirmwareVolumeBase;
3)BFV的大小,单位是字节。
讯享网 /// /// Size of the boot firmware volume, in bytes. /// UINTN BootFirmwareVolumeSize;
4)指向临时RAM的第一个字节。
/// /// Points to the first byte of the temporary RAM. /// VOID *TemporaryRamBase;
5)临时RAM的大小,以字节为单位。
讯享网 /// /// Size of the temporary RAM, in bytes. /// UINTN TemporaryRamSize;
6)指向PEI可以使用的临时RAM的第一个字节。PeiTemporaryRamBase和PeiTemporaryRamSize所描述的区域不能超出TemporaryRamBase和TemporaryRamSize所描述的区域。这个区域不应该与StackBase和StackSize返回的区域重叠。
/// /// 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;
7)PEI使用的可用临时RAM的大小,以字节为单位。
讯享网 /// /// The size of the available temporary RAM available for /// use by the PEI Foundation, in bytes. /// UINTN PeiTemporaryRamSize;
8)指向堆栈的第一个字节。这可能是由TemporaryRamBase和TemporaryRamSize描述的内存的一部分,也可能是一个完全独立的区域。
/// /// 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;
9)堆栈的大小,以字节为单位。
讯享网 /// /// Size of the stack, in bytes. /// UINTN StackSize;
3、IA32下的SEC入口函数,截取了一部分,详细代码在UefiCpuPkg\SecCore\SecMain.c。SEC的C语言阶段的入口点。SEC汇编代码初始化一些临时内存并建立堆栈后,控制被转移到这个函数。

二、PEI(Pre-EFI Initialization)前期初始化阶段
虽然SEC阶段对CPU和CPU内部的资源进行了初始化。但PEI阶段可用的资源依旧十分有限,该阶段是对内存进行初始化,主要功能是为DXE阶段准备执行环境,将所需要传递给DXE的信息组成HOB(Hand Off Block)列表,最终将控制权转交给DXE。UEFI具有模块化设计的特点,PEI就是一个模块。PEI Image的入口函数调用PEI模块的入口函数PEICore。
(一)PEI阶段的执行流程
1、SEC模块找到PEI Image的入口函数_ModuleEntryPoint,函数位于 MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.c中。
VOID EFIAPI _ModuleEntryPoint( IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList ) { ProcessModuleEntryPointList (SecCoreData, PpiList, NULL); // // Should never return // ASSERT(FALSE); CpuDeadLoop (); }
2、_ModuleEntryPoint函数最终调用PEI模块的入口函数PEICore,进入PEI入口。
讯享网VOID EFIAPI PeiCore ( IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreDataPtr, IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList, IN VOID *Data )
以OVMF为例,从SEC阶段分析得知,PEI入口函数是PeiCore,位置:
edk2\MdeModulePkg\Core\Pei\PeiMain\PeiMain.c,以上代码只是PeiCore函数的一部分。
3、根据SEC阶段传入的信息初始化PS(PEICore Service)。
// // Initialize PEI Core Services // InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
4、调度系统中的PEIM(PEI Module),准备HOB列表。
讯享网 // // Call PEIM dispatcher // PeiDispatcher (SecCoreData, &PrivateData);
5、调用PEIServices得到DXE IPL PPI的Entry服务(即DXELoadCore)。
// // Lookup DXE IPL PPI // Status = PeiServicesLocatePpi ( &gEfiDxeIplPpiGuid, 0, NULL, (VOID )&TempPtr.DxeIpl ); ASSERT_EFI_ERROR (Status);
注意:PPI与DXE阶段的Protocol类似,每个PPI都是一个结构体,包含有函数指针和变量。每个PPI都有一个GUID。通过PEIServices的LocatePPI服务可以找到GUID对应的PPI实例。
6、 DXELoadCore服务找出并运行DXEImage的入口函数,将HOB列表传递给DXE。
讯享网 // DXE IPL Status = TempPtr.DxeIpl->Entry ( TempPtr.DxeIpl, &PrivateData.Ps, PrivateData.HobList );
PEI阶段执行流程图如下:

PEI阶段执行流程完整描述:SEC模块找到PEI Image的入口函数 _ModuleEntryPoint, _ModuleEntryPoint函数最终调用PEI模块的入口函数PEICore,进入PEICore后,首先根据从SEC阶段出入的信息设置PEI Core Services,然后调用PEIDispatcher执行系统总的PEIM,在内存初始化完成后,系统切换栈并重新进入PEICore。重新进入PEICore后使用的不再是临时RAM 而是真正的内存。在所有PEIM执行完成后,调用PEIServices的LocatePPI服务得到DXE IPL PPI,并调用DXE IPL PPI的Entry服务(即DEXLoadCore),找出DEX Image的入口函数,执行DXE Image函数并将HOB列表传递给DXE。
(二)具体调用的系统中的PEIM如下
- CPU PEIM(提供CPU相关功能,如进行Cache设置、主频设置等等)。
- 平台相关的PEIM(初始化内存控制器、I/O控制器等等)。
- 内存初始化PEIM(对内存进行初始化,此时内存才可以被使用,之前使用的是CPU模拟的临时内存)。
(三)PEI阶段的功能
- 初始化内存
- 为DXE阶段准备执行环境
具体为:
基本的Chipset初始化
Memory Sizing
BIOS Recovery
S3 Resume
切换Stack到Memory(Disable CAR, Enable Cache)
启动DXEIPL(DXE Initial Program Loader)
(四)PEI划分
PEI内核(PEI Foundation):负责PEI基础服务和流程。
PEIM(PEI Module)派遣器:找出系统中所有的PEIM,并根据PEIM之间的依赖关系按顺序执行PEIM。PEI阶段对系统的初始化主要由PEIM完成。

每个PEIM都是一个独立的模块。通过PEIMServices,PEIM可以调用PEI阶段提供的系统服务。通过调用这些服务,PEIM可以访问PEI内核。PEIM之间的通信通过PPI(PEIM-to-PEIM Interfaces)完成。

(五)为什么要有PEI Phase?
1. ROM空间的问题,所有的Code都没有压缩。
2. Memory还没有初始化。
3. Chipset没有初始化。
三、DXE(Driver Execution Environment)驱动执行环境阶段
DXE阶段执行大部分系统初始化工作,进入此阶段时,已经有足够的内存可以使用,因此可以完成大量的驱动加载和初始化工作。遍历固件中所有的Driver,当Driver所依赖的资源都满足要求时,调度Driver到执行队列执行,直到所有的Driver都被加载和执行完毕,系统完成初始化。
(一)DXE阶段的执行流程
1、DXE Core入口。
VOID EFIAPI DxeMain ( IN VOID *HobStart )
2、根据HOB列表初始化系统服务。
讯享网 // VectorInfoList = NULL; GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart); if (GuidHob != NULL) { VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob)); } Status = InitializeCpuExceptionHandlersEx (VectorInfoList, NULL); ASSERT_EFI_ERROR (Status);
3、初始化DXE调度程序。
// // Initialize the DXE Dispatcher // CoreInitializeDispatcher ();
4、负责调用Dispatcher,所有的DXE Driver在这个函数中被检测并执行。
讯享网 CoreDispatcher ();
5、 传输控制到BDS架构协议。

DXE阶段的执行流程如下:

(二)DXE阶段的功能
- 几乎所有的硬件初始化都在这里完成。
- 产生EFI System Table,来提供各种Service供所有阶段使用。
- 把控制权交给BDS来BOOT OS。
(三)涉及到的元件及功能
- DXE Core:可视为DXE的核心,用来Dispatch DXE Driver和产生EFI System Table,以提供BOOT Service,RunTime Service,DXE Service,负责DXE基础服务和执行流程。
- DXE Driver:被DXE Core所读取,用来做各种硬件初始化,产生protocol和其它Service。
- DXE Dispatcher:DXE Core的一部分,以正确的顺序来搜寻和执行DXE Driver,负责调度执行DXE驱动,初始化系统设备。DXE提供的基础服务包括系统表、启动服务、Run Time Services。
- DXE architecture protocol:由DXE Driver所产生,是DXE Core和HardWare沟通的唯一媒介,所以没有install完全不能开机。
- EFI System Table: 包含了许多pointer,如所有EFI System Table,Configuration Table,Handledatabase,Console Device。
(四)DXE Architecture Protocol种类及其功能
1、Security: 提供 DXE core 验证 firmware volume中的程序是否可用。
2、Cpu: 提供cpu的service,如管理cache,管理中断,取得处理器频率,查询处理器的timer。
3、下面是一个结构体,它用来提供一个微小的延时,单位为百万分之一秒。
typedef struct _EFI_METRONOME_ARCH_PROTOCOL { EFI_METRONOME_WAIT_FOR_TICK WaitForTIck; UINT32 TickPeriod; }EFI_METRONOME_ARCH_PROTOCOL;
4、Timer: 提供固定时间的中断,使Dxe Core Dispatch 完成所有driver后,会将控制权交给BDS。
四、BDS (Boot Device Select)启动设备选择阶段
该阶段所做的任务:
在BDS阶段,主要是初始化控制台设备,加载执行必要的设备驱动,根据用户的选择,执行相应的启动项。
概述:
DXE阶段最终会调用BDS ARCH Protocol的接口EFI_BDS_ARCH_PROTOCOL.Entry()转入BDS阶段。BDS阶段负责加载额外的驱动,与用户交互,必要的硬件初始化,并转入操作系统。
这个阶段前面是DXE后面是OS Loader或shell,同时所有定制化的东西都在这个阶段完成,最主要的Setup page(UI界面)是不同的,不同的BIOS Vendor的UI是不一样的。造成直接影响的三个决策是:启动策略的管理、启动设备的选择、Setup界面。

从DXE拿到控制权后由用户去选择启动设备,开始转交控制权。在过程中可能失败,为了防止此类现象出现定义了Watch Dog来实时监控状态,如果失败则会返回启动界面,BDS再从下一个启动选项开始启动,直到启动成功,如上图所示。所以在BDS阶段要通过Boot Option这个Variable准备好所有可能的Boot选项,可以提供给用户选择。
在整个BDS phase还需要提供用户一个可配置的UI界面,该界面包含若干配置选项信息,这些信息完全是客户定制化的,客户想给用户暴露什么信息,就提供什么信息,正常时候报给客户的信息有:启动列表(哪些是设备是可以启动的)、基本的一些配置(Seurite boot如果这个选项是强制选项,那么根本不会暴露给用户)、显示的页面(宽屏或是窄屏)、安全相关的passwd、硬件相关的CPU芯片组的工作,硬盘工作模式等等。
(一)BSD阶段执行流程
BDS阶段是可以用于定制化的module,可以根据客户要求进行相应的设计。
1、Entry()的服务例程。连接好设备,初始化控制台,并尝试启动选项。BDS 的入口函数,负责安装EFI_BDS_ARCH_PROTOCOL 协议,以让DXE Foundation 调用。
讯享网VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This )
2、Timeout用于在例如设备启动过程中时间的累计计算,如果在时间内一直未成功,则会进行下一个设备启动。
BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
3、函数用于初始化一个加载选项。
讯享网 Status = EfiBootManagerInitializeLoadOption ( &LoadOption, LoadOptionNumberUnassigned, LoadOptionTypePlatformRecovery, LOAD_OPTION_ACTIVE, L"Default PlatformRecovery", FilePath, NULL, 0 );
4、在调用平台代码之前初始化ConnectConIn事件。通过PcdGetbool来判定条件进而触发事件函数 (用于实现定制化要求)。
if (PcdGetBool (PcdConInConnectOnDemand)) { Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, BdsDxeOnConnectConInCallBack, NULL, &gConnectConInEventGuid, &gConnectConInEvent ); if (EFI_ERROR (Status)) { gConnectConInEvent = NULL; } }
5、执行平台初始化,可以通过OEM/IBV定制,可以在PlatformBootManagerBeforeConsole中完成的事情。
讯享网 PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);
6、基于控制台设备变量ConIn、ConOut和ErrOut连接所有控制台设备。
EfiBootManagerConnectAllDefaultConsoles ();
7、尝试启动EFI启动选项。这个例程设置L“BootCurent”,并通知EFI准备好启动事件。
讯享网EfiBootManagerBoot (&BootManagerMenu);
8、整个启动函数,包括枚举所有boot option ,然后判断UEFI还是Legacy启动,Legacy启动通过读MBI进行;UEFI启动通过读取特定路径下的BOOt信息,根据Boot Option优先级选择设备启动。
BdsBootDeviceSelect ();
(二)BDS Steps
- 初始化语言和字符串数据库
- 获得当前启动模式
- 基于启动模式建立设备清单
- 连接设备
- 检测input output设备
- 执行内存测试
- 过程引导选项

(三)执行策略
- 初始化控制台console设备,查看系统有多少可以启动的设备。
- 启动所有检测到的设备,加载Driver。
- 检测启动console设备,即输入输出设备。
- 根据收集到的所有信息,提供一个setup的UI界面,终端用户可以在此选择,当用户真正选择启动选项的时候,BDS就会加载启动选项里的OS loader,最后移交真正的控制权给OS Loader ,由OS Loader 转移控制权给OS。
(四)BDS三大任务
console初始化、Driver初始化、BootDeviceSelect
具体包括:
初始化快捷键服务、初始化SystemTable 中的FirmwareVendor 和FirmwareRevision 域、平台相关BDS 初始化、初始化HwErrRecSupport 系统变量、加载操作系统等。
当加载项其启动失败时,系统将重新执行DXE Dispatcher以加载更多的驱动,然后重新尝试加载驱动项。BDS策略通过全局NVRAM变量配置,这些变量可以被运行时服务的GetVariable()读取,通过SetVariable()设置(如BootOrder定义了启动顺序,Boot对应不同的启动项,#为十六进制数)。当用户选中某个启动项(或进入系统默认启动项)后,OS Loader启动,系统进入TSL阶段。
五、TSL(Transient System Load)操作系统加载前期阶段
TSL阶段是OS Loader执行的第一个阶段,为OS Loader准备执行环境,OS Loader调用ExitBootService结束启动服务,进入RunTime阶段。
TSL阶段被称为临时系统的原因在于它为操作系统加载器准备执行环境。虽然是临时系统,但是已经具备操作系统的雏形,UEFI Shell是这个临时系统的人机交互界面。正常运行中,系统不会进入UEFI Shell,而是直接执行OS Loader,只有在用户干预或是操作系统加载器出现严重问题时才会进入UEFI Shell。
在TSL阶段,系统资源管理通过BS管理,BS提供的服务如下:
- 事件服务:事件是异步操作的基础。有了事件的支持,才可以在UEFI系统内执行并发操作。
- 内存管理:主要提供内存的分配与释放,管理系统的内存映射。
- Protocol管理:提供了安装Protocol与卸载Protocol的服务,以及注册Protocol通知函数(该函数会在Protocol安装时调用)的服务。
- Protocol的实用类服务:包括Protocol的打开与关闭,查找支持protocol的控制器。
- 驱动管理:包括用于将驱动安装到控制器的connect服务,及将驱动从控制器上卸载的disconnect服务。
- Image管理:此类服务包括加载,卸载,启动和推出UEFI应用程序或驱动。
- ExitBootServices:用于结束启动服务,注销BS。
六、 RT(Run Time)运行阶段
在RT阶段,OS Loader已经完全取得了系统的控制权,因此要清理和回收一些之前被UEFI占用的资源,runtime services随着操作系统的运行提供相应的运行时的服务,这个期间一旦出现错误和异常,将进入AL进行修复。
RT阶段提供的服务如下:

七、AL(After Life)灾难恢复阶段
在RT阶段如果系统(硬件或是软件)遇到灾难性错误,系统固件需要提供错误处理以及灾难恢复机制,这种机制运行在AL阶段。根据厂家自定义修复方案,UEFI和UEFI PI均未对AL阶段的行为和规范进行定义。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/16464.html