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 type EFI_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-tag EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. Types EFI_PEI_PPI_DESCRIPTOR and EFI_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 the EFI_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 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.

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 and TemporaryRamSize 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

  1. 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.

  2. The PEI Foundation initializes or updates the four-byte field immediately preceding the currently loaded IDT base address.

  3. 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

  1. 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.

  2. The PEI initializes or updates the eight-byte field immediately preceding the currently loaded IDT base address.

  3. 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.

Table 5.1 Dependency Expression Opcode Summary

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.

Table 5.2 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.

Table 5.3 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.

Table 5.4 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.

Table 5.5 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.

Table 5.6 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.

Table 5.7 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.

Table 5.8 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:

  1. 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.

  2. Create a new firmware volume HOB.

  3. 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.

  4. Otherwise, all PEIMs in the firmware volume are scheduled for dispatching.

  5. 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:

  1. Preserve the dispatch weak ordering.

  2. Prevent an infinite loop.

  3. Control processor resources.

  4. Preserve proper dispatch order.

  5. Make use of available memory.

  6. Invoke each PEIM’s entry point.

  7. 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 .

Table 5.9 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 EFI_PEI_FIRMWARE_VOLUME_PPI

<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:

  1. The algorithm scans through the PEIMs that it knows about.

  2. 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.

  3. If all of the GUIDed interfaces listed in the depex are available, the PEIM is invoked.

  4. Create the EFI_PEI_LOADED_IMAGE_PPI and call the PEI Service ReinstallPpi()

  5. Iterations continue through all known PEIMs in all known FVs until a pass is made with no PEIMs dispatched, thus signifying completion.

  6. 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:

  1. If any instances of EFI_PEI_LOAD_FILE_PPI are installed, they are called, one at a time, until one reports EFI_SUCCESS .

  2. 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.

  3. If any instances of EFI_PEI_SECURITY2_PPI are installed, they are called, one at a time, as long as none returns an EFI_SECURITY_VIOLATION error. If such an error is returned, then the PEIM is marked as dispatched, but is never invoked.

  4. The PEIM’s entry point is invoked with the file’s handle and the PEI Services Table pointer.

  5. 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:

  1. 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 in AttestationState .

  2. 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 in AttestationState .

  3. 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 .