PEI Services
1. PEI Services Table介绍
PEI Foundation
建立了一个名为PEI Services Table
的系统表,该表对系统中的所有Pre-EFI初始化模块(PEIMs)可见。
PEI Foundation
在系统初始化时所需要的功能、命令或其他能力,会被抽象然后定义在PEI Services Table
中。
由于PEI阶段直到阶段末尾才有永久性内存可用,因此PEI阶段创建的服务范围无法像后续阶段那样丰富。
由于PEI Foundation
及其临时RAM的位置在构建时未知,因此在每个PEIM的入口点以及每个PEIM到PEIM接口(PPI)的一部分中传递了PEI Services
表的指针。
- 比如下面这个例子,update boot mode的函数:
//
// update boot mode
//
...
...
Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);
...
当它在调用GetBootMode
这个PPI时,也将PeiServices这个指针作为参数一起传入了。
顺便,我们可以看一下GetBootMode
是如何实现的。
/**
EFI_BOOT_MODE GetBootMode() returns current boot mode. If no boot mode
information is available, BOOT_WITH_FULL_CONFIGURATION is returned.
**/
EFI_BOOT_MODE GetBootMode()
{
return GetBootModeHob();
}
/**
Get the system boot mode from the HOB list.
This function returns the system boot mode information from the
PHIT HOB in HOB list.
If the pointer to the HOB list is NULL, then ASSERT().
@param VOID
@return The Boot Mode.
**/
EFI_BOOT_MODE
EFIAPI
GetBootModeHob (
VOID
)
{
EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
HandOffHob = (EFI_HOB_HANDOFF_INFO_TABLE *)GetHobList ();
return HandOffHob->BootMode;
}
可以看到,其实GetBootMode
这个PPI,最终也是通过读取HOB
来获取的BootMode
。这里也可以看到HOB
的用法。
另外,需要注意的是:在PEI Foundation中,PEI Services表使用EFI_TABLE_HEADER
,其中CRC32
字段对PEI是特殊的。该值对PEI是可忽略的,应设置为零。
1.1. PEI Services Table内容
// PI规范版本信息
#define PI_SPECIFICATION_VERSION ((1 << 16) | 90)
// PEI服务表
#define PEI_SERVICES_SIGNATURE 0x5652455320494550
#define PEI_SERVICES_REVISION PI_SPECIFICATION_VERSION
typedef struct EFI_PEI_SERVICES {
EFI_TABLE_HEADER Hdr; // 表头
// PPI函数
EFI_PEI_INSTALL_PPI InstallPpi;
EFI_PEI_REINSTALL_PPI ReInstallPpi;
EFI_PEI_LOCATE_PPI LocatePpi;
EFI_PEI_NOTIFY_PPI NotifyPpi;
// 启动模式函数
EFI_PEI_GET_BOOT_MODE GetBootMode;
EFI_PEI_SET_BOOT_MODE SetBootMode;
// HOB函数
EFI_PEI_GET_HOB_LIST GetHobList;
EFI_PEI_CREATE_HOB CreateHob;
// 固件卷函数
EFI_PEI_FFS_FIND_NEXT_VOLUME2 FfsFindNextVolume;
EFI_PEI_FFS_FIND_NEXT_FILE2 FfsFindNextFile;
EFI_PEI_FFS_FIND_SECTION_DATA2 FfsFindSectionData;
// PEI内存函数
EFI_PEI_INSTALL_PEI_MEMORY InstallPeiMemory;
EFI_PEI_ALLOCATE_PAGES AllocatePages;
EFI_PEI_ALLOCATE_POOL AllocatePool;
EFI_PEI_COPY_MEM CopyMem;
EFI_PEI_SET_MEM SetMem;
// 状态码
EFI_PEI_REPORT_STATUS_CODE ReportStatusCode;
// 重置
EFI_PEI_RESET_SYSTEM ResetSystem;
// (由发布PEIM安装的接口)
// I/O抽象
EFI_PEI_CPU_IO_PPI *CpuIo;
EFI_PEI_PCI_CFG2_PPI *PciCfg;
// 额外的文件系统相关服务
EFI_PEI_FFS_FIND_BY_NAME FfsFindFileByName;
EFI_PEI_FFS_GET_FILE_INFO FfsGetFileInfo;
EFI_PEI_FFS_GET_VOLUME_INFO FfsGetVolumeInfo;
EFI_PEI_REGISTER_FOR_SHADOW RegisterForShadow;
EFI_PEI_FFS_FIND_SECTION_DATA3 FindSectionData3;
EFI_PEI_FFS_GET_FILE_INFO2 FfsGetFileInfo2;
EFI_PEI_RESET2_SYSTEM ResetSystem2;
EFI_PEI_FREE_PAGES FreePages;
} EFI_PEI_SERVICES;
EFI_PEI_SERVICES
是由PEI Foundation
提供的函数集合。这些服务分为以下几类:
(1)管理启动模式(BootMode)
(2)分配早期和永久内存
(3)支持固件文件系统(FFS)
(4)抽象化PPI数据库
(5)创建交接块(HOBs)
PEI Foundation
调用PEIM
时都会传递一个指向EFI_PEI_SERVICES
表的指针。
因此,每个PEIM
都可以访问EFI_PEI_SERVICES
中的服务。
并且与UEFI Boot Service
不同的是,PEI Services没有调用限制,例如UEFI 2.0任务优先级级别(TPL)限制。
具体来说,服务可以从PEIM或Notification Services
中调用。
PEI Services中的一些服务也只是对于平台提供的服务的代理,例如Reset Services
、Status Code
和I/O Abstraction Service
。
这种分区设计旨在为所有PEIM提供一致的接口,而不使PEI Foundation实现受到特定平台的束缚(高复用性)。
任何此表以外的Service都应通过PPI调用。并且,在PEIM将接口实例复制到EFI_PEI_SERVICES
表中之前,PEIM安装的后续服务都将返回EFI_NOT_AVAILABLE_YET
。
2.常见的PEI Service
PEI Service
是由PEI Foundation
在阶段结束时创建的功能、命令或其他能力。由于PEI阶段直到阶段末尾才有永久性内存可用,因此PEI Foundation
在PEI阶段创建的服务无法像后续阶段那样丰富。
PEI服务如下表所示:
表8.1:PEI服务
- PPI服务:管理PEIM到PEIM接口(PPIs),以便在PEIM之间进行调用。接口在PEI基础维护的临时RAM中的数据库中安装和跟踪。
- 启动模式服务:管理系统的启动模式(S3、S5、正常启动、诊断等)。
- HOB服务:创建称为交接块(HOBs)的数据结构,用于向PI架构的下一阶段传递信息。
- 固件卷服务:在固件卷中查找PEIMs和其他固件文件。
- PEI内存服务:提供一组内存管理服务,用于在发现永久性内存之前和之后使用。
- 状态码服务:提供通用的进度和错误码报告服务,例如端口080h或用于简单文本输出的串行端口进行调试。
- 重置服务:提供一种通用的重启系统的方法。
PEI服务的调用约定类似于PPI。有关PPI的更多详细信息,请参阅PEIM到PEIM通信。
2.1 PPI Service
以下服务提供了抽象PPI数据库的接口集:
(1) InstallPpi()
(2) ReinstallPpi()
(3) LocatePpi()
(4) NotifyPpi()
2.2.1 InstallPpi()
这是PEI Foundation
提供的第一个服务。该服务的目的是发布可以用来调用额外PEIMs的接口。
该函数通过GUID在PEI PPI Database
中安装接口。
typedef EFI_STATUS (EFIAPI *EFI_PEI_INSTALL_PPI) (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
);
PeiServices
:指向PEI基础发布的EFI_PEI_SERVICES表的间接指针。
PpiList
:指向调用者要安装的接口列表的指针。类型EFI_PEI_PPI_DESCRIPTOR在“PEIM描述符”中定义。
返回状态码
EFI_SUCCESS:接口已成功安装。
EFI_INVALID_PARAMETER:PpiList指针为NULL。
EFI_INVALID_PARAMETER:PPI描述符列表中的任何一个没有在Flags字段中设置EFI_PEI_PPI_DESCRIPTOR_PPI标志。
EFI_OUT_OF_RESOURCES:PPI数据库中没有额外空间。
该服务允许给定的PEIM向PEI基础注册接口。接口采用遵循EFI_PEI_PPI_DESCRIPTOR格式的记录列表的指针。
由于PEI基础维护的是对列表的指针而不是复制列表,因此列表必须位于PEIM主体中,或者从临时或永久RAM中分配。
列表的长度由EFI_PEI_PPI_DESCRIPTOR中的Flags字段设置了EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST标志的EFI_PEI_PPI_DESCRIPTOR描述。列表中至少应有一个EFI_PEI_PPI_DESCRIPTOR。
可以安装的EFI_PEI_PPI_DESCRIPTOR类型包括EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH和EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK。