5. PEI Foundation
5.1. Introduction
The PEI Foundation centers around the PEI Dispatcher. The dispatcher’s job is to hand control to the PEIMs in an orderly manner. The PEI Foundation also assists in PEIM-to-PEIM communication. The central resource for the module-to-module communication involves the PPI. The marshalling of references to PPIs can occur using the installable or notification interface.
The PEI Foundation is constructed as an autonomous binary image
that is of file type EFI_FV_FILETYPE_PEI_CORE
and is composed of
the following:
An authentication section
A code image that is possibly PE32+
See the Platform Initialization Specification, Volume 3, for information on section and file types. If the code that comprises the PEI Foundation is not a PE32+ image, then it is a raw binary whose lowest address is the entry point to the PEI Foundation. The PEI Foundation is discovered and authenticated by the Security (SEC) phase.
5.1.1. Prerequisites
The PEI phase is handed control from the Security (SEC) phase of the PI Architecture-compliant boot process. The PEI phase must satisfy the following minimum prerequisites before it can begin execution:
Processor execution mode
Access to the firmware volume that contains the PEI Foundation
It is expected that the SEC infrastructure code and PEI Foundation are not linked together as a single ROMable executable image. The entry point from SEC into PEI is not architecturally fixed but is instead dependent on the PEI Foundation location within FV0, or the Boot Firmware Volume.
5.1.2. Processor Execution Mode
5.1.2.1. Processor Execution Mode in IA-32 Intel ® Architecture
In IA-32 Intel architecture, the Security (SEC) phase of the PI Architecture is responsible for placing the processor in a native linear address mode by which the full address range of the processor is accessible for code, data, and stack. For example, “flat 32” is the IA-32 processor generation mode in which the PEI phase will execute. The processor must be in its most privileged “ring 0” mode, or equivalent, and be able to access all memory and I/O space.
This prerequisite is strictly dependent on the processor generation architecture.
5.1.2.2. Processor Execution Mode in Itanium ® Processor Family
The PEI Foundation will begin executing after the Security (SEC) phase has completed. The SEC phase subsumed the System Abstraction Layer entry point (SALE_ENTRY) in Itanium ® architecture. In addition, the SEC phase makes the appropriate Processor Abstraction Layer (PAL) calls or platform services to enable the temporary memory store. The SEC passes its handoff state to the PEI Foundation in physical mode with some configured memory stack, such as the processor cache configured as memory.
5.1.2.3. Access to the Boot Firmware Volume (BFV) andother boot-critical FVs
The program that the Security (SEC) phase hands control to is known as the PEI Foundation. PEIMs may reside in the BFVor other FVs. A “special” PEIM must be resident in the BFV to provide information about the location of the other FVs.
Each file that is required to boot, in the BFV and other critical FVs (like where the PEI foundation is located), must be able to be discovered and validated by the PEI phase. This allows the PEI phase to determine if those FVs have been corrupted.
The PEI Foundation and the PEIMs are expected to be stored in some reasonably tamper-proof (albeit not necessarily in the strict security-based definition of the term) nonvolatile storage (NVS). The storage is expected to be fairly analogous to a flat file system with the unique IDs substituting for names. Rules for using the particular NVS might affect certain storage considerations, but a standard data-only mechanism for locating PEIMs by ID is required. The PI Architecture architecture describes the PI Firmware Volume format and PI Firmware File System format, with the GUID convention of naming files. These standards are architectural for PEI inasmuch as the PEI phase needs to directly support this file system.
The BFV can only be constructed of type
EFI_FIRMWARE_FILE_SYSTEM2_GUID
.
The PEI Foundation, and some PEIMs required for recovery, must be either locked into a nonupdateable FVor must be able to be updated via a “fault-tolerant” mechanism. The fault-tolerant mechanism is designed such that, if the system halts at any point, either the old (preupdate) PEIM or the newly updated PEIM is entirely valid and that the PEI phase can determine which is valid.
5.1.2.4. Access to the Boot Firmware Volume in IA-32Intel Architecture
In IA-32 Intel architecture, the Security (SEC) file is at the top of the Boot Firmware Volume (BFV). This SEC file will have the 16-byte entry point for IA-32 and restarts at address 0xFFFFFFF0.
5.1.2.5. Access to the Boot Firmware Volume in ItaniumProcessor Family
In the Itanium processor family, the microcode starts up the Processor Abstraction Layer A (PAL-A) code, which is the first layer of PAL code and is provided by the processor vendor, that resides in the Boot Firmware Volume (BFV). This code minimally initializes the processor and then finds and authenticates the second layer of PAL code, called PAL-B. The location of both PAL-A and PAL-B can be found by consulting either of the following:
The architected pointers in the ROM (near the 4 GiB region)
The Firmware Interface Table (FIT) pointer in the ROM
The PAL layer communicates with the OEM boot firmware using a single entry point called the System Abstraction Layer entry point (SALE_ENTRY). The PEI Foundation will be located at the SALE_ENTRY point on the boot firmware device for an Itanium-based system. The Itanium processor family PEIMs, like other PEIMs, may reside in the BFV or other firmware volumes. A “special” PEIM must be resident in the BFV to provide information about the location of the other firmware volumes; this will be described in the context of the EFI_PEI_FIND_FV_PPI description. It must also be noted that in an Itanium-based system, all the processors in each node start up and execute the PAL code and subsequently enter the PEI Foundation. The BFV of a particular node must be accessible by all the processors running in that node. This also means that some of the PEIMs in the Itanium® architecture boot path will be multiprocessor (MP) aware.
In an Itanium-based system, it is also imperative that the organization of firmware modules in the BFV must be such that at least the PAL-A is contained in the fault-tolerant regions. This processor-specific PAL-A code authenticates the PAL-B code, which is usually contained in the non-fault-tolerant regions of the firmware system. The PAL-A and PAL-B binary components are always visible to all the processors in a node at the time of power-on; the system fabric should not need to be initialized.
5.2. PEI Foundation Entry Point
5.2.1. PEI Foundation Entry Point
The Security (SEC) phase calls the entry point to the PEI Foundation with the following information:
A set of PPIs
Size and location of the Boot Firmware Volume (BFV)
Size and location of other boot-critical FVs, by adding the firmware volume into the PpiList with
EFI_PEI_FIRMWARE_VOLUME_PPI
type.Size and location of the temporary RAM
Size and location of the temporary RAM available for use by the PEI Foundation
Size and location of the stack
The entry point is described in “Code Definitions” below.
Prototype
typedef
VOID
EFIAPI
(*EFI_PEI_CORE_ENTRY_POINT)(
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
);
Parameters
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. The type
EFI_SEC_PEI_HAND_OFF
is defined in “Related Definitions” below.
PpiList
Points to a list of one or more PPI descriptors. These PPI descriptors can be a combination of descriptors of type
EFI_PEI_PPI_DESCRIPTOR
for PPIs to be installed initially by the PEI core and descriptors of typeEFI_PEI_NOTIFY_DESCRIPTOR
for notifications in which the PEI Core will notify when the PPI service is installed. An empty PPI list consists of a single descriptor with the end-tagEFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
. TypesEFI_PEI_PPI_DESCRIPTOR
andEFI_PEI_NOTIFY_DESCRIPTOR
are defined in “PEIM Descriptors.” As part of its initialization phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database, such that both the PEI Foundation and any modules can leverage the associated service calls and/or code in these early PPIs. This should contain all the boot critical FVs that would be passed from SEC to PEI Foundation thorough theEFI_PEI_FIRMWARE_VOLUME_PPI
.
Description
This function is the entry point for the PEI Foundation, which allows the SEC phase to pass information about the stack, temporary RAM and the Boot Firmware Volume. In addition, it also allows the SEC phase to pass services and data forward for use during the PEI phase in the form of one or more PPIs. These PPI’s will be installed and/or immediately signaled if they are notification type.
There is no limit to the number of additional PPIs that can be passed from SEC into the PEI Foundation. As part of its initialization phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database such that both the PEI Foundation and any modules can leverage the associated service calls and/or code in these early PPIs.
Finally, later phases of platform evolution might need many
of the features and data that the SEC phase might possibly
have. To support this, the SEC phase can construct a
EFI_PEI_PPI_DESCRIPTOR
and pass its address into the PEI
Foundation as the final argument.
Among these PPIs, the SEC can pass an optional PPI,
EFI_SEC_PLATFORM_INFORMATION_PPI
, as part of the PPI list
that is passed to the PEI Foundation entry point. This PPI
abstracts platform-specific information that the PEI
Foundation needs to discover where to begin dispatching
PEIMs. Other possible values to pass into the PEI Foundation
would include any security or verification services, such as
the Trusted Computing Group (TCG) access services, because
the SEC would constitute the Core Root-of-Trust Module
(CRTM) in a TCG-conformant system.
Further, SEC can pass the EFI_SEC_HOB_DATA_PPI
as a part
of the PPI list. This PPI can retrieve zero or more HOBs to
be added to the HOB list before any PEIMs are dispatched.
typedef struct _EFI_SEC_PEI_HAND_OFF {
UINT16 DataSize;
VOID *BootFirmwareVolumeBase;
UINTN BootFirmwareVolumeSize;
VOID *TemporaryRamBase;
UINTN TemporaryRamSize;
VOID *PeiTemporaryRamBase;
UINTN PeiTemporaryRamSize;
VOID *StackBase;
UINTN StackSize;
} EFI_SEC_PEI_HAND_OFF;
DataSize
Size of the data structure.
BootFirmwareVolumeBase
Points to the first byte of the boot firmware volume, which the PEI Dispatcher should search for PEI modules.
BootFirmwareVolumeSize
Size of the boot firmware volume, in bytes.
TemporaryRamBase
Points to the first byte of the temporary RAM.
TemporaryRamSize
Size of the temporary RAM, in bytes.
PeiTemporaryRamBase
Points to the first byte of the temporary RAM available for use by the PEI Foundation. The area described by
PeiTemporaryRamBase
andPeiTemporaryRamSize
must not extend outside beyond the area described byTemporaryRamBase
&TemporaryRamSize
. This area should not overlap with the area reported byStackBase
andStackSize
.
PeiTemporaryRamSize
Size of the available temporary RAM available for use by the PEI Foundation, in bytes.
StackBase
Points to the first byte of the stack. This are may be part of the memory described by
TemporaryRamBase
andTemporaryRamSize
or may be an entirely separate area.
StackSize
Size of the stack, in bytes.
The information from SEC is mandatory information that is placed on the stack by the SEC phase to invoke the PEI Foundation.
The SEC phase provides the required processor and/or platform initialization such that there is a temporary RAM region available to the PEI phase. This temporary RAM could be a particular configuration of the processor cache, SRAM, or other source. What is important with respect to this handoff is that the PEI ascertain the available amount of cache as RAM from this data structure.
Similarly, the PEI Foundation needs to receive a priori
information about where to commence the dispatch of
PEIMs. A platform can have various size BFVs. As such,
the BootFirmwareVolume
value tells the PEI Foundation
where it can expect to discover a firmware volume header
data structure, and it is this firmware volume that
contains the PEIMs necessary to perform the basic system
initialization.
5.3. PEI Calling Convention Processor Binding
Unless otherwise specified, the calling convention used for PEI functions is the same as the one specified in the UEFI specification. However, for certain processors, an alternate calling convention is recommended for new PPI definitions.
5.4. PEI Services Table Retrieval
This section describes processor-specific mechanisms for retrieving a pointer to a pointer to the PEI Services Table (EFI_PEI_SERVICES **
) such as is commonly used in PEIMs. The means of storage and retrieval are processor specific.
5.4.1. x86
For x86 processors, EFI_PEI_SERVICES **
is stored in the 4 bytes immediately preceding the Interrupt Descriptor Table. The EFI_PEI_SERVICES **
can be retrieved with the following code fragment, which should be placed in a library routine for portability between architectures:
IDTR32 STRUCT
Limit DW 1 DUP (?)
BaseAddress DD 1 DUP (?)
IDTR32 ENDS
sub esp, SIZEOF IDTR32
sidt FWORD PTR ss:[esp]
mov eax, [esp].IDTR32.BaseAddress
mov eax, DWORD PTR [eax - 4]
add esp, SIZEOF IDTR32
5.4.1.1. Interrupt Descriptor Table Initialization and Ownership Rules
The SEC Core must initialize the IDT using the lidt command and ensure that the four-bytes field immediately preceding the IDT base address resides within temporary memory.
The PEI Foundation initializes or updates the four-byte field immediately preceding the currently loaded IDT base address.
Any PEIM can reinitialize the IDT with the following restrictions:
The four-bytes field immediately prior to new IDT base address must reside within the temporary or permanent memory.
The four-byte field immediately preceding the old IDT base address must be copied to the four-byte field immediately preceding the new IDT base address.
5.4.2. x64
For x64 processors, the EFI_PEI_SERVICES **
is stored in eight bytes immediately preceding the Interrupt Descriptor Table. The EFI_PEI_SERVICES **
can be retrieved with the following code fragment, which should be placed in a library routine for portability between architectures:
IDTR64 STRUCT
Limit DW 1 DUP (?)
BaseAddress DQ 1 DUP (?)
IDTR64 ENDS
sub rsp, SIZEOF IDTR64
sidt [rsp]
mov rax, [rsp].IDTR64.BaseAddress
mov rax, QWORD PTR [rax - 8]
add rsp, SIZEOF IDTR64
5.4.2.1. Interrupt Descriptor Table Initialization and Ownership Rules
The SEC Core must initialize the IDT using the lidt command and ensure that the eight-bytes field immediately preceding the IDT base address resides within temporary memory.
The PEI initializes or updates the eight-byte field immediately preceding the currently loaded IDT base address.
Any PEIM can reinitialize the IDT with the following restrictions:
The eight-bytes field immediately prior to new IDT base address must reside within the temporary or permanent memory
The eight-byte field immediately preceding the old IDT base address must be copied to the eight-byte field immediately preceding the new IDT base address.
5.4.3. Itanium Processor Family - Register Mechanism
For Itanium Processor Family processors, the EFI_PEI_SERVICES **
is stored in kernel register 7 (ar.kr7).
Information on the kernel registers for IPF can be found at http://www.intel.com/design/itanium/downloads/245358.htm.
The EFI_PEI_SERVICES **
can be retrieved with the following code fragment, which may be placed in a library routine for portability between architectures:
AsmReadKr7
mov r8, ar.kr7;;
br.ret b0;;
CONST EFI_PEI_SERVICES **
GetPeiServicesTablePointer (
VOID
)
{
return (CONST EFI_PEI_SERVICES **)AsmReadKr7 ();
}
Note: Compilers should not be using KRs, they are reserved for OS use (i.e.,this is the overlap w/ the Software Development Manual). Also, priv. level 3 code can only read KRs and not write them anyway, only PL0 code can write these.
5.4.4. ARM Processor Family - Register Mechanism
For ARM Processor Family processors, the EFI_PEI_SERVICES **
is stored in the TPIDRURW read/write Software Thread ID register defined in the ARMv7-A Architectural Reference Manual.
The EFI_PEI_SERVICES **
can be retrieved with the following code fragment, which may be placed in a library routine for portability between architectures:
CpuReadTPIDRURW:
MRC p15, 0, r0, c13, c0, 2
bx lr
CONST EFI_PEI_SERVICES **
GetPeiServicesTablePointer (
VOID
)
{
return (CONST EFI_PEI_SERVICES **)CpuReadTPIDRURW ();
}
5.4.4.1. ARM Vector Table
For ARM processors the vector table entries are instructions, and thus are limited to 24-bit relative offset of a branch instruction. The PI specification requires that the 8 defined vectors contain the following instruction LDR pc, [pc, #0x20]. This means the 32-bit address of the handler is contained at a 32-byte offset from the address of the vector. When PI code hooks into the vector table it must ensure that the 32-bit absolute address offset 32-bytes from the vector is what is updated. The first code in the platform that initializes the vector table must fill it with 8 LDR pc, [pc, #0x20] instructions.
5.4.5. AArch64 Processor Family - Register Mechanism
For AArch64 architecture processors, the EFI_PEI_SERVICES **
is stored in the TPIDR_EL0 register. Information on this register can be found in the “ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile”.
5.4.6. RISC-V Processor Family - Register Mechanism
For RISC-V architecture processors, the EFI_PEI_SERVICES **
is stored in the SSCRATCH register. Information on this register can be found in the “The RISC-V Instruction Set Manual Volume II: Privileged Architecture”.
ASM_FUNC (RiscVGetSupervisorScratch)
csrr a0, CSR_SSCRATCH
ret
CONST EFI_PEI_SERVICES **
GetPeiServicesTablePointer (
VOID
)
{
return (CONST EFI_PEI_SERVICES **)RiscVGetSupervisorScratch ();
}
5.4.7. LoongArch Processor Family - Register Mechanism
For the LoongArch Processor, the EFI_PEI_SERVICES**
is stored in the CSR_KS0(SAVE0)
register. Information on this register can be found in the LoongArch Reference Manual, Volume 1 at https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html.
The EFI_PEI_SERVICES**
can be retrieved with the following code fragment, which may be placed in a library routine for portability between architectures:
#define LOONGARCH_CSR_KS0 0x30
AsmCsrReadKs0:
csrrd $a0, LOONGARCH_CSR_KS0
jirl $zero, $ra, 0
CONST EFI_PEI_SERVICES **
EFIAPI
GetPeiServicesTablePointer (
VOID
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = (CONST EFI_PEI_SERVICES **)AsmCsrReadKs0 ();
ASSERT (PeiServices != NULL);
return PeiServices;
}
5.5. PEI Dispatcher Introduction
The PEI Dispatcher’s job is to hand control to the PEIMs in an
orderly manner. The PEI Dispatcher consists of a single phase. It
is during this phase that the PEI Foundation will examine each
file in the firmware volumes that contain files of type
EFI_FV_FILETYPE_PEIM
or EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
(see the Platform Initialization Specification, Volume 3, for
file type definitions). It will examine the dependency expression
(depex) and the optional a priori file within each firmware file
to decide when a PEIM is eligible to be dispatched. The binary
encoding of the depex will be the same as that of a depex
associated with a PEIM.
5.6. Ordering
5.6.1. Requirements
Except for the order imposed by an a priori file, it is not reasonable to expect PEIMs to be executed in any order. A chipset initialization PEIM usually requires processor initialization and a memory initialization PEIM usually requires chipset initialization. On the other hand, the PEIMs that satisfy these requirements might have been authored by different organizations and might reside in different FVs. The requirement is thus to, without memory, create a mechanism to allow for the definition of ordering among the different PEIMs so that, by the time a PEIM executes, all of the requirements for it to execute have been met.
Although the update and build processes assist in resolving ordering issues, they cannot be relied upon completely. Consider a system with a removable processor card containing a processor and firmware volume that plugs into a main system board. If the processor card is upgraded, it is entirely reasonable that the user should expect the system to work even though no update program was executed.
5.6.2. Requirement Representation and Notation
Requirements are represented by GUIDs, with each GUID representing a particular requirement. The requirements are represented by two sets of data structures:
The dependency expression (depex) of a given PEIM
The installed set of PPIs maintained by the PEI Foundation in the PPI database
This mechanism provides for a “weak ordering” among PEIMs. If PEIMs A and B consume X (written AcX and BcX), once a PEIM (C) that produces X (CpX) is executed, A and B can be executed. There is no definition about the order in which A and B are executed.
5.6.3. PEI a priori File Overview
The PEI a priori file is a special file that may optionally be present in a firmware volume, and its main purpose is to provide a greater degree of flexibility in the firmware design of a platform. Specifically, the a priori file complements the dependency expression mechanism of PEI by stipulating a series of modules which need be dispatched in a prescribed order.
There may be at most one PEI a priori file per firmware volume
present in a platform. The a priori file has a known GUID file
name PEI_APRIORI_FILE_NAME_GUID
, enabling the PEI Foundation
dispatch behavior to find the a priori file if it is present.
The contents of the file shall contain data of the format
PEI_APRIORI_FILE_CONTENTS
, with possibly zero entries. Every
time the PEI Dispatcher discovers a firmware volume, it first
looks for the a priori file. The PEIM’s enumerated in a an a
priori file must exist in the same firmware volume as the a
priori file iteself; no cross-volume mapping is allowed. The
PEI Foundation will invoke the PEIM’s listed in the
PEI_APRIORI_FILE_CONTENTS
in the order found in this file.
Without the a priori file, PEIMs executed solely because of their dependency expressions are weakly ordered. This means that the execution order is not completely deterministic between boots or between platforms. In some cases a deterministic execution order is required. The PEI a priori file provides a deterministic execution order of PEIMs using the following two implementation methods.
The a priori model must be supported by all PEI Foundation implementations, but it does not preclude additional a priori dispatch methodologies, as long as the latter models use a different mechanism and/or file name GUID for the alternate a priori module listing. The a priori file format follows below.
5.6.3.1. PEI_APRIORI_FILE_NAME_GUID
Summary
The GUID PEI_APRIORI_FILE_NAME_GUID
definition is the file
name of the PEI a priori file that is stored in a firmware
volume.
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;
Parameters
FileNamesWithinVolume[]
An array of zero or more EFI_GUID type entries that match the file names of PEIM modules in the same Firmware Volume. The maximum number of entries
NumberOfModulesInVolume
is determined by the number of modules in the FV.
Description
This file must be of type EFI_FV_FILETYPE_FREEFORM
and
must contain a single section of type EFI_SECTION_RAW
.
For details on firmware volumes, firmware file types, and
firmware file section types, see the Platform
Initialization Specification , Volume 3.
5.6.3.2. Dispatch Behavior
The a priori file can contain a list of the EFI_GUIDs,
which are the names of the PEIM files within the same
firmware volume. Herein, the PEI Foundation dispatch
logic reads the list of names from the a priori file and
invokes the appropriately named module in the order
enumerated in the a priori file. This value can be
calculated by means of the size of
PEI_APRIORI_FILE_CONTENTS
. This shall be an integral
number of GUID sizes.
If there is a file name within
PEI_APRIORI_FILE_CONTENTS
which is in the deleted state
or does not exist, the specific file name shall be
ignored by the PEI Foundation dispatch logic and the
successive entry invoked.
During dispatch of PEIM’s in the a priori file, any PEIMs in newly published firmware volumes will be ignored until completion of the a priori file dispatch. These interfaces would be assessed during subsequent module dispatch, though.
In addition to ignoring any additional volumes published
during a priori dispatch, any dependency expressions
associated with PEIMs listed within
PEI_APRIORI_FILE_CONTENTS
are ignored.
During dispatch of the a priori PEIM list, the PEI
Dispatcher shall invoke the EFI_PEI_SECURITY2_PPI
AuthenticationState
service, if it exists, to qualify
the dispatch of each module. This is the same behavior as
the normal dependency-based dispatch. For the a priori
file in the boot firmware volume, for example, the
EFI_PEI_SECURITY2_PPI
could be passed by the SEC into
the PEI Foundation via the optional
EFI_PEI_PPI_DESCRIPTOR
list. This latter scenario
allows authentication of PEIMs in the a priori file.
After executing all of the PEIMs specified in the a priori file, the PEI Dispatcher searches the firmware volume for any additional PEIMs and executes them according to their dependency expressions.
5.6.4. Firmware Volume Image Files
For PEI, while processing a firmware volume, if a file of
type EFI_FV_FIRMWARE_VOLUME_IMAGE
is found, the PEI
Dispatcher will check whether this firmware volume image
file was already processed. If it was, then the file is
ignored.
Otherwise, the PEI Dispatcher will search the file for a
section with the type EFI_SECTION_PEI_DEPEX
, and if
found, evaluate the expression against the presently
installed entries in the PPI database. If the file has a
dependency expression that evaluates to TRUE (or no
EFI_SECTION_PEI_DEPEX
section), then the PEI Dispatcher
will search the file for a section with the type
EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, copy its contents into
memory, and install the EFI_PEI_FIRMWARE_VOLUME_INFO_PPI
and EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI
for the firmware
volume image, and add HOBs of type EFI_HOB_FIRMWARE_VOLUME
and EFI_HOB_FIRMWARE_VOLUME2
to the hob list for the
firmware volume image.
5.6.5. PEIM Dependency Expressions
The sequencing of PEIMs is determined by evaluating a dependency expression associated with each PEIM. This expression describes the requirements necessary for that PEIM to run, which imposes a weak ordering on the PEIMs. Within this weak ordering, the PEIMs may be initialized in any order.
5.6.6. Types of Dependencies
The base unit of the dependency expression is a dependency. A representative syntax (used in this document for descriptive purposes) for each dependency is shown in the following section. The syntax is case-insensitive and mnemonics are used in place of non-human-readable data such as GUIDs. White space is optional.
The operands are GUIDs of PPIs. The operand becomes “true” when a PPI with the GUID is registered.
5.7. Dependency Expressions
5.7.1. Introduction
A PEIM is stored in a firmware volume as a file with one or more sections. One of the sections must be a PE32+ image. If a PEIM has a dependency expression, then it is stored in a dependency section. A PEIM may contain additional sections for compression and security wrappers. The PEI Dispatcher can identify the PEIMs by their file type. In addition, the PEI Dispatcher can look up the dependency expression for a PEIM by looking for a dependency section in a PEIM file. The dependency section contains a section header followed by the actual dependency expression that is composed of a packed byte stream of opcodes and operands.
Dependency expressions stored in dependency sections are designed to meet the following goals:
Be small to conserve space.
Be simple and quick to evaluate to reduce execution overhead.
These two goals are met by designing a small, stack-based instruction set to encode the dependency expressions. The PEI Dispatcher must implement an interpreter for this instruction set to evaluate dependency expressions. The instruction set is defined in the following topics.
See Dependency Expression Grammar for an example BNF grammar for a dependency expression compiler. There are many possible methods of specifying the dependency expression for a PEIM. This example grammar demonstrates one possible design for a tool that can be used to help build PEIM images.
5.7.1.1. Dependency Expression Instruction Set
The following topics describe each of the dependency expression (depex) opcodes in detail. Information includes a description of the instruction functionality, binary encoding, and any limitations or unique behaviors of the instruction.
Several of the opcodes require a GUID operand. The GUID
operand is a 16-byte value that matches the type EFI_GUID
that is described in Chapter 2 of the UEFI 2.0
specification. These GUIDs represent PPIs that are produced
by PEIMs and the file names of PEIMs stored in firmware
volumes. A dependency expression is a packed byte stream of
opcodes and operands. As a result, some of the GUID operands
will not be aligned on natural boundaries. Care must be
taken on processor architectures that do allow unaligned
accesses.
The dependency expression is stored in a packed byte stream
using postfix notation. As a dependency expression is
evaluated, the operands are pushed onto a stack. Operands
are popped off the stack to perform an operation. After the
last operation is performed, the value on the top of the
stack represents the evaluation of the entire dependency
expression. If a push operation causes a stack overflow,
then the entire dependency expression evaluates to FALSE
.
If a pop operation causes a stack underflow, then the entire
dependency expression evaluates to FALSE
. Reasonable
implementations of a dependency expression evaluator should
not make arbitrary assumptions about the maximum stack size
it will support. Instead, it should be designed to grow the
dependency expression stack as required. In addition, PEIMs
that contain dependency expressions should make an effort to
keep their dependency expressions as small as possible to
help reduce the size of the PEIM.
All opcodes are 8-bit values, and if an invalid opcode is
encountered, then the entire dependency expression evaluates
to FALSE
.
If an END opcode is not present in a dependency expression,
then the entire dependency expression evaluates to FALSE
.
The final evaluation of the dependency expression results in
either a TRUE
or FALSE
result.
Note
The PEI Foundation will only support the evaluation of dependency expressions that are less than or equal to 256 terms.
Dependency Expression Opcode Summary is a summary of the opcodes that are used to build dependency expressions. The following sections describe each of these instructions in detail.
Opcode |
Description |
---|---|
0x02 |
PUSH <PPI GUID> |
0x03 |
AND |
0x04 |
OR |
0x05 |
NOT |
0x06 |
TRUE |
0x07 |
FALSE |
0x08 |
END |
5.7.1.1.1. PUSH
Syntax
PUSH <PPI GUID>
Description
Pushes a Boolean value onto the stack. If the GUID is
present in the handle database, then a TRUE
is pushed onto
the stack. If the GUID is not present in the handle
database, then a FALSE
is pushed onto the stack. The test
for the GUID in the handle database may be performed with
the Boot Service LocatePpi()
.
Operation
Status = (*PeiServices)->LocatePpi (PeiServices, GUID, 0, NULL, &Interface);
if (EFI_ERROR (Status)) {
PUSH FALSE;
} Else {
PUSH TRUE;
}
The following table defines the PUSH
instruction encoding.
Byte |
Description |
---|---|
0 |
0x02 |
1 16 |
A 16 byte GUID that represents a protocol that is produced by a different PEIM The format is the same at type EFI_GUID |
Behaviors and Restrictions
None.
5.7.1.1.2. AND
Syntax
AND
Description
Pops two Boolean operands off the stack, performs a Boolean
AND
operation between the two operands, and pushes the
result back onto the stack.
Operation
Operand1 <= POP Boolean stack element
Operand2 <= POP Boolean stack element
Result <= Operand1 AND Operand2
PUSH Result
AND Instruction Encoding defines the
AND
instruction encoding.
Byte |
Description |
---|---|
0 |
0x03 |
Behaviors and Restrictions
None.
5.7.1.1.3. OR
Syntax
OR
Description
Pops two Boolean operands off the stack, performs a Boolean
OR
operation between the two operands, and pushes the
result back onto the stack.
Operation
Operand1 <= POP Boolean stack element
Operand2 <= POP Boolean stack element
Result <= Operand1 OR Operand2
PUSH Result
OR Instruction Encoding defines the OR
instruction encoding.
Byte |
Description |
---|---|
0 |
0x04 |
Behaviors and Restrictions
None.
5.7.1.1.4. NOT
Syntax
NOT
Description
Pops a Boolean operands off the stack, performs a Boolean
NOT
operation on the operand, and pushes the result back
onto the stack.
Operation
Operand <= POP Boolean stack element
Result <= NOT Operand
PUSH Result
NOT Instruction Encoding defines the
NOT
instruction encoding.
Byte |
Description |
---|---|
0 |
0x05 |
Behaviors and Restrictions
None.
5.7.1.1.5. TRUE
Syntax
TRUE
Description
Pushes a Boolean TRUE
onto the stack.
Operation
PUSH TRUE
TRUE Instruction Encoding defines the
TRUE
instruction encoding.
Byte |
Description |
---|---|
0 |
0x06 |
Behaviors and Restrictions
None.
5.7.1.1.6. FALSE
Syntax
FALSE
Description
Pushes a Boolean FALSE
onto the stack.
Operation
PUSH FALSE
FALSE Instruction Encoding defines the
FALSE
instruction encoding.
Byte |
Description |
---|---|
0 |
0x07 |
Behaviors and Restrictions
None.
5.7.1.1.7. END
Syntax
END
Description
Pops the final result of the dependency expression evaluation off the stack and exits the dependency expression evaluator.
Operation
POP Result
RETURN Result
END Instruction Encoding defines the
END
instruction encoding.
Byte |
Description |
---|---|
0 |
0x08 |
Behaviors and Restrictions
This opcode must be the last one in a dependency expression.
5.7.2. Dependency Expression with No Dependencies
A PEIM that does not have any dependencies will have a
dependency expression that evaluates to TRUE
with no
dependencies on any PPI GUIDs.
5.7.3. Empty Dependency Expressions
If a PEIM file does not contain a dependency section, then the PEIM has an empty dependency expression.
5.7.4. Dependency Expression Reverse Polish Notation(RPN)
The actual equations will be presented by the PEIM in a simple-to-evaluate form, namely postfix. The following is a BNF encoding of this grammar. See Dependency Expression Instruction Set for definitions of the dependency expressions.
<statement> ::= <expression> END
<expression> ::= PUSH <guid> |
TRUE |
FALSE |
<expression> NOT |
<expression> <expression> OR |
<expression> <expression> AND
5.8. Dispatch Algorithm
5.8.1. Overview
5.8.1.1. Ordering Algorithm
The dispatch algorithm repeatedly scans through the PEIMs to find those that have not been dispatched. For each PEIM that is found, it scans through the PPI database of PPIs that have been published, searching for elements in the yet-to-be-dispatched PEIM’s depex. If all of the elements in the depex are in the PEI Foundation’s PPI database, the PEIM is dispatched. The phase terminates when all PEIMs are scanned and none dispatched.
Note
The PEIM may be dispatched without a search if its depex is NULL.
5.8.1.2. Multiple Firmware Volume Support
In order to expose a new firmware volume, a PEIM should
install an instance of EFI_PEI_FIRMWARE_VOLUME_INFO_PPI
containing the firmware volume format GUID, the starting
address and the size of the firmware volume’s window. PEIMs
exposing firmware volumes which have a firmware volume
format other than the PI Architecture Firmware Volume format
should include the firmware volume format GUID in their
dependency expression.
PEIMs exposing memory-mapped firmware volumes should create a memory resource descriptor HOB for the memory occupied by the firmware volume if it is outside of the PEI memory.
For each new exposed firmware volume, the PEI Foundation will take the following steps:
Create a new firmware volume handle. The firmware volume handle may be created by the PEI Foundation or by the optional
EFI_PEI_FIRMWARE_VOLUME_PPI.
Create a new firmware volume HOB.
If the firmware volume’s format (identified by its GUID) is not supported directly by the PEI Foundation and it is not supported by any installed
EFI_PEI_FIRMWARE_VOLUME_PPI
, the firmware volume is skipped.Otherwise, all PEIMs in the firmware volume are scheduled for dispatching.
Find the a priori file, if it exists, and dispatch any PEIMs listed in it.
5.8.2. Requirements
5.8.2.1. Requirements of a Dispatching Algorithm
The dispatching algorithm must meet the following requirements:
Preserve the dispatch weak ordering.
Prevent an infinite loop.
Control processor resources.
Preserve proper dispatch order.
Make use of available memory.
Invoke each PEIM’s entry point.
Know when the PEI Dispatcher tasks are finished.
5.8.2.2. Preserving Weak Ordering
The algorithm must preserve the weak ordering implied by the depex.
5.8.2.3. Preventing Infinite Loops
It is illegal for AcXpY (A consumes X and produces Y) and BcYpX. This is known as a cycle and is unresolvable even if memory is available. At a minimum, the dispatching algorithm must not end up in an infinite loop in such a scenario. With the algorithm described above, neither PEIM would be executed.
5.8.2.4. Controlling Processor Register Resources
The algorithm must require that a minimum of the processor’s register resources be preserved while PEIMs are dispatched.
5.8.2.5. Preserving Proper Dispatch Order
The algorithm must preserve proper dispatch order in cases such as the following:
AcQpZ BcLpR CpL DcRpQ
The issue with the above scenario is that A and B are not obviously related until D is processed. If A and B were in one firmware volume and C and D were in another, the ordering could not be resolved until execution. The proper dispatch order in this case is CBDA. The algorithm must resolve this type of case.
5.8.2.6. Using Available Memory
The PEI Foundation begins operation using a temporary memory store that contains the initial call stack from the Security (SEC) phase. The SEC phase must pass the size and location of the stack and the size and location of the temporary memory store.
The PEI stack will be available for subsequent PEIM invocations, and the PEI heap will be used for PEIM memory allocations and Hand-Off Block (HOB) creation.
There can be no memory writes to the address space beyond
this initial temporary memory until a PEIM registers a
permanent memory range using the PEI Service
InstallPeiMemory()
. When permanent memory is installed,
the PEI Foundation will copy the call stack that is located
in temporary memory into a segment of permanent memory. If
necessary, the size of the call stack can be expanded to
support the subsequent transition into DXE.
In addition to the call stack, the PEI Foundation will copy the following from temporary to permanent memory:
PEI Foundation private data
PEI Foundation heap
HOB list
Installed Firmware Volumes
Any permanent memory consumed in this fashion by the PEI Foundation will be described in a HOB, which the PEI Foundation will create.
The PEI Foundation will copy any installed firmware volumes
from the temporary memory location to a permanent memory
location with the alignment specified in the firmware volume
header. Any uncompressed PE32 or TE sections within PEIMs in
these firmware volumes will be fixed up. This ensures any
static EFI_PEI_PPI_DESCRIPTOR
s or PPI interface pointers
in these PEIMs point to the permanent memory addresses.
In addition, if there were any EFI_PEI_PPI_DESCRIPTOR
s
created in the temporary memory heap or declared statically
in PEIMs, their respective locations have been translated by
an offset equal to the difference between the original
location in temporary memory and the destination location in
permanent memory. In addition to this heap copy, the PEI
Foundation will traverse the PEI PPI database. Any
references to EFI_PEI_PPI_DESCRIPTOR
s that are in
temporary memory will be fixed up by the PEI Foundation to
reflect the location of the EFI_PEI_PPI_DESCRIPTOR
s
destination in permanent memory.
The PEI Foundation will invoke the DXE IPL PPI after dispatching all candidate PEIMs. The DXE IPL PPI may have to allocate additional regions from permanent memory to be able to load and relocate the DXE Foundation from its firmware store. The DXE IPL PPI will describe these memory allocations in the appropriate HOB such that when control is passed to DXE, an accurate record of the memory usage will be known to the DXE Foundation.
5.8.2.7. Invoking the PEIM’s Entry Point
The entry point of a PEIM uses the calling conventions specified in the UEFI 2.0 specification, which detail how parameters are passed to a function. After assessing a PEIM’s dependency expression to see if it can be invoked, the PEI Foundation will pass control to the PEIM’s entry point. This entry point is a value described in the PEIM’s image header.
The PEI Foundation will pass an indirect pointer to the PEI Services Table and the handle of the firmware file when it invokes the PEIM.
In the entry point of the PEIM, the PEIM has the opportunity do the following:
Locate other PPIs
Install PPIs that reference services within the body of this PEIM
Register for a notification
Upon return from the PEIM’s entry point, it returns back to the PEI Foundation.
See the Microsoft Portable Executable and Common Object File Format Specification for information on PE/COFF images; see TE Image for information on TE images.
5.8.2.8. Knowing When Dispatcher Tasks Are Finished
The PEI Dispatcher is finished with a pass when it has finished dispatching all the PEIMs that it can. During a pass, some PEIMs might not have been dispatched if they had requirements that no other PEIM has met.
However, with the weak ordering defined in previous requirements, system RAM could possibly be initialized before all PEIMs are given a chance to run. This situation can occur because the system RAM initialization PEIM is not required to consume all resources provided by all other PEIMs. The PEI Dispatcher must recognize that its tasks are not complete until all PEIMs have been given an opportunity to run.
5.8.2.9. Reporting PEI Core Location
If the EFI_PEI_LOADED_IMAGE_PPI
is supported by the PEI
Dispatcher, then the PEI Foundation must first report its
own location by using the PEI Service InstallPpi()
and the
EFI_PEI_LOADED_IMAGE_PPI
. If the FileHandle
is unknown,
then NULL
can be used. PEI Foundation must also report the
location of the PEIM loaded by creating the
EFI_PEI_LOADED_IMAGE_PPI
and call the PEI Service
ReinstallPpi()
.
5.8.3. Example Dispatch Algorithm
The following pseudo code is an example of an algorithm that uses few registers and implements the requirements listed in the previous section. The pseudo code uses simple C-like statements but more assembly-like flow-of-control primitives.
The dispatch algorithm’s main data structure is the DispatchedBitMap as described in Example Dispatch Map .
PEIM# |
Item |
PEIM# |
Item |
---|---|---|---|
FV0 |
4 |
FV1 |
|
PEI Foundation |
<non PEIM> |
||
0 |
PEIM |
<non PEIM> |
|
1 |
PEIM |
<non PEIM> |
|
2 |
PEIM with |
<non PEIM> |
|
<non PEIM> |
6 |
<non PEIM> |
|
3 |
PEIM |
7 |
PEIM |
Example Dispatch Map is an example of a dispatch in a given set of firmware volumes (FVs). Following are the steps in this dispatch:
The algorithm scans through the PEIMs that it knows about.
When it comes to a PEIM that has not been dispatched, it verifies that all of the required PPIs listed in the dependency expression (depex) are in the PPI database.
If all of the GUIDed interfaces listed in the depex are available, the PEIM is invoked.
Create the
EFI_PEI_LOADED_IMAGE_PPI
and call the PEI ServiceReinstallPpi()
Iterations continue through all known PEIMs in all known FVs until a pass is made with no PEIMs dispatched, thus signifying completion.
After the dispatch completes, the PEI Foundation locates and invokes the GUID for the DXE IPL PPI, passing in the HOB address and a valid stack. Failing to discover the GUID for the DXE IPL PPI shall be an error.
5.8.4. Dispatching When Memory Exists
The purpose of the PEI phase of execution is to discover and initialize main memory. There are several circumstances in which the shadowing of a PEIM and the relocation of this image into memory are of interest. This can include but is not limited to compressing PEIMs, such as the DXE IPL PPI, those modules that are required for crisis recovery, and platforms in which code is executed from temporary memory.
The PEI architecture shall not dictate what compression mechanism is to be used, but there will be a Decompress service that is published by some PEIM that the PEI Foundation will discover and use when it becomes available. In addition, loading images also requires a full image-relocation service and the ability to flush the cache. The former will allow the PEIM that was relocated into RAM to have its relocations adjust pursuant to the new load address. The latter service will be invoked by the PEI Foundation so that this relocated code can be run, especially on Itanium-based platforms that do not have a coherent data and code cache.
A compressed section shall have an implied dependency on permanent memory having been installed. To speed up boot time, however, there can be an explicit annotation of this dependency.
5.8.5. PEIM Dispatching
When the PEI Dispatcher has decided to invoke a PEIM, the following steps are taken:
If any instances of
EFI_PEI_LOAD_FILE_PPI
are installed, they are called, one at a time, until one reportsEFI_SUCCESS
.If no instance reports
EFI_SUCCESS
or there are no instances installed, then the built-in support for (at least) the PE32+/TE XIP image formats is used.If any instances of
EFI_PEI_SECURITY2_PPI
are installed, they are called, one at a time, as long as none returns anEFI_SECURITY_VIOLATION
error. If such an error is returned, then the PEIM is marked as dispatched, but is never invoked.The PEIM’s entry point is invoked with the file’s handle and the PEI Services Table pointer.
The PEIM is marked as dispatched.
The PEI Core may decide, because of memory constraints or performance reasons, to dispatch XIP instead of shadowing into memory.
5.8.6. PEIM Authentication
The PEI specification provides three methods which the PEI Foundation can use to authenticate a PEIM:
The authentication information could be encoded as part of a GUIDed section. In this case, the provider of the
EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
(see the Platform Initialization Specification , Volume 3) can check the authentication data and return the results inAttestationState
.The authentication information can be checked by the provider of the
EFI_PEI_LOAD_FILE_PPI
(see the Platform Initialization Specification , Volume 3) and the results returned inAttestationState
.The PEI Foundation may implement the digital signing as described in the UEFI 2.0 specification.
In all cases, the result of the authentication must be passed
to any instances of the EFI_PEI_SECURITY2_PPI
.