PEI Foundation
1、PEI Foundation简介
PEI Foundation
是一个独立的二进制镜像,文件类型为EFI_FV_FILETYPE_PEI_CORE
。该二进制image由以下部分组成:
(1)认证部分
(2)可能是PE32+格式的代码镜像部分
如果组成PEI基础的代码不是PE32+镜像,那么它是一个原始二进制文件,其最低地址是PEI Foundation的入口点。
PEI基础由安全(SEC)阶段发现并认证。
- 有关
Section
和File Type
的详细信息,参阅《Platform Initialization Specification》第3卷。
2、PEI Foundation 和 PEI Dispatcher
PEI Foundation
围绕PEI Dispatcher
展开。
PEI Dispatcher
的主要任务有:
1.按照有序的方式,将控制权交给PEIMs(Pre-EFI Initialization Modules)
。
2.协助PEIM
之间通信。
PEIM
之间通信的核心资源是PPI(PEIM到PEIM接口)
。PPI的引用可以通过安装接口或通知接口来管理。
3、PEI执行的先决条件
PEI阶段从合乎PI架构,并且合规启动过程的SEC
阶段接手控制。
PEI阶段在开始执行之前必须满足以下最低先决条件:
(1)处理器执行模式
(2)访问包含PEI Foundation
的固件卷
3.1 处理器执行模式 (IA-32)
在IA-32英特尔架构中,PI架构的安全(SEC
)阶段负责将处理器置于原生线性地址模式,通过该模式可以访问处理器的完整地址范围,用于代码、数据和堆栈。
例如,“平坦32”是IA-32处理器执行PEI阶段的模式。处理器必须处于其最特权的“ring 0”模式,或等效模式,并能够访问所有内存和I/O空间。
此先决条件严格依赖于处理器架构。
3.2 访问引导固件卷FV 和 其它启动关键固件卷FV
获得SEC
阶段交接控制的程序称为PEI Foundation
。
通常情况下,PEIMs
并不固定存放在某一类FV中。PEIMs
可能驻留在引导固件卷(BFV
)或其他FVs中。
但是有一个“特殊”PEIM必须驻留在引导固件卷BFV
中,以提供有关其他FVs位置的信息。
每个在BFV和其他关键FVs(如PEI Foundation
所在位置)中所需的启动文件,都必须能够被PEI阶段发现并验证。
只有这样,PEI阶段才能确定这些FVs是否已损坏。
PEI Foundation
和一些PEIMs将被存储在某种相对防篡改的非易失性存储(NVS)中。
这种存储预计与带有唯一ID的Flat文件系统相当。NVS特定的规则可能会影响某些存储考虑,但需要一个标准的数据机制,通过ID定位PEIMs。
PI架构描述了PI固件卷格式和PI固件文件系统格式,以及使用GUID命名文件的约定。
这些标准对PEI而言是架构性的,因为PEI阶段需要直接支持这种文件系统。
BFV只能是EFI_FIRMWARE_FILE_SYSTEM2_GUID
类型。
PEI Foundation
以及一些用于恢复的PEIMs
,必须被锁定在不可更新的FV中,或者必须能够通过“Fault Tolerant
”机制进行更新。
Fault Tolerant
机制的设计是这样的:即使系统在任何时间点停止,旧的(更新前)PEIM或新更新的PEIM也完全有效。
并且PEI阶段可以确定哪一个是有效的。
4. PEI Foundation Entry Point
5.PEI Dispatcher
PEI Dispatcher
的任务是按照有序的方式将控制权交给PEIMs。
PEI Dispatcher
包含一个单独的阶段。在此阶段,PEI Foundation
将检查两类固件卷的文件:
EFI_FV_FILETYPE_PEIM
或EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
类型文件
(有关文件类型定义,请参阅《Platform Initialization Specification》第3卷)。
PEI Dispatcher
将检查依赖表达式(depex
)和每个固件文件中的可选先验文件,以确定PEIM何时有资格被调度。
depex的二进制编码与PEIM的depex相同。
6. PEI 调度过程排序
PEIMs
并不会按照指定的顺序执行,或者说,不能期望它们会按照指定的顺序执行。简单来说,当一个PEIM
执行时,如果它的依赖关系没有满足,那么它就会被跳过,等待满足后再继续执行。在此期间,后续PEIM将会被执行。
举个例子,芯片组初始相关的PEIM执行前,需要处理器初始化完成,而内存初始化PEIM
有需要芯片组初始化完成。这些隐藏的依赖关系,也隐藏着执行顺序要求。
不仅如此,这些相关的PEIMs
可能是不同组织共同编写而成,而且他们可能位于不同的固件卷FVs中。
有时候我们可以借助update或者build的办法,来解决排序的问题,但是这些办法其实并不可靠。比如当我们在一个主板上更换一个板卡,板卡上有CPU和其固件。这时,我们如果更换了板卡,就可能导致系统无法正常工作。
为了满足上述需求和解决弊端,PEI阶段需要实现一个机制,这个机制可以在没有内存的前提下,允许不同PEIMs
在得到满足之后再继续执行。
6.1 机制的表示
机制通过GUID
表示,每个GUID
代表一个特定的要求。
要求通过以下两组数据结构表示:
(1)PEIM
的依赖表达式(depex)
(2)PEI Foundation
在PPI数据库中维护的已安装PPI集合
这种机制为PEIMs
提供了一种“弱排序”。如果PEIMs
A和B都消费X(记作AcX和BcX),一旦PEIM
(C)产生X(CpX),A和B就可以执行。不过关于A和B的执行顺序没有定义。
我们来看个例子:对于一个Peimain.inf
来说,需要产生AprioriFileName
和EfiFirmwareFileSystem
,那么它就会将需要的PEIMs
,在自身的inf
文件中,以GUID
的形式列出:
例如:PeiAprioriFileName
, EfiFirmwareFileSystem2
和EfiFirmwareFileSystem3
## A part of Peimain.inf file
...
[Guids]
gPeiAprioriFileNameGuid ## SOMETIMES_CONSUMES ## File
gEfiFirmwareFileSystem2Guid
gEfiFirmwareFileSystem3Guid
...
6.2 PEI_APRIORI_FILE
PEI_APRIORI_FILE
是一种特殊的文件,并且是可选的。它位于固件卷FV中,主要功能是指定模块执行顺序,补充了PEI依赖表达式的功能缺失,增加了平台设计的灵活性。
当没有选用PEI_APRIORI_FILE
机制的时候,根据普通依赖表达式所执行的PEIMs并不存在严格的顺序。PEIMs之间的执行顺序在不同平台或者环境下,执行顺序并不完全相同。
固件卷中最多只能有一个PEI_APRIORI_FILE
,并且有统一的GUID文件名PEI_APRIORI_FILE_NAME_GUID
,供PEI Foundation
找到并且调度。PEI_APRIORI_FILE
文件的内容应该是PEI_APRIORI_FILE_CONTENTS
类型,可能包含0个或者多个Entries。
下面是相关原型定义:
#define PEI_APRIORI_FILE_NAME_GUID \{0x1b45ccθa,0x156a,0x428a,0xaf62,0x49,0×86,\0x4d,0xa0,0xe6,0xe6}
typedef struct {
EFI_GUID FileNamesWithinVolume[NumberOfModulesInVolume];
// Optional list of file-names
}PEI_APRIORI_FILE_CONTENTS;
PEI Dispatcher发现一个固件卷FV的时候,首先会查找PEI_APRIORI_FILE
。注意,固件卷中所列出的PEI_APRIORI_FILE
中的相关PEIMs,只能存在于当前固件卷FV中,不允许跨卷映射。
看个例子:
### Sample.fdf
APRIORI PEI {
INF StatusCodePei.inf
INF NvramPei.inf
INF Pcd.inf
INF RomLayoutPei.inf
}
INF CapsulePei.inf
INF ResetSystemPei.inf
Sample.fdf
是一个UEFI BIOS的固件描述类型的文件,在其中会描述相关inf模块的顺序和其他信息(更加详细的介绍可以自行搜索)。
在上述平台中,前四个inf模块StatusCodePei.inf
,NvramPei.inf
,Pcd.inf
,RomLayoutPei.inf
是存在严格执行顺序的,而后两个并不一定会顺序执行。