UEFI Platform Integration Specification, version 1.7 Errata A
1 简介
1.1 概述
该规范定义了实现平台初始化 (PI) 规范(以下简称“PI 架构”)的 Pre-EFI 初始化 (PEI) 阶段所需的核心代码和服务。
此 PEI 核心接口规范 (CIS) 执行以下操作:
- 描述 PEI 阶段的基本组件
- 为 UEFI PI 工作组 (PIWG) 在架构上要求的服务和功能提供代码定义
- 描述固件执行的后续阶段所需的机器准备
- 讨论描述系统重启类型的状态变量
有关更多信息,请参阅下面的“PEI CIS 的组织”。
1.2 PEI CIS 的组织
该 PEI 核心接口规范的组织方式如表 1-1 所示。
由于 PEI Foundation 只是基于 PI 架构的固件解决方案的一个组件,因此本文档中引用了许多其他规范。
Table 1-1: Organization of the PEI CIS
章节 | 描述 |
---|---|
概述 | 描述 PEI 的主要组件,包括 PEI 服务、引导模式、PEI 调度程序和 PEIM。 |
“PEI Services Table” | 描述维护 PEI 服务的数据结构。 |
“Services - PEI” | 详细说明构成 PEI 服务的每个功能. |
“PEI Foundation” | 描述 PEI Foundation 及其操作方法以及 PEI Dispatcher 及其相关的依赖表达式语法。 |
“PEIMs” | 描述 Pre-EFI 初始化模块 (PEIM) 的格式和使用。 |
“Architectural PPIs” | 包含 PEI 基金会使用的 PEIM 到 PEIM 接口 (PPI)。 |
“额外的 PPIs” | 包含可以存在于平台上的 PPI。 |
“PEI to DXE Handoff” | 描述 PEI 阶段调用 DXE 阶段时机器和内存的状态。 |
“Boot Paths” | 描述 PEI 阶段支持的重启模式和行为。 |
“PEI 物理内存使用 | 描述 PEI 阶段的内存映射和内存使用情况。 |
“Itanium® 处理器系列独有的特殊路径” | 包含 Itanium® 处理器系列独有的 PEI 期间流程。 |
“安全 (SEC) 阶段信息” | 包含 PEI 之前发生的执行阶段的概述。 |
“依赖表达式语法” | 描述了一种工具的 BNF 语法,该工具可以将包含依赖表达式的文本文件转换为存储在固件卷中的 PEIM 的依赖部分。 |
“TE 映像” | 描述 TE 可执行文件的格式。 |
“TE 映像创建” | 描述了如何从 PE32 可执行文件创建 TE 可执行文件。 |
“TE 映像加载” | 描述了 TE 可执行文件如何加载到内存中。 |
1.3 本文档中使用的约定
本文档使用下面描述的排版和说明约定。
1.3.1 数据结构描述
支持的处理器是“little endian”机器。
这种区别意味着内存中多字节数据项的低位字节位于最低地址,而高位字节位于最高地址。
一些支持的处理器可能被配置为“小端”和“大端”操作。
所有设计为符合本规范的实现都将使用“小端”操作。
在一些内存布局描述中,某些字段被标记为保留。
软件必须将这些字段初始化为零并在读取时忽略它们。
在更新操作中,软件必须保留任何保留字段。
本文档中描述的数据结构一般采用以下格式:
结构名称:数据结构的正式名称。
摘要:数据结构的简要说明。
原型:数据结构的“C 风格”类型声明。
参数:数据结构原型中每个字段的简要说明。
描述:对数据结构提供的功能的描述,包括调用者应该注意的任何限制和注意事项。
相关定义:仅由该数据结构使用的类型声明和常量。
1.3.2 程序说明
本文档中描述的过程通常采用以下格式:
ProcedureName():过程的正式名称。
摘要:程序的简要说明。
原型:定义调用序列的“C 风格”过程头。
参数:过程原型中每个字段的简要说明。
描述:对接口提供的功能的描述,包括调用者应该注意的任何限制和注意事项。
相关定义:仅由该过程使用的类型声明和常量。
返回的状态代码:接口返回的任何代码的描述。 执行此表中列出的任何状态代码都需要该过程。
可能会返回额外的错误代码,但它们不会通过标准一致性测试进行测试,
并且任何使用该过程的软件都不能依赖于实现可能提供的任何扩展错误代码。
1.4 Requirements
本文档是架构规范,是统一 EFI 论坛定义和发布的平台初始化架构 (PI Architecture) 规范系列的一部分。
PI 架构的主要目的是为可能来自不同供应商的固件组件提供一个互操作性表面。
因此,符合本规范的责任落在作为规范一部分描述的设施的生产者和消费者身上。
通常,生产者实现有责任确保实现中存在符合要求的消费者固件组件可能尝试使用的任何设施。
同样,固件组件的开发人员有责任确保其实现仅依赖于定义为 PI 架构一部分的设施。
当合规组件的集合被设计为仅使用 PI 体系结构规范系列中定义的所需设施时,可以确保最大的互操作性。
由于本文档是架构规范,因此已注意以允许生产者和消费者在实现中具有最大灵活性的方式来指定架构。
但是,对于必须实现本规范的哪些元素以确保设计用于与此处描述的体系结构接口一起工作的代码的操作有一致且可预测的环境存在某些要求。
为了描述这些要求,规范包括必需的设施,例如接口和数据结构,以及标记为可选的设施。
通常,要使实现符合本规范,实现必须包括在所有方面都与作为规范一部分呈现的所需设施描述的完整描述相匹配的功能元素。
规范中没有明确标记为“可选”的任何部分都被认为是必需的设施。
当规范的某些部分被标记为“可选”时,实现可以选择提供匹配元素或将它们排除在外。
如果一个元素是由一个设施的实现提供的,那么它必须在所有方面都与相应的完整描述相匹配。
实际上,这意味着对于规范中涵盖的任何设施,实现的任何实例只有在完全准确地遵循规范描述的情况下才能声称符合。
这并不排除提供超出规范中描述的附加功能的实现。
此外,它不排除实现省略在规范中标记为可选的设施
因此,设计用于在符合 PI 架构的实现中运行的固件的模块化组件仅在它们仅依赖于本规范和相关 PI 架构规范中描述的设施时才符合要求。
换句话说,任何没有任何超出 PI 架构规范范围的外部依赖性的模块化组件都是符合要求的。
如果模块化组件依赖于对接口或数据结构的引用进行正确和完整的操作,
而该接口或数据结构既不是其自身映像的一部分,也不是任何 PI 架构规范中描述的,那么它就是不符合标准的。
在某些所需设施不存在的情况下,可以对规范进行部分实现。
这样的实现是不符合标准的,并且本身符合标准的其他固件组件可能无法正确运行。
不符合要求的实现的正确操作明确超出了 PI 架构和本规范的范围。
1.5 本文档中使用的约定
1.5.1 数字格式
在本标准中,二进制数由任何仅由西方阿拉伯数字 0 和 1 后跟小写 b(例如 0101b)组成的数字序列表示。
可以在二进制数表示中的字符之间包含下划线或空格以提高可读性或描绘字段边界(例如,0 0101 1010b 或 0_0101_1010b)
在本标准中,十六进制数在任何仅由西方阿拉伯数字 0 到 9 和/或大写英文字母 A 到 F(例如,0xFA23)组成的数字序列之前用 0x 表示。
可以在十六进制数字表示的字符之间包含下划线或空格,以提高可读性或描绘字段边界(例如,0xBFD8C FA23 或 0xB_FD8C_FA23)
在本标准中,十进制数由任何仅由阿拉伯数字 0 到 9 组成的数字序列表示,后面没有紧跟小写 b 或小写 h(例如,25)。
本标准使用以下约定来表示十进制数:
- 小数分隔符(即,分隔数字的整数部分和小数部分)是句点;
- 千位分隔符(即,在数字的一部分中分隔三位数字组)是一个逗号;
- 千位分隔符用于整数部分,不用于数字的小数部分
1.5.2 Binary prefixes
2 Overview
PI 体系结构规范(以下称为“PI 体系结构”)的预 EFI 初始化 (PEI) 阶段在启动流程的早期被调用。
具体来说,在安全 (SEC) 阶段进行一些初步处理后,任何机器重启事件都会调用 PEI 阶段。
PEI 阶段最初将与处于新生状态(nascent state)的平台一起运行,仅利用处理器上的资源(例如作为调用堆栈的处理器缓存)来调度 Pre-EFI 初始化模块 (PEIM)。
这些 PEIM 负责以下内容:
- 初始化一些持久化内存补充
- 描述 Hand-Off Blocks (HOB) 中的内存
- 描述 HOB 中的固件卷位置(FV)
- 将控制传递到驱动程序执行环境 (DXE) 阶段
从设计角度来说,PEI 阶段旨在成为实现上述目的的最少量代码。
因此,任何更复杂的算法或处理都应推迟到 DXE 执行阶段。
PEI 阶段还负责危机恢复(crisis recovery)和从 S3 睡眠状态恢复。
对于危机恢复,PEI 阶段应该驻留在固件存储的一些小的、容错的块中。
因此,必须使 PEI 阶段的占用空间尽可能小。
此外,对于成功的 S3 恢复而言,恢复的速度至关重要,因此应尽量减少通过固件的代码路径。
这两个引导流程还说明需要将 PEI 阶段的处理和代码路径保持在最低限度。
PEI 阶段的实现比任何其他阶段都更依赖于处理器架构。
特别是,处理器在其初始或接近初始状态提供的资源越多,PEI Foundation 和 PEIM 之间的接口就越丰富。
因此,以下讨论的几个部分说明了对体系结构的要求,但在其他方面与体系结构相关。
2.2 Design Goals
PI 架构需要 PEI 阶段来配置系统以满足 PI 架构架构的驱动程序执行环境 (DXE) 阶段的最低先决条件。
通常,需要 PEI 阶段来初始化一个足够大的线性 RAM 阵列,以便成功执行 DXE 阶段元素。
PEI 阶段提供了一个框架,允许供应商为每个功能不同的系统硬件提供单独的初始化模块,
这些模块必须在 PI 架构中的 DXE 执行阶段之前进行初始化。
PEI 阶段提供了一个通用框架,通过该框架可以独立设计、开发和更新单独的初始化模块。
PEI 阶段的开发是为了满足 PI 架构中的以下目标:
- 维护“信任链”。 这包括防止对 PEI 阶段或其模块进行未经授权的更新,以及在 PEI 阶段对 PEI Foundation 及其模块进行认证。
- 提供核心 PEI 模块(PEI Foundation),该模块对于特定处理器架构或多或少保持不变,但将支持来自不同供应商的插件模块,特别是处理器、芯片组、RAM 初始化等。
- 允许独立开发早期初始化模块。
2.3 Pre-EFI Initialization (PEI) Phase
PI 架构兼容引导的预 EFI 初始化 (PEI) 阶段的设计本质上是 PI 架构的 DXE 阶段的微型版本,并解决了许多相同的问题。
PEI 阶段设计为分几个部分进行开发。PEI 阶段包括以下内容:
- 一些称为 PEI Foundation 的核心代码
- 称为 Pre-EFI 初始化模块 (PEIM) 的专用插件
与 DXE 不同,PEI 阶段不能假设有合理数量的 RAM,因此 DXE 中的丰富功能在 PEI 中不存在。
PEI 阶段将其支持限制为以下操作:
- 定位、验证和调度 PEIM
- 促进 PEIM 之间的通信
- 向后续阶段提供移交数据
下面显示了在 PEI 阶段完成的过程:
2.4 PEI Services
PEI Foundation 建立了一个名为 PEI Services Table 的系统表,
该表对系统中的所有预 EFI 初始化模块 (PEIM) 可见。
PEI 服务被定义为 PEI Foundation 在满足该服务的初始化要求时表现出来的功能、命令或其他能力。
由于 PEI 阶段在接近结束时没有永久内存可用,因此在 PEI 阶段创建的服务范围不会像在后期阶段创建的那样丰富。
由于 PEI Foundation 及其临时 RAM 的位置在构建时未知,
指向 PEI 服务表的指针被传递到每个 PEIM 的入口点以及每个 PEIM 到 PEIM 接口 (PPI) 的一部分。
PEI 基础服务类
- | - |
---|---|
PPI 服务 | 管理 PPI 以促进 PEIM 之间的模块间调用。 接口在临时 RAM 中维护的数据库上安装和跟踪。 |
引导模式服务 | 管理系统的引导模式(S3、S5、正常引导、诊断等)。 |
HOB 服务 | 创建称为切换块 (HOB) 的数据结构,用于将信息传递到 PI 架构的下一阶段。 |
固件卷服务 | 在固件卷中查找 PEIM 和其他固件文件。 |
PEI 内存服务 | 提供一组内存管理服务,供在发现永久内存之前和之后使用。 |
状态代码服务 | 提供常见的进度和错误代码报告服务(例如,端口 080h 或用于调试的简单文本输出的串行端口)。 |
重置服务 | 提供启动系统热重启或冷重启的常用方法。 |
2.5 PEI Foundation
PEI Foundation 是负责以下事项的实体:
- 成功调度 EFI 前初始化模块 (PEIM)
- 维持引导模式
- 初始化永久内存
- 调用驱动程序执行环境 (DXE) 加载程序
PEI Foundation 被写入为可在给定指令集架构的所有平台上移植。
因此,32 位英特尔 ® 架构 (IA-32) 的二进制文件应适用于所有奔腾 ® 处理器,从采用 MMX™ 技术的奔腾 II 处理器到最新的奔腾 4 处理器。
同样,用于 Itanium® 处理器系列的 PEI Foundation 二进制文件应适用于所有 Itanium 处理器。
无论处理器微架构如何,PEI Foundation 公开的服务集应该是相同的。
PEI Foundation 周围的统一表面区域允许 PEIM 用 C 编程语言编写并跨任何微体系结构编译。
2.6 PEI Dispatcher
PEI Dispatcher 本质上是一个在 PEI Foundation 中实现的状态机。
PEI Dispatcher 评估正在检查的固件卷中的 Pre-EFI 初始化模块 (PEIM) 中的依赖关系表达式。
依赖表达式是 PEIM 到 PEIM 接口 (PPI) 的逻辑组合。
这些表达式描述了在调用给定 PEIM 之前必须可用的 PPI。
为了评估 PEIM 的依赖表达式,PEI Dispatcher 参考 PEI Foundation 中的 PPI 数据库来确定已安装哪些 PPI。
如果已经安装了 PPI,依赖表达式的计算结果为 TRUE,它告诉 PEI Dispatcher 它可以运行 PEIM。
此时,PEI Foundation 将控制权传递给具有真正依赖表达式的 PEIM。
一旦 PEI Dispatcher 评估了所有公开固件卷中的所有 PEIM 并且不再有 PEIM 可以被调度(即,依赖表达式不会从 FALSE 评估为 TRUE),PEI Dispatcher 将退出。
正是在这一点上,PEI Dispatcher 不能调用任何额外的 PEIM。
然后 PEI Foundation 重新获得 PEI Dispatcher 的控制权,并调用 DXE IPL PPI 将控制权传递给 DXE 执行阶段。
2.7 Pre-EFI Initialization Modules (PEIMs)
Pre-EFI 初始化模块 (PEIM) 是专门的驱动程序,可将 PEI Foundation 个性化到平台。
它们类似于 DXE 驱动程序,通常对应于正在初始化的组件。
PEI Foundation 代码负责按顺序分发 PEIM 并提供基本服务。PEIM 旨在镜像正在初始化的组件。
在“内存不足”的环境中,PEIM 之间的通信并不容易。
尽管如此,如果没有彼此之间的某种交互,就无法对 PEIM 进行编码,即使可以,这样做也是低效的。
PEI 阶段为 PEIM 提供了从其他 PEIM 定位和调用接口的机制。
由于 PEI 阶段存在于可用硬件资源最少且从引导固件设备执行的环境中,
因此强烈建议 PEIM 执行最少必要的工作以将系统初始化为满足 DXE 阶段先决条件的状态.
预计在未来,通常的做法是由软件或硬件组件的供应商提供 PEIM(可能以源代码形式),以便客户可以快速调试集成问题。
2.8 PEIM-to-PEIM Interfaces (PPIs)
PEIM 使用称为 PEIM 到 PEIM 接口 (PPI) 的结构相互通信。
PPI 包含在 EFI_PEI_PPI_DESCRIPTOR 数据结构中,该数据结构由 GUID/指针对组成。
GUID“命名”接口,关联的指针为该 PPI 提供关联的数据结构和/或服务集。
PPI 的使用者必须使用 PEI 服务 LocatePpi() 来发现感兴趣的 PPI。
PPI 的生产者使用 PEI 服务 InstallPpi() 或 ReinstallPpi() 在其 PEIM 中发布可用的 PPI。
所有 PEIM 都以相同的方式注册和定位,即通过上面列出的 PEI 服务。
在 PPI 的这个命名空间中,有两类 PPI:
- Architectural PPI
- Additional PPI
Architectural PPI 是其 GUID 在 PEI CIS 中描述的 PPI,并且是 PEI Foundation 已知的 GUID。
这些 Architectural PPI 通常为具有特定平台实现的服务的 PEI Foundation 提供通用接口,
例如 PEI 服务 ReportStatusCode()
。
Additional PPI 是对互操作性很重要但不受 PEI Foundation 依赖的 PPI。
它们可以分为强制性或可选性。
具体来说,要拥有一大类可互操作的 PEIM,最好以某种标准方式安装最终引导模式,
以便 PEIM 可以在其依赖项表达式中使用此 PPI。
在 PEI CIS 中定义这些额外 PPI 的另一种方法是使用不同名称的类似服务的激增。
2.9 Firmware Volumes
Pre-EFI 初始化模块 (PEIM) 驻留在固件卷 (FV) 中。
PEI 阶段支持 PEIM 驻留在多个固件卷中的能力。
其他 PEIM 可以公开固件卷以供 PEI 基金会使用。
3 PEI Services Table
3.1 简介
PEI 基金会建立了一个名为 PEI Services Table 的系统表,该表对系统中的所有 Pre-EFI 初始化模块 (PEIM) 可见。
PEI 服务被定义为 PEI 基金会在满足该服务的初始化要求时表现出来的功能、命令或其他能力。
由于 PEI 阶段在接近结束时没有永久内存可用,因此在 PEI 阶段创建的服务范围不会像在后期阶段创建的那样丰富。
因为在构建时 PEI 基金会及其临时 RAM 的位置是未知的,所以指向 PEI 服务表的指针被传递到每个 PEIM 的入口点以及每个 PEIM 到 PEIM 接口 (PPI) 的一部分。
注意:在 PEI 基金会将 EFI_TABLE_HEADER 用于 PEI 服务表时,对 CRC32 字段进行了特殊处理。 此值对于 PEI 是可忽略的,应设置为零。
3.2 PEI Services Table
3.2.1 EFI_PEI_SERVICES
总结
PEI 服务表包括一个表中的函数指针列表。
该表位于临时或永久存储器中,具体取决于 PEI 的能力和执行阶段。
此表中的功能在第 20 页的“服务 - PEI”中定义。
Related 定义
//
// PEI Specification Revision information
//
#define PEI_SPECIFICATION_MAJOR_REVISION 1
#define PEI_SPECIFICATION_MINOR_REVISION 70
//
// UEFI PEI Services Table
//
#define PEI_SERVICES_SIGNATURE 0x5652455320494550
#define ((PEI_SPECIFICATION_MAJOR_REVISION<<17) |
(PEI_SPECIFICATION_MINOR_REVISION))
typedef EFI_PEI_SERVICES {
EFI_TABLE_HEADER Hdr;
//
// PPI Functions
//
EFI_PEI_INSTALL_PPI InstallPpi;
EFI_PEI_REINSTALL_PPI ReInstallPpi;
EFI_PEI_LOCATE_PPI LocatePpi;
EFI_PEI_NOTIFY_PPI NotifyPpi;
//
// Boot Mode Functions
//
EFI_PEI_GET_BOOT_MODE GetBootMode;
EFI_PEI_SET_BOOT_MODE SetBootMode;
//
// HOB Functions
//
EFI_PEI_GET_HOB_LIST GetHobList;
EFI_PEI_CREATE_HOB CreateHob;
//
// Firmware Volume Functions
//
EFI_PEI_FFS_FIND_NEXT_VOLUME2 FfsFindNextVolume;
EFI_PEI_FFS_FIND_NEXT_FILE2 FfsFindNextFile;
EFI_PEI_FFS_FIND_SECTION_DATA2 FfsFindSectionData;
//
// PEI Memory Functions
//
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;
//
// Status Code
EFI_PEI_REPORT_STATUS_CODE ReportStatusCode;
//
// Reset
//
EFI_PEI_RESET_SYSTEM ResetSystem;
//
// (the following interfaces are installed by publishing PEIM)
//
// I/O Abstractions
//
EFI_PEI_CPU_IO_PPI *CpuIo;
EFI_PEI_PCI_CFG2_PPI *PciCfg;
//
// Additional File System-Related Services
//
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;
参数:
- Hdr:PEI 服务表的表头。 此标头包含 PEI_SERVICES_SIGNATURE 和 PEI_SERVICES_REVISION 值以及 EFI_PEI_SERVICES 结构的大小和 32 位 CRC,以验证 PEI 基金会服务表的内容是否有效。 |
- InstallPpi:通过 GUID 在 PEI PEIM 到 PEIM 接口 (PPI) 数据库中安装接口。 请参阅本文档中的 InstallPpi() 函数说明。
- ReInstallPpi:通过 GUID 在 PEI PPI 数据库中重新安装接口。 请参阅本文档中的 ReinstallPpi() 函数说明。
- LocatePpi 通过 GUID 在 PEI PPI 数据库中定位接口。 请参阅本文档中的 LocatePpi() 函数说明。
- NotifyPpi 安装通知服务,在安装或重新安装给定接口时回调。 请参阅本文档中的 NotifyPpi() 函数说明。
- GetBootMode 返回引导模式的当前值。 请参阅本文档中的 GetBootMode() 函数说明。
- SetBootMode 设置引导模式的值。 请参阅本文档中的 SetBootMode() 函数说明。
- GetHobList 返回指向内存中切换块 (HOB) 列表的指针。请参阅本文档中的 GetHobList() 函数说明。
- CreateHob 抽象 HOB 头的创建。请参阅本文档中的 CreateHob() 函数说明。
- FfsFindNextVolume 发现系统中固件卷的实例。请参阅本文档中的 FfsFindNextVolume() 函数说明。
- FfsFindNextFile 发现系统中固件文件的实例。请参阅本文档中的 FfsFindNextFile() 函数说明。
- FfsFindSectionData 搜索固件文件中的部分。请参阅本文档中的 FfsFindSectionData() 函数说明。
- InstallPeiMemory 向 PEI 基金会注册找到的内存配置。请参阅本文档中的 InstallPeiMemory() 函数说明。
- AllocatePages 分配由 PEI 基金会管理的内存范围。请参阅本文档中的 AllocatePages() 函数说明。
- AllocatePool 释放由 PEI 基金会管理的内存范围。请参阅本文档中的 AllocatePool() 函数说明。
- CopyMem 将一个缓冲区的内容复制到另一个缓冲区。请参阅本文档中的 CopyMem() 函数说明。
- SetMem 用指定的值填充缓冲区。请参阅本文档中的 SetMem() 函数说明。
- ReportStatusCode 提供一个接口,PEIM 可以调用该接口来报告状态代码。 请参阅本文档中的 ReportStatusCode() 函数说明。这是由提供商 PEIM 通过将接口复制到 PEI 服务表中来安装的。
- ResetSystem 重置整个平台。 请参阅本文档中的 ResetSystem() 函数说明。 这是由提供商 PEIM 通过将接口复制到 PEI 服务表中来安装的。
- ResetSystem2 重置整个平台。 请参阅本文档中的 ResetSystem2() 函数说明。 这是由提供商 PEIM 通过将接口复制到 PEI 服务表中来安装的。
- CpuIo 提供一个接口,PEIM 可以调用该接口来执行 I/O 事务。 此接口由提供商 PEIM 通过将接口复制到 PEI 服务表中来安装。
- PciCfg 提供一个接口,PEIM 可以调用该接口来执行 PCI 配置事务。 此接口由提供商 PEIM 通过将接口复制到 EFI_PEI_SERVICES 表中来安装。
- FfsFindFileByName 按名称发现卷中的固件文件。 请参阅本文档中的 FfsFindFileByName()。
- FfsGetFileInfo 返回有关特定文件的信息。 请参阅本文档中的 FfsGetFileInfo()。
- FfsGetFileInfo2 返回有关特定文件的信息。 请参阅本文档中的 FfsGetFileInfo2()。
- FfsGetVolumeInfo 返回有关特定卷的信息。 请参阅本文档中的 FfsGetVolumeInfo()。
- RegisterForShadow 注册要在内存可用时重新加载的驱动程序。 请参阅本文档中的 RegisterForShadow()。
- FindSectionData3 在固件文件中搜索一个部分。 请参阅本文档中的 FfsFindSectionData3() 函数说明。
- FreePages 释放先前使用 AllocatePages() 分配的内存。
描述:
EFI_PEI_SERVICES 是一组函数,其实现由 PEI 基金会提供。 这些服务分为不同的类别,包括:
- 管理引导模式
- 分配早期和永久内存
- 支持固件文件系统 (FFS)
- 抽象 PPI 数据库抽象
- 创建切换块 (HOB)
当 PEI 基金会调用 PEIM 时,将指向 EFI_PEI_SERVICES 表的指针传递到每个 PEIM .
因此,每个 PEIM 都可以访问这些服务。
与 UEFI 引导服务不同,PEI 服务没有调用限制,例如 UEFI 2.0 任务优先级 (TPL) 限制。
具体来说,可以从 PEIM 或通知服务调用服务。
一些服务也是平台提供服务的代理,例如重置服务、状态代码服务和 I/O 抽象。
这种分区旨在提供一个与所有 PEIM 的接口一致,而无需使用特定于平台的知识来妨碍 PEI 基金会的实施。
任何超出此表中集合的可调用服务都应使用 PPI 调用。
后面的 PEIM 安装的服务将返回 EFI_NOT_AVAILABLE_YET,直到 PEIM 将接口的实例复制到 EFI_PEI_SERVICES 表中。
4 Services - PEI
4.1 简介
PEI 服务被定义为 PEI 基金会在阶段完成后保持可用的功能、命令或其他能力。
由于 PEI 阶段在接近结束时没有永久内存可用,因此在 PEI 阶段创建的 PEI 基金会服务的范围不会像后期阶段创建的那样丰富。
- PPI 服务:管理 PEIM 到 PEIM 接口 (PPI) 以促进 PEIM 之间的模块间调用。 接口在临时 RAM 中维护的数据库上安装和跟踪。
- 引导模式服务:管理系统的引导模式(S3、S5、正常引导、诊断等)。
- HOB 服务:创建称为切换块 (HOB) 的数据结构,用于将信息传递到 PI 架构的下一阶段。
- 固件卷服务:遍历固件卷中的固件文件系统 (FFS) 以查找闪存设备中的 PEIM 和其他固件文件。
- PEI 内存服务:提供一组内存管理服务,供在发现永久内存之前和之后使用。
- 状态代码服务:提供常见的进度和错误代码报告服务(例如,端口 080h 或用于调试的简单文本输出的串行端口)。
- 重置服务:提供启动系统热重启或冷重启的常用方法。
PEI 服务的调用约定类似于 PPI。 有关 PPI 的更多详细信息,请参阅“PEIM 到 PEIM 通信”。
将服务调用绑定到服务的方法涉及一个调度表,EFI_PEI_SERVICES。指向该表的指针被传递到 PEIM 入口点。
4.2 PPI Services
以下服务提供了用于抽象 PPI 数据库的接口集:
- InstallPpi()
- ReinstallPpi()
- LocatePpi()
- NotifyPpi()
InstallPpi()
摘要:此服务是 PEI 基金会提供的第一个服务。
此函数通过 GUID 在 PEI PPI 数据库中安装一个接口。
该服务的目的是发布一个接口,其他方可以使用它来调用其他 PEIM。
原型:
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 类型在第 110 页的“PEIM 描述符”中定义。
描述:
此服务使给定的 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_NOTIFY_DISPATCH 和 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK。
返回的状态代码
- EFI_SUCCESS 接口安装成功。
- EFI_INVALID_PARAMETER PpiList 指针为 NULL。
- EFI_INVALID_PARAMETER 列表中的任何 PEI PPI 描述符都没有在 Flags 字段中设置 EFI_PEI_PPI_DESCRIPTOR_PPI 位。
- EFI_OUT_OF_RESOURCES PPI 数据库中没有额外的空间。
4.3 Boot Mode Services
4.4 HOB Services
4.5 Firmware Volume Services
4.6 PEI Memory Services
4.7 Status Code Service
4.8 Reset Services
4.9 I/O and PCI Services
PEI 基金会发布 CPU I/O 和 PCI 配置服务。
5 PEI Foundation
5.1 简介
PEI 基金会以 PEI Dispatcher 为中心。
调度员的工作是有序地将控制权交给 PEIM。
PEI 基金会还协助 PEIM 到 PEIM 的交流。
模块到模块通信的核心资源涉及 PPI。
可以使用可安装或通知界面对 PPI 的引用进行编组。
PEI Foundation 构建为一个自治二进制映像,文件类型为 EFI_FV_FILETYPE_PEI_CORE,由以下部分组成:
- 身份验证部分
- 可能是 PE32 的代码映像
有关部分和文件的信息,请参阅 Platform Initialization Specification,第 3 卷 。
如果构成 PEI 基金会的代码不是 PE32 映像,则它是原始二进制文件,其最低地址是 PEI 基金会的入口点。
PEI 基金会由安全 (SEC) 阶段发现和验证。
5.1.1 先决条件
PEI 阶段由符合 PI 架构的引导过程的安全 (SEC) 阶段控制。
PEI 阶段在开始执行之前必须满足以下最低先决条件:
- 处理器执行模式
- 访问包含 PEI 基金会的固件卷
期望 SEC 基础设施代码和 PEI 基金会不会链接在一起作为单个 ROMable 可执行文件镜像。
从 SEC 到 PEI 的入口点在架构上不是固定的,而是取决于 FV0 中的 PEI 基金会位置,或引导固件卷。
5.1.2 Processor Execution Mode
5.1.2.1 IA-32 英特尔 ® 架构中的处理器执行模式
在 IA-32 英特尔架构中,PI 架构的安全 (SEC) 阶段负责将处理器置于原生线性地址模式,
通过该模式,处理器的完整地址范围 处理器可访问代码、数据和堆栈。
例如,“flat 32”是 IA-32 处理器生成模式,PEI 阶段将在其中执行。
处理器必须处于其最高特权的“ring 0”模式或等效模式,并且能够访问所有内存和 I/O 空间。
这个先决条件严格依赖于处理器代架构。
5.1.2.2 Itanium® 处理器系列中的处理器执行模式
PEI 基金会将在安全 (SEC) 阶段完成后开始执行。 SEC 阶段包含了 Itanium® 中的系统抽象层入口点 (SALE_ENTRY)。
此外,SEC 阶段进行适当的处理器抽象层 (PAL) 调用或平台服务以启用临时内存存储。
SEC 将其切换状态以物理模式传递给 PEI 基金会,其中包含一些已配置的内存堆栈,例如将处理器缓存配置为内存。
5.1.2.3 访问引导固件卷 (BFV) 和其他引导关键 FV
安全 (SEC) 阶段控制的程序被称为 PEI 基金会。
PEIM 可能驻留在 BFV 或其他 FV 中。
BFV 中必须有一个“特殊”PEIM,以提供有关其他 FV 位置的信息。
在 BFV 和其他关键 FV(例如 PEI 基金会所在的位置)中启动所需的每个文件都必须能够被 PEI 阶段发现和验证。
这允许 PEI 阶段确定这些 FV 是否已损坏。
PEI 基金会和 PEIM 预计将存储在一些合理的防篡改(尽管不一定在严格的基于安全的术语定义中)非易失性存储 (NVS) 中。
预计存储将非常类似于具有唯一 ID 代替名称的平面文件系统。
使用特定 NVS 的规则可能会影响某些存储注意事项,但需要一种用于通过 ID 定位 PEIM 的标准纯数据机制。
PI 架构架构描述了 PI 固件卷格式和 PI 固件文件系统格式,以及命名文件的 GUID 约定。
这些标准是 PEI 的架构标准,因为 PEI 阶段需要直接支持该文件系统。
BFV 只能构造为 EFI_FIRMWARE_FILE_SYSTEM2_GUID 类型。
PEI 基金会和恢复所需的一些 PEIM 必须要么锁定在不可更新的 FV 中,要么必须能够通过“容错”机制进行更新。
容错机制被设计成这样,如果系统在任何时候停止,旧的(更新前的)PEIM 或新更新的 PEIM 都是完全有效的,
并且 PEI 阶段可以确定哪个是有效的。
5.1.2.4 访问 IA-32 Intel 架构中的引导固件卷
在 IA-32 Intel 架构中,安全 (SEC) 文件位于引导固件卷 (BFV) 的顶部。
此 SEC 文件将具有 IA-32 的 16 字节入口点,并在地址 0xFFFFFFF0 处重新启动。
5.1.2.5 访问安腾处理器家族中的引导固件卷
在安腾处理器家族中,微码启动处理器抽象层 A(PAL-A)代码,这是第一层 PAL 代码,由处理器供应商提供,驻留在引导固件卷 (BFV) 中。
此代码最低限度地初始化处理器,然后查找并验证称为 PAL-B 的第二层 PAL 代码。
PAL-A 和 PAL-B 的位置可以通过查阅以下任一方法找到:
- ROM 中的架构指针(4 GiB 区域附近)
- ROM 中的固件接口表 (FIT) 指针 PAL 层使用称为系统抽象层入口点 (SALE_ENTRY) 的单个入口点与 OEM 启动固件进行通信。
PEI Foundation 将位于基于 Itanium 的系统的引导固件设备上的 SALE_ENTRY 点。
Itanium 处理器系列 PEIM 与其他 PEIM 一样,可以驻留在 BFV 或其他固件卷中。
“特殊”PEIM 必须驻留在 BFV 中,以提供有关其他固件卷位置的信息;这将在 EFI_PEI_FIND_FV_PPI 的上下文中描述
还必须注意的是,在基于 Itanium 的系统中,每个节点中的所有处理器都启动并执行 PAL 代码,然后进入 PEI 基金会。
特定节点的 BFV 必须可由该节点中运行的所有处理器访问。
这也意味着 Itanium® 体系结构引导路径中的某些 PEIM 将支持多处理器 (MP)。
在基于 Itanium 的系统中,BFV 中固件模块的组织也必须如此,至少 PAL-A 包含在容错区域中。
此特定于处理器的 PAL-A 代码验证 PAL-B 代码,该代码通常包含在固件系统的非容错区域中。
PAL-A 和 PAL-B 二进制组件在上电时始终对节点中的所有处理器可见; 系统结构不需要初始化。
5.2 PEI Foundation Entry Point
5.2.1 PEI 基金会入口点
安全 (SEC) 阶段使用以下信息调用 PEI 基金会的入口点:
- 一组 PPI
- 引导固件卷 (BFV) 的大小和位置
- 其他 boot-critical 固件卷的大小和位置 ,通过将固件卷添加到具有 EFI_PEI_FIRMWARE_VOLUME_PPI 类型的 PpiList。
- 临时 RAM 的大小和位置
- 可供 PEI 基金会使用的临时 RAM 的大小和位置
- 堆栈的大小和位置
入口点在下面的“代码定义”中描述。
Prototype
typedef
VOID
EFIAPI
(*EFI_PEI_CORE_ENTRY_POINT)(
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
);
参数:
- SecCoreData 指向包含有关 PEI 内核操作环境信息的数据结构,
例如临时 RAM 的大小和位置、堆栈位置和 BFV 位置。 EFI_SEC_PEI_HAND_OFF 类型在下面的“相关定义”中定义。 - PpiList 指向一个或多个 PPI 描述符的列表。
这些 PPI 描述符可以是 EFI_PEI_PPI_DESCRIPTOR 类型的描述符的组合,
用于最初由 PEI 核心安装的 PPI 和类型 EFI_PEI_NOTIFY_DESCRIPTOR 的描述符用于通知,PEI 核心将在安装 PPI 服务时通知。
一个空的 PPI 列表由一个带有结束标签 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST 的描述符组成。
EFI_PEI_PPI_DESCRIPTOR 和 EFI_PEI_NOTIFY_DESCRIPTOR 类型在“PEIM 描述符”中定义。
作为初始化阶段的一部分,PEI 基金会将这些 SEC 托管的 PPI 添加到其 PPI 数据库中,
这样 PEI 基金会和任何模块都可以利用相关的服务调用和/或代码。
这应该包含将通过 EFI_PEI_FIRMWARE_VOLUME_PPI 从 SEC 传递到 PEI Foundation 的所有启动关键 FV。
描述:
此函数是 PEI 基金会的入口点,它允许 SEC 阶段传递有关堆栈、临时 RAM 和引导固件卷的信息。
此外,它还允许 SEC 阶段以一个或多个 PPI 的形式转发服务和数据以供 PEI 阶段使用。
这些 PPI 将被安装和/或编码在这些早期的 PPI 中。
最后,平台演化的后期阶段可能需要 SEC 阶段可能拥有的许多功能和数据。
为了支持这一点,SEC 阶段可以构造一个 EFI_PEI_PPI_DESCRIPTOR 并将其地址作为最终参数传递给 PEI 基金会。
在这些 PPI 中,SEC 可以传递一个可选的 PPI,EFI_SEC_PLATFORM_INFORMATION_PPI,
作为传递给 PEI 基金会入口点的 PPI 列表的一部分。
该 PPI 抽象了平台特定的信息,PEI 基金会需要这些信息来发现从哪里开始分发 PEIM。
传递给 PEI 基金会的其他可能值包括任何安全或验证服务,例如可信计算组 (TCG) 访问服务,
因为 SEC 将在符合 TCG 的情况下构成核心信任根模块 (CRTM) 系统。
此外,SEC 可以将 EFI_SEC_HOB_DATA_PPI 作为 PPI 列表的一部分传递。
在任何 PEIM 被分派之前,该 PPI 可以检索要添加到 HOB 列表的零个或多个 HOB。
5.3 PEI Calling Convention Processor Binding
除非另有说明,用于 PEI 函数的调用约定与 UEFI 规范中指定的调用约定相同。 但是,对于某些处理器,建议为新的 PPI 定义使用替代调用约定。
5.4 PEI 服务表检索
本节描述用于检索指向 PEI 服务表 (EFI_PEI_SERVICES**) 的指针的处理器特定机制,如 PEIM 中常用的。
存储和检索方式是特定于处理器的。
5.4.4 ARM Processor Family – Register Mechanism
对于 ARM 处理器系列处理器,(EFI_PEI_SERVICES) 存储在 ARMv7-A 架构参考手册中定义的 TPIDRURW 读/写软件线程 ID 寄存器中。
可以使用以下代码片段检索 EFI_PEI_SERVICES,可以将其放置在库例程中以实现架构之间的可移植性:
CpuReadTPIDRURW:
MRC p15, 0, r0, c13, c0, 2
bx lr
EFI_PEI_SERVICES **
GetPeiServicesTablePointer (
VOID
)
{
return (EFI_PEI_SERVICES **)(UINTN)CpuReadTPIDRURW ();
}
5.4.4.1 ARM 向量表
对于 ARM 处理器,向量表条目是指令,因此限于分支指令的 24 位相对偏移量。
PI 规范要求定义的 8 个向量包含以下指令 LDR pc, [pc, #0x20]
。
这意味着处理程序的 32 位地址位于向量地址的 32 字节偏移处。
当 PI 代码挂接到向量表中时,它必须确保与向量相距 32 字节的 32 位绝对地址偏移量是更新的内容。
平台中初始化向量表的第一个代码必须用 8 个 LDR pc, [pc, #0x20]
指令填充它。
5.5 PEI Dispatcher Introduction
PEI 调度员的工作是有序地将控制权交给 PEIM。PEI Dispatcher 由单个阶段组成。
在此阶段,PEI 基金会将检查固件卷中包含 EFI_FV_FILETYPE_PEIM 或 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 类型文件的每个文件(有关文件类型定义,请参阅平台初始化规范,第 3 卷)。
它将检查每个固件文件中的依赖表达式 (depex) 和可选的先验文件,以确定何时可以分发 PEIM。
depex 的二进制编码将与与 PEIM 关联的 depex 的二进制编码相同。
5.6 Ordering
5.6.1 要求
除了 a priori 文件规定的顺序外,期望 PEIM 以任何顺序执行都是不合理的。
芯片组初始化 PEIM 通常需要处理器初始化,而存储器初始化 PEIM 通常需要芯片组初始化。
另一方面,满足这些要求的 PEIM 可能由不同的组织编写并且可能驻留在不同的 FV 中。
因此,要求是在没有内存的情况下创建一种机制来允许定义不同 PEIM 之间的排序,
以便在 PEIM 执行时,它执行的所有要求都已得到满足。
尽管更新和构建过程有助于解决排序问题,但不能完全依赖它们。
考虑一个带有可拆卸处理器卡的系统,其中包含插入主系统板的处理器和固件卷。
如果处理器卡被升级,即使没有执行更新程序,用户也应该期望系统工作是完全合理的。
5.6.2 需求表示和符号
需求由 GUID 表示,每个 GUID 代表一个特定的需求。
这些要求由两组数据结构表示:
- 给定 PEIM 的依赖表达式 (depex)
- PEI 基金会在 PPI 数据库中维护的已安装 PPI 集
该机制提供了 PEIM 之间的“弱排序”。
如果 PEIM A 和 B 消耗 X(写成 AcX 和 BcX),一旦执行了产生 X(CpX)的 PEIM(C),A 和 B 就可以被执行。
A 和 B 的执行顺序没有定义。
5.6.3 PEI a priori File Overview
PEI 先验文件是一个特殊文件,可以选择存在于固件卷中,其主要目的是在平台的固件设计中提供更大程度的灵活性。
具体来说,先验文件通过规定一系列需要按规定顺序调度的模块来补充 PEI 的依赖表达机制。
平台中存在的每个固件卷最多可能有一个 PEI 先验文件。
先验文件具有已知的 GUID 文件名 PEI_APRIORI_FILE_NAME_GUID,使 PEI 基金会调度行为能够找到先验文件(如果存在)。
文件的内容应包含格式为 PEI_APRIORI_FILE_CONTENTS 的数据,可能有零个条目。
每次 PEI Dispatcher 发现固件卷时,它首先查找先验文件。
在先验文件中列举的 PEIM 必须与先验文件本身存在于同一固件卷中;不允许跨卷映射。
PEI 基金会将按照此文件中的顺序调用 PEI_APRIORI_FILE_CONTENTS 中列出的 PEIM。
在没有先验文件的情况下,PEIM 仅仅因为它们的依赖表达式而被执行是弱排序的。
这意味着执行顺序在引导之间或平台之间不是完全确定的。
在某些情况下,需要确定性的执行顺序。
PEI 先验文件使用以下两种实现方法提供了 PEIM 的确定性执行顺序。
所有 PEI 基金会实现都必须支持先验模型,但它不排除额外的先验调度方法,
只要后一种模型使用不同的机制和/或文件名 GUID 来替代先验模块列表。
先验文件格式如下:
PEI_APRIORI_FILE_NAME_GUID
Summary
GUID PEI_APRIORI_FILE_NAME_GUID 定义是存储在固件卷中的 PEI 先验文件的文件名。
GUID
#define PEI_APRIORI_FILE_NAME_GUID \
{0x1b45cc0a,0x156a,0x428a,0xaf62,0x49,0x86,\
0x4d,0xa0,0xe6,0xe6}
typedef struct {
EFI_GUID FileNamesWithinVolume[NumberOfModulesInVolume];
// Optional list of file-names
} PEI_APRIORI_FILE_CONTENTS;
参数:
- FileNamesWithinVolume[] 与同一固件卷中 PEIM 模块的文件名匹配的零个或多个 EFI_GUID 类型条目的数组。
NumberOfModulesInVolume 的最大条目数由 FV 中的模块数决定
5.6.3.1 Dispatch Behavior
先验文件可以包含 EFI_GUID 列表,它们是同一固件卷中 PEIM 文件的名称。
此处,PEI 基金会调度逻辑从先验文件中读取名称列表,并按照先验文件中列举的顺序调用适当命名的模块。
这个值可以通过 PEI_APRIORI_FILE_CONTENTS 的大小来计算。这应该是 GUID 大小的整数。
如果 PEI_APRIORI_FILE_CONTENTS 中存在处于删除状态或不存在的文件名,
则该特定文件名将被 PEI 基金会调度逻辑忽略并调用后续条目。
在先验文件中派发 PEIM 期间,新发布的固件卷中的任何 PEIM 将被忽略,直到先验文件派发完成。
不过,这些接口将在后续模块调度期间进行评估。
除了忽略在先验调度期间发布的任何其他卷之外,与列在 PEI_APRIORI_FILE_CONTENTS 中的 PEIM 关联的任何依赖表达式都将被忽略。
在先验 PEIM 列表的调度期间,PEI 调度程序应调用 EFI_PEI_SECURITY2_PPI AuthenticationState 服务(如果存在)以限定每个模块的调度。
这与普通的基于依赖的调度行为相同。
对于启动固件卷中的先验文件,例如,EFI_PEI_SECURITY2_PPI 可以由 SEC 通过可选的 EFI_PEI_PPI_DESCRIPTOR 列表传递到 PEI 基金会。
后一种情况允许对先验文件中的 PEIM 进行身份验证。
在执行完先验文件中指定的所有 PEIM 后,PEI Dispatcher 在固件卷中搜索任何其他 PEIM 并根据它们的依赖表达式执行它们。
5.6.4 固件卷映像文件
对于 PEI,在处理固件卷时,如果发现类型为 EFI_FV_FIRMWARE_VOLUME_IMAGE 的文件,
PEI Dispatcher 将检查该固件卷映像文件是否已经被处理。如果是,则忽略该文件。
否则,PEI 调度程序将在文件中搜索类型为 EFI_SECTION_PEI_DEPEX 的部分,
如果找到,则根据 PPI 数据库中当前安装的条目评估表达式。
如果文件有一个评估为 TRUE 的依赖表达式(或没有 EFI_SECTION_PEI_DEPEX 部分),
那么 PEI Dispatcher 将在文件中搜索类型为 EFI_SECTION_FIRMWARE_VOLUME_IMAGE 的部分,
将其内容复制到内存中,并安装 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI 和 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI 的固件卷 映像,
并将 EFI_HOB_FIRMWARE_VOLUME 和 EFI_HOB_FIRMWARE_VOLUME2 类型的 HOB 添加到固件卷映像的 HOB 列表中。
5.6.5 PEIM 依赖表达式
PEIM 的排序是通过评估与每个 PEIM 关联的依赖表达式来确定的。
该表达式描述了 PEIM 运行所需的要求,这对 PEIM 施加了弱排序。
在这种弱排序中,PEIM 可以按任何顺序初始化。
5.6.6 依赖的类型
依赖表达式的基本单元是依赖。 以下部分显示了每个依赖项的代表性语法(在本文档中用于描述目的)。
语法不区分大小写,并且使用助记符代替非人类可读的数据,例如 GUID。空白是可选的。
操作数是 PPI 的 GUID。 当注册具有 GUID 的 PPI 时,操作数变为“TRUE”。
5.7 Dependency Expressions
5.8 Dispatch Algorithm
5.8.1 概述
5.8.1.1 排序算法
调度算法反复扫描 PEIM 以找到那些尚未调度的 PEIM。
对于找到的每个 PEIM,它会扫描已发布的 PPI 的 PPI 数据库,
在尚未分发的 PEIM 的 depex 中搜索元素。
如果 depex 中的所有元素都在 PEI 基金会的 PPI 数据库中,则调度 PEIM。
当所有 PEIM 都被扫描并且没有被调度时,该阶段终止。
5.8.1.2 多固件卷支持
为了暴露新的固件卷,PEIM 应该安装一个 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI 实例,
其中包含固件卷格式 GUID、起始地址和固件卷窗口的大小。
公开固件卷格式而不是 PI 架构固件卷格式的固件卷的 PEIM 应在其依赖项表达式中包含固件卷格式 GUID。
如果固件卷在 PEI 内存之外,则暴露内存映射固件卷的 PEIM 应为固件卷占用的内存创建内存资源描述符 HOB。
对于每个新公开的固件卷,PEI 基金会将采取以下步骤:
- 创建新的固件卷句柄。 固件卷句柄可以由 PEI 基金会或可选的 EFI_PEI_FIRMWARE_VOLUME_PPI 创建。
- 创建一个新的固件卷 HOB。
- 如果 PEI 基金会不直接支持固件卷的格式(由其 GUID 标识),并且任何已安装的 EFI_PEI_FIRMWARE_VOLUME_PPI 都不支持,则跳过固件卷。
- 否则,固件卷中的所有 PEIM 都被调度调度。
- 查找先验文件(如果存在),并分发其中列出的任何 PEIM。
5.8.2 要求
5.8.2.1 调度算法要求
调度算法必须满足以下要求:
- 保持调度弱排序。
- 防止无限循环。
- 控制处理器资源。
- 保持正确的分发顺序。
- 利用可用内存。
- 调用每个 PEIM 的入口点。
- 知道 PEI Dispatcher 任务何时完成。
5.8.2.2 保留弱排序
算法必须保留 depex 隐含的弱排序。
5.8.2.6 使用可用内存
PEI 基金会使用临时内存存储开始操作,该存储包含来自安全 (SEC) 阶段的初始调用堆栈。
SEC 阶段必须传递堆栈的大小和位置以及临时内存存储的大小和位置。
PEI 堆栈可用于后续的 PEIM 调用,而 PEI 堆将用于 PEIM 内存分配和切换块 (HOB) 创建。
在 PEIM 使用 PEI 服务 InstallPeiMemory() 注册永久内存范围之前,不能有内存写入超出此初始临时内存的地址空间。
当安装永久内存时,PEI 基金会会将位于临时内存中的调用堆栈复制到一段永久内存中。
如有必要,可以扩展调用堆栈的大小,以支持后续过渡到 DXE。
除了调用堆栈之外,PEI 基金会还将以下内容从临时内存复制到永久内存:
- PEI 基金会私有数据
- PEI 基金会堆
- HOB 列表
- 已安装的固件卷
将描述 PEI 基金会以这种方式消耗的任何永久内存在 PEI 基金会将创建的 HOB 中。
PEI 基金会会将任何已安装的固件卷从临时内存位置复制到永久内存位置,并按照固件卷标头中指定的对齐方式进行。
这些固件卷中 PEIM 中任何未压缩的 PE32 或 TE 部分都将被修复。
这确保这些 PEIM 中的任何静态 EFI_PEI_PPI_DESCRIPTOR 或 PPI 接口指针指向永久内存地址。
此外,如果在临时内存堆中创建了任何 EFI_PEI_PPI_DESCRIPTOR 或在 PEIM 中静态声明,
则它们各自的位置已被转换为偏移量,该偏移量等于临时内存中的原始位置与永久内存中的目标位置之间的差值。
除了这个堆副本,PEI 基金会还会遍历 PEI PPI 数据库。
任何对临时内存中 EFI_PEI_PPI_DESCRIPTORs 的引用将由 PEI 基金会修复,
以反映 EFI_PEI_PPI_DESCRIPTORs 目的地在永久内存中的位置。
PEI 基金会将在调度所有候选 PEIM 后调用 DXE IPL PPI。
DXE IPL PPI 可能必须从永久内存中分配额外的区域,以便能够从其固件存储中加载和重新定位 DXE Foundation。
DXE IPL PPI 将在适当的 HOB 中描述这些内存分配,以便当控制权传递给 DXE 时,DXE 基金会将知道内存使用的准确记录。
5.8.2.7 调用 PEIM 的入口点
PEIM 的入口点使用 UEFI 2.0 规范中指定的调用约定,其中详细说明了如何将参数传递给函数。
在评估 PEIM 的依赖表达式以查看它是否可以被调用后,PEI 基金会会将控制权传递给 PEIM 的入口点。
该入口点是在 PEIM 的图像标头中描述的值。
PEI 基金会在调用 PEIM 时将传递一个指向 PEI 服务表和固件文件句柄的间接指针。
在 PEIM 的入口点,PEIM 有机会执行以下操作:
- 定位其他 PPI
- 在此 PEIM 的主体内安装引用服务的 PPI
- 注册通知
- 从 PEIM 的入口点返回后,它返回 到 PEI 基金会。
- 有关 PE 的信息,请参阅 Microsoft Portable Executable and Common Object File Format Specification
5.8.4 当内存存在时分派
PEI 执行阶段的目的是发现和初始化主内存。
在几种情况下,PEIM 的阴影和将该图像重新定位到内存中是有意义的。
这可以包括但不限于压缩 PEIM,例如 DXE IPL PPI、危机恢复所需的那些模块以及从临时内存执行代码的平台。
PEI 架构不应规定要使用什么压缩机制,但某些 PEIM 会发布一个解压缩服务,PEI 基金会将在该服务可用时发现并使用该服务。
此外,加载图像还需要完整的图像重定位服务和刷新缓存的能力。
前者将允许重定位到 RAM 中的 PEIM 根据新的加载地址调整其重定位。
后一种服务将由 PEI 基金会调用,以便可以运行重新定位的代码,
尤其是在没有一致数据和代码缓存的基于 Itanium 的平台上。
压缩部分应隐含依赖于已安装的永久内存。
但是,为了加快启动时间,可以对该依赖项进行显式注释