summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2018-04-25 17:45:46 +0800
committerGuo Mang <mang.guo@intel.com>2018-04-25 17:45:46 +0800
commit03de3a8a20ef4daa46632f0661c9dba0b4ed8f2a (patch)
tree63294afbc7b12b784af3961c651c652dbb3f86f3
parent13a8de89581cae47f03188ec98b4e698310eb767 (diff)
downloadedk2-platforms-03de3a8a20ef4daa46632f0661c9dba0b4ed8f2a.tar.xz
Copy Pei core and PCD driver
Copy Pei core and PCD driver from edk2 because we need to do override on these two drivers. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Guo Mang <mang.guo@intel.com>
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c86
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c541
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c253
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h32
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c1372
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c2438
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h377
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c240
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c932
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c814
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c128
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.uni27
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.uni19
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h1831
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf136
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c480
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c787
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c119
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c151
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c74
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c1678
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf355
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni295
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni19
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c1074
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h1088
26 files changed, 15346 insertions, 0 deletions
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c
new file mode 100644
index 0000000000..39afeba838
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c
@@ -0,0 +1,86 @@
+/** @file
+ This module provide function for ascertaining and updating the boot mode:
+ GetBootMode()
+ SetBootMode()
+ See PI Specification volume I, chapter 9 Boot Paths for additional information
+ on the boot mode.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+ This service enables PEIMs to ascertain the present value of the boot mode.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode A pointer to contain the value of the boot mode.
+
+ @retval EFI_SUCCESS The boot mode was returned successfully.
+ @retval EFI_INVALID_PARAMETER BootMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT EFI_BOOT_MODE *BootMode
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+
+ if (BootMode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ HandOffHob = (PrivateData->HobList.HandoffInformationTable);
+
+ *BootMode = HandOffHob->BootMode;
+
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This service enables PEIMs to update the boot mode variable.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode The value of the boot mode to set.
+
+ @return EFI_SUCCESS The value was successfully updated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ HandOffHob = (PrivateData->HobList.HandoffInformationTable);
+
+ HandOffHob->BootMode = BootMode;
+
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c
new file mode 100644
index 0000000000..c82c221540
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c
@@ -0,0 +1,541 @@
+/** @file
+ The default version of EFI_PEI_CPU_IO_PPI support published by PeiServices in
+ PeiCore initialization phase.
+
+ EFI_PEI_CPU_IO_PPI is installed by some platform or chipset-specific PEIM that
+ abstracts the processor-visible I/O operations. When PeiCore is started, the
+ default version of EFI_PEI_CPU_IO_PPI will be assigned to PeiServices table.
+
+Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+///
+/// This default instance of EFI_PEI_CPU_IO_PPI install assigned to EFI_PEI_SERVICE.CpuIo
+/// when PeiCore's initialization.
+///
+EFI_PEI_CPU_IO_PPI gPeiDefaultCpuIoPpi = {
+ {
+ PeiDefaultMemRead,
+ PeiDefaultMemWrite
+ },
+ {
+ PeiDefaultIoRead,
+ PeiDefaultIoWrite
+ },
+ PeiDefaultIoRead8,
+ PeiDefaultIoRead16,
+ PeiDefaultIoRead32,
+ PeiDefaultIoRead64,
+ PeiDefaultIoWrite8,
+ PeiDefaultIoWrite16,
+ PeiDefaultIoWrite32,
+ PeiDefaultIoWrite64,
+ PeiDefaultMemRead8,
+ PeiDefaultMemRead16,
+ PeiDefaultMemRead32,
+ PeiDefaultMemRead64,
+ PeiDefaultMemWrite8,
+ PeiDefaultMemWrite16,
+ PeiDefaultMemWrite32,
+ PeiDefaultMemWrite64
+};
+
+/**
+ Memory-based read services.
+
+ This function is to perform the Memory Access Read service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Memory-based write services.
+
+ This function is to perform the Memory Access Write service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ IO-based read services.
+
+ This function is to perform the IO-base read service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ IO-based write services.
+
+ This function is to perform the IO-base write service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ 8-bit I/O read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the I/O space.
+**/
+UINT8
+EFIAPI
+PeiDefaultIoRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 16-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 16-bit value returned from the I/O space.
+**/
+UINT16
+EFIAPI
+PeiDefaultIoRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 32-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 32-bit value returned from the I/O space.
+**/
+UINT32
+EFIAPI
+PeiDefaultIoRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 64-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 64-bit value returned from the I/O space.
+**/
+UINT64
+EFIAPI
+PeiDefaultIoRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 8-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ )
+{
+}
+
+/**
+ 16-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ )
+{
+}
+
+/**
+ 32-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ )
+{
+}
+
+/**
+ 64-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ )
+{
+}
+
+/**
+ 8-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the memory space.
+
+**/
+UINT8
+EFIAPI
+PeiDefaultMemRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 16-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 16-bit value returned from the memory space.
+
+**/
+UINT16
+EFIAPI
+PeiDefaultMemRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 32-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 32-bit value returned from the memory space.
+
+**/
+UINT32
+EFIAPI
+PeiDefaultMemRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 64-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 64-bit value returned from the memory space.
+
+**/
+UINT64
+EFIAPI
+PeiDefaultMemRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 8-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ )
+{
+}
+
+/**
+ 16-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ )
+{
+}
+
+/**
+ 32-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ )
+{
+}
+
+/**
+ 64-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ )
+{
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c
new file mode 100644
index 0000000000..e71566b5a7
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c
@@ -0,0 +1,253 @@
+/** @file
+ PEI Dispatcher Dependency Evaluator
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ schedulability is that the dependency expression is satisfied.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+#include "Dependency.h"
+
+/**
+
+ This routine determines if a PPI has been installed.
+ The truth value of a GUID is determined by if the PPI has
+ been published and can be queried from the PPI database.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Stack Reference to EVAL_STACK_ENTRY that contains PPI GUID to check
+
+ @retval TRUE if the PPI is already installed.
+ @retval FALSE if the PPI has yet to be installed.
+
+**/
+BOOLEAN
+IsPpiInstalled (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EVAL_STACK_ENTRY *Stack
+ )
+{
+ VOID *PeiInstance;
+ EFI_STATUS Status;
+ EFI_GUID PpiGuid;
+
+ //
+ // If there is no GUID to evaluate, just return current result on stack.
+ //
+ if (Stack->Operator == NULL) {
+ return Stack->Result;
+ }
+
+ //
+ // Copy the Guid into a locale variable so that there are no
+ // possibilities of alignment faults for cross-compilation
+ // environments such as Intel?Itanium(TM).
+ //
+ CopyMem(&PpiGuid, Stack->Operator, sizeof(EFI_GUID));
+
+ //
+ // Check if the PPI is installed.
+ //
+ Status = PeiServicesLocatePpi(
+ &PpiGuid, // GUID
+ 0, // INSTANCE
+ NULL, // EFI_PEI_PPI_DESCRIPTOR
+ &PeiInstance // PPI
+ );
+
+ if (EFI_ERROR(Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This is the POSTFIX version of the dependency evaluator. When a
+ PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on
+ the evaluation stack. When that entry is poped from the evaluation
+ stack, the PPI is checked if it is installed. This method allows
+ some time savings as not all PPIs must be checked for certain
+ operation types (AND, OR).
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param DependencyExpression Pointer to a dependency expression. The Grammar adheres to
+ the BNF described above and is stored in postfix notation.
+
+ @retval TRUE if it is a well-formed Grammar
+ @retval FALSE if the dependency expression overflows the evaluation stack
+ if the dependency expression underflows the evaluation stack
+ if the dependency expression is not a well-formed Grammar.
+
+**/
+BOOLEAN
+PeimDispatchReadiness (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *DependencyExpression
+ )
+{
+ DEPENDENCY_EXPRESSION_OPERAND *Iterator;
+ EVAL_STACK_ENTRY *StackPtr;
+ EVAL_STACK_ENTRY EvalStack[MAX_GRAMMAR_SIZE];
+
+ Iterator = DependencyExpression;
+
+ StackPtr = EvalStack;
+
+ while (TRUE) {
+
+ switch (*(Iterator++)) {
+
+ //
+ // For performance reason we put the frequently used items in front of
+ // the rarely used items
+ //
+
+ case (EFI_DEP_PUSH):
+ //
+ // Check to make sure the dependency grammar doesn't overflow the
+ // EvalStack on the push
+ //
+ if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+
+ //
+ // Push the pointer to the PUSH opcode operator (pointer to PPI GUID)
+ // We will evaluate if the PPI is insalled on the POP operation.
+ //
+ StackPtr->Operator = (VOID *) Iterator;
+ Iterator = Iterator + sizeof (EFI_GUID);
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = %a\n", StackPtr->Operator, IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
+ StackPtr++;
+ break;
+
+ case (EFI_DEP_AND):
+ case (EFI_DEP_OR):
+ if (*(Iterator - 1) == EFI_DEP_AND) {
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ }
+ //
+ // Check to make sure the dependency grammar doesn't underflow the
+ // EvalStack on the two POPs for the AND operation. Don't need to
+ // check for the overflow on PUSHing the result since we already
+ // did two POPs.
+ //
+ if (StackPtr < &EvalStack[2]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+
+ //
+ // Evaluate the first POPed operator only. If the operand is
+ // EFI_DEP_AND and the POPed operator evaluates to FALSE, or the
+ // operand is EFI_DEP_OR and the POPed operator evaluates to TRUE,
+ // we don't need to check the second operator, and the result will be
+ // evaluation of the POPed operator. Otherwise, don't POP the second
+ // operator since it will now evaluate to the final result on the
+ // next operand that causes a POP.
+ //
+ StackPtr--;
+ //
+ // Iterator has increased by 1 after we retrieve the operand, so here we
+ // should get the value pointed by (Iterator - 1), in order to obtain the
+ // same operand.
+ //
+ if (*(Iterator - 1) == EFI_DEP_AND) {
+ if (!(IsPpiInstalled (PeiServices, StackPtr))) {
+ (StackPtr-1)->Result = FALSE;
+ (StackPtr-1)->Operator = NULL;
+ }
+ } else {
+ if (IsPpiInstalled (PeiServices, StackPtr)) {
+ (StackPtr-1)->Result = TRUE;
+ (StackPtr-1)->Operator = NULL;
+ }
+ }
+ break;
+
+ case (EFI_DEP_END):
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ StackPtr--;
+ //
+ // Check to make sure EvalStack is balanced. If not, then there is
+ // an error in the dependency grammar, so return EFI_INVALID_PARAMETER.
+ //
+ if (StackPtr != &EvalStack[0]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
+ return IsPpiInstalled (PeiServices, StackPtr);
+
+ case (EFI_DEP_NOT):
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ //
+ // Check to make sure the dependency grammar doesn't underflow the
+ // EvalStack on the POP for the NOT operation. Don't need to
+ // check for the overflow on PUSHing the result since we already
+ // did a POP.
+ //
+ if (StackPtr < &EvalStack[1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ (StackPtr-1)->Result = (BOOLEAN) !IsPpiInstalled (PeiServices, (StackPtr-1));
+ (StackPtr-1)->Operator = NULL;
+ break;
+
+ case (EFI_DEP_TRUE):
+ case (EFI_DEP_FALSE):
+ if (*(Iterator - 1) == EFI_DEP_TRUE) {
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ }
+ //
+ // Check to make sure the dependency grammar doesn't overflow the
+ // EvalStack on the push
+ //
+ if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ //
+ // Iterator has increased by 1 after we retrieve the operand, so here we
+ // should get the value pointed by (Iterator - 1), in order to obtain the
+ // same operand.
+ //
+ if (*(Iterator - 1) == EFI_DEP_TRUE) {
+ StackPtr->Result = TRUE;
+ } else {
+ StackPtr->Result = FALSE;
+ }
+ StackPtr->Operator = NULL;
+ StackPtr++;
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Invalid opcode)\n"));
+ //
+ // The grammar should never arrive here
+ //
+ return FALSE;
+ }
+ }
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h
new file mode 100644
index 0000000000..5021ce056b
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h
@@ -0,0 +1,32 @@
+/** @file
+ This module contains data specific to dependency expressions
+ and local function prototypes.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_DEPENDENCY_H_
+#define _PEI_DEPENDENCY_H_
+
+
+#define MAX_GRAMMAR_SIZE 64
+
+//
+// type definitions
+//
+typedef UINT8 DEPENDENCY_EXPRESSION_OPERAND;
+
+typedef struct {
+ BOOLEAN Result;
+ VOID *Operator;
+} EVAL_STACK_ENTRY;
+
+#endif
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
new file mode 100644
index 0000000000..79f2e5cebc
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -0,0 +1,1372 @@
+/** @file
+ EFI PEI Core dispatch services
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Discover all Peims and optional Apriori file in one FV. There is at most one
+ Apriori file in one FV.
+
+
+ @param Private Pointer to the private data passed in from caller
+ @param CoreFileHandle The instance of PEI_CORE_FV_HANDLE.
+
+**/
+VOID
+DiscoverPeimsAndOrderWithApriori (
+ IN PEI_CORE_INSTANCE *Private,
+ IN PEI_CORE_FV_HANDLE *CoreFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ EFI_PEI_FILE_HANDLE AprioriFileHandle;
+ EFI_GUID *Apriori;
+ UINTN Index;
+ UINTN Index2;
+ UINTN PeimIndex;
+ UINTN PeimCount;
+ EFI_GUID *Guid;
+ EFI_PEI_FILE_HANDLE *TempFileHandles;
+ EFI_GUID *FileGuid;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_FV_FILE_INFO FileInfo;
+
+ FvPpi = CoreFileHandle->FvPpi;
+
+ //
+ // Walk the FV and find all the PEIMs and the Apriori file.
+ //
+ AprioriFileHandle = NULL;
+ Private->CurrentFvFileHandles[0] = NULL;
+ Guid = NULL;
+ FileHandle = NULL;
+ TempFileHandles = Private->FileHandles;
+ FileGuid = Private->FileGuid;
+
+ //
+ // If the current Fv has been scanned, directly get its cachable record.
+ //
+ if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) {
+ CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
+ return;
+ }
+
+ //
+ // Go ahead to scan this Fv, and cache FileHandles within it.
+ //
+ Status = EFI_NOT_FOUND;
+ for (PeimCount = 0; PeimCount <= PcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) {
+ Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
+ if (Status != EFI_SUCCESS || PeimCount == PcdGet32 (PcdPeiCoreMaxPeimPerFv)) {
+ break;
+ }
+
+ Private->CurrentFvFileHandles[PeimCount] = FileHandle;
+ }
+
+ //
+ // Check whether the count of files exceeds the max support files in a FV image
+ // If more files are required in a FV image, PcdPeiCoreMaxPeimPerFv can be set to a larger value in DSC file.
+ //
+ ASSERT ((Status != EFI_SUCCESS) || (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)));
+
+ //
+ // Get Apriori File handle
+ //
+ Private->AprioriCount = 0;
+ Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
+ if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {
+ //
+ // Read the Apriori file
+ //
+ Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Calculate the number of PEIMs in the A Priori list
+ //
+ Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+ Private->AprioriCount = FileInfo.BufferSize;
+ if (IS_SECTION2 (FileInfo.Buffer)) {
+ Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+ Private->AprioriCount /= sizeof (EFI_GUID);
+
+ for (Index = 0; Index < PeimCount; Index++) {
+ //
+ // Make an array of file name guids that matches the FileHandle array so we can convert
+ // quickly from file name to file handle
+ //
+ Status = FvPpi->GetFileInfo (FvPpi, Private->CurrentFvFileHandles[Index], &FileInfo);
+ CopyMem (&FileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));
+ }
+
+ //
+ // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file.
+ // Add available PEIMs in Apriori file into TempFileHandles array at first.
+ //
+ Index2 = 0;
+ for (Index = 0; Index2 < Private->AprioriCount; Index++) {
+ while (Index2 < Private->AprioriCount) {
+ Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]);
+ if (Guid != NULL) {
+ break;
+ }
+ }
+ if (Guid == NULL) {
+ break;
+ }
+ PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID);
+ TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex];
+
+ //
+ // Since we have copied the file handle we can remove it from this list.
+ //
+ Private->CurrentFvFileHandles[PeimIndex] = NULL;
+ }
+
+ //
+ // Update valid Aprioricount
+ //
+ Private->AprioriCount = Index;
+
+ //
+ // Add in any PEIMs not in the Apriori file
+ //
+ for (;Index < PeimCount; Index++) {
+ for (Index2 = 0; Index2 < PeimCount; Index2++) {
+ if (Private->CurrentFvFileHandles[Index2] != NULL) {
+ TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2];
+ Private->CurrentFvFileHandles[Index2] = NULL;
+ break;
+ }
+ }
+ }
+ //
+ //Index the end of array contains re-range Pei moudle.
+ //
+ TempFileHandles[Index] = NULL;
+
+ //
+ // Private->CurrentFvFileHandles is currently in PEIM in the FV order.
+ // We need to update it to start with files in the A Priori list and
+ // then the remaining files in PEIM order.
+ //
+ CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
+ }
+ }
+ //
+ // Cache the current Fv File Handle. So that we don't have to scan the Fv again.
+ // Instead, we can retrieve the file handles within this Fv from cachable data.
+ //
+ Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE;
+ CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
+
+}
+
+//
+// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
+// This part of memory still need reserved on the very top of memory so that the DXE Core could
+// use these memory for data initialization. This macro should be sync with the same marco
+// defined in DXE Core.
+//
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
+/**
+ This function is to test if the memory range described in resource HOB is available or not.
+
+ This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
+ memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
+ available or not.
+
+ @param PrivateData Pointer to the private data passed in from caller
+ @param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB
+**/
+BOOLEAN
+PeiLoadFixAddressIsMemoryRangeAvailable (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ BOOLEAN IsAvailable;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ IsAvailable = TRUE;
+ if (PrivateData == NULL || ResourceHob == NULL) {
+ return FALSE;
+ }
+ //
+ // test if the memory range describe in the HOB is already allocated.
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a memory allocation HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ if(MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart &&
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength) {
+ IsAvailable = FALSE;
+ break;
+ }
+ }
+ }
+
+ return IsAvailable;
+
+}
+/**
+ Hook function for Loading Module at Fixed Address feature
+
+ This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
+ configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
+ feature is configured as Load Modules at Fixed Offset, the functino is to find the top address which is TOLM-TSEG in general.
+ And also the function will re-install PEI memory.
+
+ @param PrivateData Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiLoadFixAddressHook(
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PHYSICAL_ADDRESS TopLoadingAddress;
+ UINT64 PeiMemorySize;
+ UINT64 TotalReservedMemorySize;
+ UINT64 MemoryRangeEnd;
+ EFI_PHYSICAL_ADDRESS HighAddress;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;
+ EFI_PEI_HOB_POINTERS CurrentHob;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_HOB_POINTERS NextHob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ //
+ // Initialize Local Variables
+ //
+ CurrentResourceHob = NULL;
+ ResourceHob = NULL;
+ NextResourceHob = NULL;
+ HighAddress = 0;
+ TopLoadingAddress = 0;
+ MemoryRangeEnd = 0;
+ CurrentHob.Raw = PrivateData->HobList.Raw;
+ PeiMemorySize = PrivateData->PhysicalMemoryLength;
+ //
+ // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE
+ // then RuntimeCodePage range and Boot time code range.
+ //
+ TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber));
+ TotalReservedMemorySize+= EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)) ;
+ //
+ // PEI memory range lies below the top reserved memory
+ //
+ TotalReservedMemorySize += PeiMemorySize;
+
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
+ //
+ // Loop through the system memory typed hob to merge the adjacent memory range
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
+ //
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY ||
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS) {
+ continue;
+ }
+
+ for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
+ if (NextHob.Raw == Hob.Raw){
+ continue;
+ }
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ NextResourceHob = NextHob.ResourceDescriptor;
+ //
+ // test if range described in this NextResourceHob is system memory and have the same attribute.
+ // Note: Here is a assumption that system memory should always be healthy even without test.
+ //
+ if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){
+
+ //
+ // See if the memory range described in ResourceHob and NextResourceHob is adjacent
+ //
+ if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)||
+ (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&
+ ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {
+
+ MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
+
+ ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
+ ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
+
+
+ ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
+
+ ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
+ //
+ // Delete the NextResourceHob by marking it as unused.
+ //
+ GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ //
+ // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
+ // the allocated memory range
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a memory allocation HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ NextResourceHob = NextHob.ResourceDescriptor;
+ //
+ // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
+ //
+ if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) {
+ continue;
+ }
+ //
+ // If the range describe in memory allocation HOB belongs to the memroy range described by the resource hob
+ //
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart &&
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
+ //
+ // Build seperate resource hob for this allocated range
+ //
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ NextResourceHob->ResourceAttribute,
+ NextResourceHob->PhysicalStart,
+ (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
+ );
+ }
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ NextResourceHob->ResourceAttribute,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
+ (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
+ );
+ }
+ NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Try to find and validate the TOP address.
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
+ //
+ // The LMFA feature is enabled as load module at fixed absolute address.
+ //
+ TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64(PcdLoadModuleAtFixAddressEnable);
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
+ //
+ // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
+ //
+ if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
+ ASSERT (FALSE);
+ }
+ //
+ // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
+ //
+ // See if Top address specified by user is valid.
+ //
+ if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress &&
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress &&
+ PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ CurrentResourceHob = ResourceHob;
+ CurrentHob = Hob;
+ break;
+ }
+ }
+ }
+ }
+ if (CurrentResourceHob != NULL) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));
+ TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
+ } else {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
+ //
+ // Print the recomended Top address range.
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
+ //
+ // See if Top address specified by user is valid.
+ //
+ if (ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n",
+ (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
+ ));
+ }
+ }
+ }
+ }
+ //
+ // Assert here
+ //
+ ASSERT (FALSE);
+ return;
+ }
+ } else {
+ //
+ // The LMFA feature is enabled as load module at fixed offset relative to TOLM
+ // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
+ //
+ //
+ // Search for a tested memory region that is below MAX_ADDRESS
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&
+ ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ //
+ // See if this is the highest largest system memory region below MaxAddress
+ //
+ if (ResourceHob->PhysicalStart > HighAddress) {
+ CurrentResourceHob = ResourceHob;
+ CurrentHob = Hob;
+ HighAddress = CurrentResourceHob->PhysicalStart;
+ }
+ }
+ }
+ }
+ if (CurrentResourceHob == NULL) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
+ //
+ // Assert here
+ //
+ ASSERT (FALSE);
+ return;
+ } else {
+ TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ;
+ }
+ }
+
+ if (CurrentResourceHob != NULL) {
+ //
+ // rebuild resource HOB for PEI memmory and reserved memory
+ //
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_TESTED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ (TopLoadingAddress - TotalReservedMemorySize),
+ TotalReservedMemorySize
+ );
+ //
+ // rebuild resource for the remain memory if necessary
+ //
+ if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ CurrentResourceHob->PhysicalStart,
+ (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
+ );
+ }
+ if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ TopLoadingAddress,
+ (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress)
+ );
+ }
+ //
+ // Delete CurrentHob by marking it as unused since the the memory range described by is rebuilt.
+ //
+ GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
+ }
+
+ //
+ // Cache the top address for Loading Module at Fixed Address feature
+ //
+ PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));
+ //
+ // reinstall the PEI memory relative to TopLoadingAddress
+ //
+ PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;
+ PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
+}
+
+/**
+ This routine is invoked in switch stack as PeiCore Entry.
+
+ @param 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.
+ @param Private Pointer to old core data that is used to initialize the
+ core's data areas.
+**/
+VOID
+EFIAPI
+PeiCoreEntry (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ //
+ // Entry PEI Phase 2
+ //
+ PeiCore (SecCoreData, NULL, Private);
+}
+
+/**
+ Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
+
+ @param[in] 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.
+ @param[in] Private Pointer to the private data passed in from caller.
+
+**/
+VOID
+PeiCheckAndSwitchStack (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ VOID *LoadFixPeiCodeBegin;
+ EFI_STATUS Status;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ UINT64 NewStackSize;
+ EFI_PHYSICAL_ADDRESS TopOfOldStack;
+ EFI_PHYSICAL_ADDRESS TopOfNewStack;
+ UINTN StackOffset;
+ BOOLEAN StackOffsetPositive;
+ EFI_PHYSICAL_ADDRESS TemporaryRamBase;
+ UINTN TemporaryRamSize;
+ UINTN TemporaryStackSize;
+ VOID *TemporaryStackBase;
+ UINTN PeiTemporaryRamSize;
+ VOID *PeiTemporaryRamBase;
+ EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
+ EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
+ EFI_PHYSICAL_ADDRESS HoleMemBase;
+ UINTN HoleMemSize;
+ UINTN HeapTemporaryRamSize;
+ EFI_PHYSICAL_ADDRESS TempBase1;
+ UINTN TempSize1;
+ EFI_PHYSICAL_ADDRESS TempBase2;
+ UINTN TempSize2;
+ UINTN Index;
+
+ PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
+
+ if (Private->SwitchStackSignal) {
+ //
+ // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
+ // usage in temporary memory for debugging.
+ //
+ DEBUG_CODE_BEGIN ();
+ UINT32 *StackPointer;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ for (StackPointer = (UINT32*)SecCoreData->StackBase;
+ (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
+ && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
+ StackPointer ++) {
+ }
+
+ DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
+ DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
+ DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
+ DEBUG ((DEBUG_INFO, " temporary memory stack ever used: %d bytes.\n",
+ (UINT32)(SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
+ ));
+ DEBUG ((DEBUG_INFO, " temporary memory heap used for HobList: %d bytes.\n",
+ (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
+ ));
+ DEBUG ((DEBUG_INFO, " temporary memory heap occupied by memory pages: %d bytes.\n",
+ (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
+ ));
+ for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ DEBUG ((DEBUG_INFO, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
+ }
+ }
+ DEBUG_CODE_END ();
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ //
+ // Loading Module at Fixed Address is enabled
+ //
+ PeiLoadFixAddressHook (Private);
+
+ //
+ // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
+ //
+ LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
+ }
+
+ //
+ // Reserve the size of new stack at bottom of physical memory
+ //
+ // The size of new stack in permanent memory must be the same size
+ // or larger than the size of old stack in temporary memory.
+ // But if new stack is smaller than the size of old stack, we also reserve
+ // the size of old stack at bottom of permanent memory.
+ //
+ NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
+ NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
+ NewStackSize = MIN (PcdGet32(PcdPeiCoreMaxPeiStackSize), NewStackSize);
+ DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
+ ASSERT (NewStackSize >= SecCoreData->StackSize);
+
+ //
+ // Calculate stack offset and heap offset between temporary memory and new permement
+ // memory seperately.
+ //
+ TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
+ TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
+ if (TopOfNewStack >= TopOfOldStack) {
+ StackOffsetPositive = TRUE;
+ StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
+ } else {
+ StackOffsetPositive = FALSE;
+ StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
+ }
+ Private->StackOffsetPositive = StackOffsetPositive;
+ Private->StackOffset = StackOffset;
+
+ //
+ // Build Stack HOB that describes the permanent memory stack
+ //
+ DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
+ BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
+
+ //
+ // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
+ //
+ TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
+ TemporaryRamSize = SecCoreData->TemporaryRamSize;
+ TemporaryStackSize = SecCoreData->StackSize;
+ TemporaryStackBase = SecCoreData->StackBase;
+ PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
+ PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
+
+ //
+ // TemporaryRamSupportPpi is produced by platform's SEC
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiTemporaryRamSupportPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&TemporaryRamSupportPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Heap Offset
+ //
+ BaseOfNewHeap = TopOfNewStack;
+ if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
+ Private->HeapOffsetPositive = TRUE;
+ Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
+ } else {
+ Private->HeapOffsetPositive = FALSE;
+ Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
+ }
+
+ DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
+
+ //
+ // Calculate new HandOffTable and PrivateData address in permanent memory's stack
+ //
+ if (StackOffsetPositive) {
+ SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
+ Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
+ } else {
+ SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
+ Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
+ }
+
+ //
+ // Temporary Ram Support PPI is provided by platform, it will copy
+ // temporary memory to permanent memory and do stack switching.
+ // After invoking Temporary Ram Support PPI, the following code's
+ // stack is in permanent memory.
+ //
+ TemporaryRamSupportPpi->TemporaryRamMigration (
+ PeiServices,
+ TemporaryRamBase,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
+ TemporaryRamSize
+ );
+
+ //
+ // Migrate memory pages allocated in pre-memory phase.
+ // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
+ // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
+ //
+ MigrateMemoryPages (Private, TRUE);
+
+ //
+ // Entry PEI Phase 2
+ //
+ PeiCore (SecCoreData, NULL, Private);
+ } else {
+ //
+ // Migrate memory pages allocated in pre-memory phase.
+ //
+ MigrateMemoryPages (Private, FALSE);
+
+ //
+ // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
+ //
+ MigratePeiServicesTablePointer ();
+
+ //
+ // Heap Offset
+ //
+ BaseOfNewHeap = TopOfNewStack;
+ HoleMemBase = TopOfNewStack;
+ HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
+ if (HoleMemSize != 0) {
+ //
+ // Make sure HOB List start address is 8 byte alignment.
+ //
+ BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
+ }
+ if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
+ Private->HeapOffsetPositive = TRUE;
+ Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
+ } else {
+ Private->HeapOffsetPositive = FALSE;
+ Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
+ }
+
+ DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
+
+ //
+ // Migrate Heap
+ //
+ HeapTemporaryRamSize = (UINTN) (Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
+ ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
+ CopyMem ((UINT8 *) (UINTN) BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
+
+ //
+ // Migrate Stack
+ //
+ CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
+
+ //
+ // Copy Hole Range Data
+ //
+ if (HoleMemSize != 0) {
+ //
+ // Prepare Hole
+ //
+ if (PeiTemporaryRamBase < TemporaryStackBase) {
+ TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
+ TempSize1 = PeiTemporaryRamSize;
+ TempBase2 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
+ TempSize2 = TemporaryStackSize;
+ } else {
+ TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
+ TempSize1 = TemporaryStackSize;
+ TempBase2 =(EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
+ TempSize2 = PeiTemporaryRamSize;
+ }
+ if (TemporaryRamBase < TempBase1) {
+ Private->HoleData[0].Base = TemporaryRamBase;
+ Private->HoleData[0].Size = (UINTN) (TempBase1 - TemporaryRamBase);
+ }
+ if (TempBase1 + TempSize1 < TempBase2) {
+ Private->HoleData[1].Base = TempBase1 + TempSize1;
+ Private->HoleData[1].Size = (UINTN) (TempBase2 - TempBase1 - TempSize1);
+ }
+ if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
+ Private->HoleData[2].Base = TempBase2 + TempSize2;
+ Private->HoleData[2].Size = (UINTN) (TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
+ }
+
+ //
+ // Copy Hole Range data.
+ //
+ for (Index = 0; Index < HOLE_MAX_NUMBER; Index ++) {
+ if (Private->HoleData[Index].Size > 0) {
+ if (HoleMemBase > Private->HoleData[Index].Base) {
+ Private->HoleData[Index].OffsetPositive = TRUE;
+ Private->HoleData[Index].Offset = (UINTN) (HoleMemBase - Private->HoleData[Index].Base);
+ } else {
+ Private->HoleData[Index].OffsetPositive = FALSE;
+ Private->HoleData[Index].Offset = (UINTN) (Private->HoleData[Index].Base - HoleMemBase);
+ }
+ CopyMem ((VOID *) (UINTN) HoleMemBase, (VOID *) (UINTN) Private->HoleData[Index].Base, Private->HoleData[Index].Size);
+ HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
+ }
+ }
+ }
+
+ //
+ // Switch new stack
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
+ (VOID *) SecCoreData,
+ (VOID *) Private,
+ (VOID *) (UINTN) TopOfNewStack
+ );
+ }
+
+ //
+ // Code should not come here
+ //
+ ASSERT (FALSE);
+ }
+}
+
+/**
+ Conduct PEIM dispatch.
+
+ @param 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.
+ @param Private Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiDispatcher (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index1;
+ UINT32 Index2;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_PEI_FILE_HANDLE PeimFileHandle;
+ UINTN FvCount;
+ UINTN PeimCount;
+ UINT32 AuthenticationState;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
+ UINTN SaveCurrentPeimCount;
+ UINTN SaveCurrentFvCount;
+ EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
+ EFI_FV_FILE_INFO FvFileInfo;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
+ PeimEntryPoint = NULL;
+ PeimFileHandle = NULL;
+ EntryPoint = 0;
+
+ if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
+ //
+ // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
+ // update the modules' status from PEIM_STATE_REGISITER_FOR_SHADOW to PEIM_STATE_DONE.
+ //
+ SaveCurrentPeimCount = Private->CurrentPeimCount;
+ SaveCurrentFvCount = Private->CurrentPeimFvCount;
+ SaveCurrentFileHandle = Private->CurrentFileHandle;
+
+ for (Index1 = 0; Index1 <= SaveCurrentFvCount; Index1++) {
+ for (Index2 = 0; (Index2 < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) {
+ if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) {
+ PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
+ Private->CurrentFileHandle = PeimFileHandle;
+ Private->CurrentPeimFvCount = Index1;
+ Private->CurrentPeimCount = Index2;
+ Status = PeiLoadImage (
+ (CONST EFI_PEI_SERVICES **) &Private->Ps,
+ PeimFileHandle,
+ PEIM_STATE_REGISITER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
+ //
+ Private->Fv[Index1].PeimState[Index2]++;
+ //
+ // Call the PEIM entry point
+ //
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+
+ PERF_START (PeimFileHandle, "PEIM", NULL, 0);
+ PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
+ PERF_END (PeimFileHandle, "PEIM", NULL, 0);
+ }
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessNotifyList (Private);
+ }
+ }
+ }
+ Private->CurrentFileHandle = SaveCurrentFileHandle;
+ Private->CurrentPeimFvCount = SaveCurrentFvCount;
+ Private->CurrentPeimCount = SaveCurrentPeimCount;
+ }
+
+ //
+ // This is the main dispatch loop. It will search known FVs for PEIMs and
+ // attempt to dispatch them. If any PEIM gets dispatched through a single
+ // pass of the dispatcher, it will start over from the Bfv again to see
+ // if any new PEIMs dependencies got satisfied. With a well ordered
+ // FV where PEIMs are found in the order their dependencies are also
+ // satisfied, this dipatcher should run only once.
+ //
+ do {
+ //
+ // In case that reenter PeiCore happens, the last pass record is still available.
+ //
+ if (!Private->PeimDispatcherReenter) {
+ Private->PeimNeedingDispatch = FALSE;
+ Private->PeimDispatchOnThisPass = FALSE;
+ } else {
+ Private->PeimDispatcherReenter = FALSE;
+ }
+
+ for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
+ CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
+ ASSERT (CoreFvHandle != NULL);
+
+ //
+ // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
+ //
+ if (CoreFvHandle->FvPpi == NULL) {
+ continue;
+ }
+
+ Private->CurrentPeimFvCount = FvCount;
+
+ if (Private->CurrentPeimCount == 0) {
+ //
+ // When going through each FV, at first, search Apriori file to
+ // reorder all PEIMs to ensure the PEIMs in Apriori file to get
+ // dispatch at first.
+ //
+ DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
+ }
+
+ //
+ // Start to dispatch all modules within the current Fv.
+ //
+ for (PeimCount = Private->CurrentPeimCount;
+ (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL);
+ PeimCount++) {
+ Private->CurrentPeimCount = PeimCount;
+ PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
+
+ if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
+ if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
+ Private->PeimNeedingDispatch = TRUE;
+ } else {
+ Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
+ ASSERT_EFI_ERROR (Status);
+ if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // For Fv type file, Produce new FvInfo PPI and FV hob
+ //
+ Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
+ if (Status == EFI_SUCCESS) {
+ //
+ // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+ Private->PeimDispatchOnThisPass = TRUE;
+ } else {
+ //
+ // The related GuidedSectionExtraction/Decompress PPI for the
+ // encapsulated FV image section may be installed in the rest
+ // of this do-while loop, so need to make another pass.
+ //
+ Private->PeimNeedingDispatch = TRUE;
+ }
+ } else {
+ //
+ // For PEIM driver, Load its entry point
+ //
+ Status = PeiLoadImage (
+ PeiServices,
+ PeimFileHandle,
+ PEIM_STATE_NOT_DISPATCHED,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // The PEIM has its dependencies satisfied, and its entry point
+ // has been found, so invoke it.
+ //
+ PERF_START (PeimFileHandle, "PEIM", NULL, 0);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
+ (VOID *)(&PeimFileHandle),
+ sizeof (PeimFileHandle)
+ );
+
+ Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
+ if (Status != EFI_SECURITY_VIOLATION) {
+ //
+ // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+ //
+ // Call the PEIM entry point for PEIM driver
+ //
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+ PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
+ Private->PeimDispatchOnThisPass = TRUE;
+ } else {
+ //
+ // The related GuidedSectionExtraction PPI for the
+ // signed PEIM image section may be installed in the rest
+ // of this do-while loop, so need to make another pass.
+ //
+ Private->PeimNeedingDispatch = TRUE;
+ }
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
+ (VOID *)(&PeimFileHandle),
+ sizeof (PeimFileHandle)
+ );
+ PERF_END (PeimFileHandle, "PEIM", NULL, 0);
+
+ }
+ }
+
+ PeiCheckAndSwitchStack (SecCoreData, Private);
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessNotifyList (Private);
+
+ //
+ // Recheck SwitchStackSignal after ProcessNotifyList()
+ // in case PeiInstallPeiMemory() is done in a callback with
+ // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
+ //
+ PeiCheckAndSwitchStack (SecCoreData, Private);
+
+ if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) && \
+ (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
+ //
+ // If memory is available we shadow images by default for performance reasons.
+ // We call the entry point a 2nd time so the module knows it's shadowed.
+ //
+ //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
+ if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot)) {
+ //
+ // Load PEIM into Memory for Register for shadow PEIM.
+ //
+ Status = PeiLoadImage (
+ PeiServices,
+ PeimFileHandle,
+ PEIM_STATE_REGISITER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+ }
+ }
+ ASSERT (PeimEntryPoint != NULL);
+ PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
+ //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
+
+ //
+ // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessNotifyList (Private);
+ }
+ }
+ }
+ }
+
+ //
+ // We set to NULL here to optimize the 2nd entry to this routine after
+ // memory is found. This reprevents rescanning of the FV. We set to
+ // NULL here so we start at the begining of the next FV
+ //
+ Private->CurrentFileHandle = NULL;
+ Private->CurrentPeimCount = 0;
+ //
+ // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL
+ //
+ SetMem (Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv), 0);
+ }
+
+ //
+ // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go
+ // through all the FV.
+ //
+ Private->CurrentPeimFvCount = 0;
+
+ //
+ // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
+ // dispatched. So we need to make another pass
+ //
+ // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
+ // pass. If we did not dispatch a PEIM/FV there is no point in trying again
+ // as it will fail the next time too (nothing has changed).
+ //
+ } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
+
+}
+
+/**
+ Initialize the Dispatcher's data members
+
+ @param PrivateData PeiCore's private data structure
+ @param OldCoreData Old data from SecCore
+ NULL if being run in non-permament memory mode.
+ @param 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.
+
+ @return None.
+
+**/
+VOID
+InitializeDispatcherData (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ PrivateData->PeimDispatcherReenter = FALSE;
+ PeiInitializeFv (PrivateData, SecCoreData);
+ } else {
+ PeiReinitializeFv (PrivateData);
+ }
+
+ return;
+}
+
+/**
+ This routine parses the Dependency Expression, if available, and
+ decides if the module can be executed.
+
+
+ @param Private PeiCore's private data structure
+ @param FileHandle PEIM's file handle
+ @param PeimCount Peim count in all dispatched PEIMs.
+
+ @retval TRUE Can be dispatched
+ @retval FALSE Cannot be dispatched
+
+**/
+BOOLEAN
+DepexSatisfied (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN PeimCount
+ )
+{
+ EFI_STATUS Status;
+ VOID *DepexData;
+ EFI_FV_FILE_INFO FileInfo;
+
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
+ }
+
+ if (PeimCount < Private->AprioriCount) {
+ //
+ // If its in the A priori file then we set Depex to TRUE
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ return TRUE;
+ }
+
+ //
+ // Depex section not in the encapsulated section.
+ //
+ Status = PeiServicesFfsFindSectionData (
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID **)&DepexData
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If there is no DEPEX, assume the module can be executed
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n"));
+ return TRUE;
+ }
+
+ //
+ // Evaluate a given DEPEX
+ //
+ return PeimDispatchReadiness (&Private->Ps, DepexData);
+}
+
+/**
+ This routine enable a PEIM to register itself to shadow when PEI Foundation
+ discovery permanent memory.
+
+ @param FileHandle File handle of a PEIM.
+
+ @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
+ @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
+ @retval EFI_SUCCESS Successfully to register itself.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterForShadow (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ PEI_CORE_INSTANCE *Private;
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ if (Private->CurrentFileHandle != FileHandle) {
+ //
+ // The FileHandle must be for the current PEIM
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) {
+ //
+ // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISITER_FOR_SHADOW;
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c
new file mode 100644
index 0000000000..8009546acd
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c
@@ -0,0 +1,2438 @@
+/** @file
+ Pei Core Firmware File System service routines.
+
+Copyright (c) 2015 HP Development Company, L.P.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVol.h"
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ }
+};
+
+PEI_FW_VOL_INSTANCE mPeiFfs2FwVol = {
+ PEI_FW_VOL_SIGNATURE,
+ FALSE,
+ {
+ PeiFfsFvPpiProcessVolume,
+ PeiFfsFvPpiFindFileByType,
+ PeiFfsFvPpiFindFileByName,
+ PeiFfsFvPpiGetFileInfo,
+ PeiFfsFvPpiGetVolumeInfo,
+ PeiFfsFvPpiFindSectionByType,
+ PeiFfsFvPpiGetFileInfo2,
+ PeiFfsFvPpiFindSectionByType2,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
+ }
+};
+
+PEI_FW_VOL_INSTANCE mPeiFfs3FwVol = {
+ PEI_FW_VOL_SIGNATURE,
+ TRUE,
+ {
+ PeiFfsFvPpiProcessVolume,
+ PeiFfsFvPpiFindFileByType,
+ PeiFfsFvPpiFindFileByName,
+ PeiFfsFvPpiGetFileInfo,
+ PeiFfsFvPpiGetVolumeInfo,
+ PeiFfsFvPpiFindSectionByType,
+ PeiFfsFvPpiGetFileInfo2,
+ PeiFfsFvPpiFindSectionByType2,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
+ }
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiFfs2FvPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiFirmwareFileSystem2Guid,
+ &mPeiFfs2FwVol.Fv
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiFfs3FvPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiFirmwareFileSystem3Guid,
+ &mPeiFfs3FwVol.Fv
+};
+
+/**
+Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
+(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
+1 0 0 0
+16 1 0 4
+128 2 0 7
+512 3 0 9
+1 KB 4 0 10
+4 KB 5 0 12
+32 KB 6 0 15
+64 KB 7 0 16
+128 KB 0 1 17
+256 KB 1 1 18
+512 KB 2 1 19
+1 MB 3 1 20
+2 MB 4 1 21
+4 MB 5 1 22
+8 MB 6 1 23
+16 MB 7 1 24
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};
+
+/**
+ Convert the FFS File Attributes to FV File Attributes
+
+ @param FfsAttributes The attributes of UINT8 type.
+
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES
+
+**/
+EFI_FV_FILE_ATTRIBUTES
+FfsAttributes2FvFileAttributes (
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINT8 DataAlignment;
+ EFI_FV_FILE_ATTRIBUTES FileAttribute;
+
+ DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
+ ASSERT (DataAlignment < 8);
+
+ if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];
+ } else {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
+ }
+
+ if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
+ FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
+ }
+
+ return FileAttribute;
+}
+
+/**
+ Returns the file state set by the highest zero bit in the State field
+
+ @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
+ in the Attributes field.
+ @param FfsHeader Pointer to FFS File Header.
+
+ @retval EFI_FFS_FILE_STATE File state is set by the highest none zero bit
+ in the header State field.
+**/
+EFI_FFS_FILE_STATE
+GetFileState(
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_STATE HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ //
+ // Get file state set by its highest none zero bit.
+ //
+ HighestBit = 0x80;
+ while (HighestBit != 0 && (HighestBit & FileState) == 0) {
+ HighestBit >>= 1;
+ }
+
+ return HighestBit;
+}
+
+/**
+ Calculates the checksum of the header of a file.
+
+ @param FileHeader Pointer to FFS File Header.
+
+ @return Checksum of the header.
+ Zero means the header is good.
+ Non-zero means the header is bad.
+**/
+UINT8
+CalculateHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FileHeader
+ )
+{
+ EFI_FFS_FILE_HEADER2 TestFileHeader;
+
+ if (IS_FFS_FILE2 (FileHeader)) {
+ CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ //
+ // Ingore State and File field in FFS header.
+ //
+ TestFileHeader.State = 0;
+ TestFileHeader.IntegrityCheck.Checksum.File = 0;
+
+ return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER));
+ //
+ // Ingore State and File field in FFS header.
+ //
+ TestFileHeader.State = 0;
+ TestFileHeader.IntegrityCheck.Checksum.File = 0;
+
+ return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER));
+ }
+}
+
+/**
+ Find FV handler according to FileHandle in that FV.
+
+ @param FileHandle Handle of file image
+
+ @return Pointer to instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE*
+FileHandleToVolume (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ UINTN Index;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BestIndex;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+ BestIndex = PrivateData->FvCount;
+
+ //
+ // Find the best matched FV image that includes this FileHandle.
+ // FV may include the child FV, and they are in the same continuous space.
+ // If FileHandle is from the child FV, the updated logic can find its matched FV.
+ //
+ for (Index = 0; Index < PrivateData->FvCount; Index++) {
+ FwVolHeader = PrivateData->Fv[Index].FvHeader;
+ if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
+ ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
+ if (BestIndex == PrivateData->FvCount) {
+ BestIndex = Index;
+ } else {
+ if ((UINT64) (UINTN) PrivateData->Fv[BestIndex].FvHeader < (UINT64) (UINTN) FwVolHeader) {
+ BestIndex = Index;
+ }
+ }
+ }
+ }
+
+ if (BestIndex < PrivateData->FvCount) {
+ return &PrivateData->Fv[BestIndex];
+ }
+
+ return NULL;
+}
+
+/**
+ Given the input file pointer, search for the first matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+ If SearchType is EFI_FV_FILETYPE_ALL, the first FFS file will return without check its file type.
+ If SearchType is PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
+ the first PEIM, or COMBINED PEIM or FV file type FFS file will return.
+
+ @param FvHandle Pointer to the FV header of the volume to search
+ @param FileName File name
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FileHandle This parameter must point to a valid FFS volume.
+ @param AprioriFile Pointer to AprioriFile image in this FV if has
+
+ @return EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+FindFileEx (
+ IN CONST EFI_PEI_FV_HANDLE FvHandle,
+ IN CONST EFI_GUID *FileName, OPTIONAL
+ IN EFI_FV_FILETYPE SearchType,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *AprioriFile OPTIONAL
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FFS_FILE_HEADER **FileHeader;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+ UINT32 FileOffset;
+ UINT64 FvLength;
+ UINT8 ErasePolarity;
+ UINT8 FileState;
+ UINT8 DataCheckSum;
+ BOOLEAN IsFfs3Fv;
+
+ //
+ // Convert the handle of FV to FV header for memory-mapped firmware volume
+ //
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvHandle;
+ FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
+
+ IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+
+ FvLength = FwVolHeader->FvLength;
+ if ((FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // If FileHeader is not specified (NULL) or FileName is not NULL,
+ // start with the first file in the firmware volume. Otherwise,
+ // start from the FileHeader.
+ //
+ if ((*FileHeader == NULL) || (FileName != NULL)) {
+ if (FwVolHeader->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->ExtHeaderOffset);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsFileHeader, 8);
+ } else {
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
+ }
+ } else {
+ if (IS_FFS_FILE2 (*FileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &(*FileHeader)->Name));
+ }
+ FileLength = FFS_FILE2_SIZE (*FileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ } else {
+ FileLength = FFS_FILE_SIZE (*FileHeader);
+ }
+ //
+ // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
+ }
+
+ FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
+ ASSERT (FileOffset <= 0xFFFFFFFF);
+
+ while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, FfsFileHeader);
+ switch (FileState) {
+
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ case EFI_FILE_HEADER_INVALID:
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ }
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER2);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+ break;
+
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
+ ASSERT (FALSE);
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ FileLength = FFS_FILE2_SIZE (FfsFileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ break;
+ }
+ } else {
+ FileLength = FFS_FILE_SIZE (FfsFileHeader);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ }
+
+ DataCheckSum = FFS_FIXED_CHECKSUM;
+ if ((FfsFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FileLength - sizeof(EFI_FFS_FILE_HEADER2));
+ } else {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER), FileLength - sizeof(EFI_FFS_FILE_HEADER));
+ }
+ }
+ if (FfsFileHeader->IntegrityCheck.Checksum.File != DataCheckSum) {
+ ASSERT (FALSE);
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (FileName != NULL) {
+ if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+ } else if (SearchType == PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE) {
+ if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) ||
+ (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) ||
+ (FfsFileHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {
+
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ } else if (AprioriFile != NULL) {
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FREEFORM) {
+ if (CompareGuid (&FfsFileHeader->Name, &gPeiAprioriFileNameGuid)) {
+ *AprioriFile = FfsFileHeader;
+ }
+ }
+ }
+ } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
+ (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ case EFI_FILE_DELETED:
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ }
+ FileLength = FFS_FILE2_SIZE (FfsFileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ } else {
+ FileLength = FFS_FILE_SIZE (FfsFileHeader);
+ }
+ FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ default:
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize PeiCore Fv List.
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
+**/
+VOID
+PeiInitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_PEI_FV_HANDLE FvHandle;
+ EFI_FIRMWARE_VOLUME_HEADER *BfvHeader;
+
+ //
+ // Install FV_PPI for FFS2 file system.
+ //
+ PeiServicesInstallPpi (&mPeiFfs2FvPpiList);
+
+ //
+ // Install FV_PPI for FFS3 file system.
+ //
+ PeiServicesInstallPpi (&mPeiFfs3FvPpiList);
+
+ BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+
+ //
+ // The FV_PPI in BFV's format should be installed.
+ //
+ Status = PeiServicesLocatePpi (
+ &BfvHeader->FileSystemGuid,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get handle of BFV
+ //
+ FvPpi->ProcessVolume (
+ FvPpi,
+ SecCoreData->BootFirmwareVolumeBase,
+ (UINTN)BfvHeader->FvLength,
+ &FvHandle
+ );
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) PrivateData->FvCount,
+ (VOID *) BfvHeader,
+ (UINT32) BfvHeader->FvLength,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
+ // additional Fvs to PeiCore.
+ //
+ Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
+ ASSERT_EFI_ERROR (Status);
+
+}
+
+/**
+ Process Firmware Volum Information once FvInfoPPI or FvInfo2PPI install.
+ The FV Info will be registered into PeiCore private data structure.
+ And search the inside FV image, if found, the new FV INFO(2) PPI will be installed.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
+ @return if not EFI_SUCESS, fail to verify FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolmeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI FvInfo2Ppi;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE FvHandle;
+ UINTN FvIndex;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *DepexData;
+ BOOLEAN IsFvInfo2;
+ UINTN CurFvCount;
+
+ Status = EFI_SUCCESS;
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiFirmwareVolumeInfo2PpiGuid)) {
+ //
+ // It is FvInfo2PPI.
+ //
+ CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI));
+ IsFvInfo2 = TRUE;
+ } else {
+ //
+ // It is FvInfoPPI.
+ //
+ CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI));
+ FvInfo2Ppi.AuthenticationStatus = 0;
+ IsFvInfo2 = FALSE;
+ }
+
+ if (CompareGuid (&FvInfo2Ppi.FvFormat, &gEfiFirmwareFileSystem2Guid)) {
+ //
+ // gEfiFirmwareFileSystem2Guid is specified for FvFormat, then here to check the
+ // FileSystemGuid pointed by FvInfo against gEfiFirmwareFileSystem2Guid to make sure
+ // FvInfo has the firmware file system 2 format.
+ //
+ // If the ASSERT really appears, FvFormat needs to be specified correctly, for example,
+ // gEfiFirmwareFileSystem3Guid can be used for firmware file system 3 format, or
+ // ((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo)->FileSystemGuid can be just used for both
+ // firmware file system 2 and 3 format.
+ //
+ ASSERT (CompareGuid (&(((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo2Ppi.FvInfo)->FileSystemGuid), &gEfiFirmwareFileSystem2Guid));
+ }
+
+ //
+ // Locate the corresponding FV_PPI according to founded FV's format guid
+ //
+ Status = PeiServicesLocatePpi (
+ &FvInfo2Ppi.FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Process new found FV and get FV handle.
+ //
+ Status = FvPpi->ProcessVolume (FvPpi, FvInfo2Ppi.FvInfo, FvInfo2Ppi.FvInfoSize, &FvHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to process new found FV, FV may be corrupted!\n"));
+ return Status;
+ }
+
+ //
+ // Check whether the FV has already been processed.
+ //
+ for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
+ if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
+ if (IsFvInfo2 && (FvInfo2Ppi.AuthenticationStatus != PrivateData->Fv[FvIndex].AuthenticationStatus)) {
+ PrivateData->Fv[FvIndex].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
+ DEBUG ((EFI_D_INFO, "Update AuthenticationStatus of the %dth FV to 0x%x!\n", FvIndex, FvInfo2Ppi.AuthenticationStatus));
+ }
+ DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo2Ppi.FvInfo));
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (PrivateData->FvCount >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, PcdGet32 (PcdPeiCoreMaxFvSupported)));
+ DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
+ ASSERT (FALSE);
+ }
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo2Ppi.FvInfo;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
+ CurFvCount = PrivateData->FvCount;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) CurFvCount,
+ (VOID *) FvInfo2Ppi.FvInfo,
+ FvInfo2Ppi.FvInfoSize,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+ FileHandle = NULL;
+ do {
+ Status = FvPpi->FindFileByType (
+ FvPpi,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+ FvHandle,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FvPpi->FindSectionByType (
+ FvPpi,
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID**)&DepexData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!PeimDispatchReadiness (PeiServices, DepexData)) {
+ //
+ // Dependency is not satisfied.
+ //
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
+ }
+ } while (FileHandle != NULL);
+ } else {
+ DEBUG ((EFI_D_ERROR, "Fail to process FV %p because no corresponding EFI_FIRMWARE_VOLUME_PPI is found!\n", FvInfo2Ppi.FvInfo));
+
+ AddUnknownFormatFvInfo (PrivateData, &FvInfo2Ppi);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verify the Guided Section GUID by checking if there is the Guided Section GUID HOB recorded the GUID itself.
+
+ @param GuidedSectionGuid The Guided Section GUID.
+ @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Ppi
+ for the Guided Section.
+
+ @return TRUE The GuidedSectionGuid could be identified, and the pointer to
+ the Guided Section Extraction Ppi will be returned to *GuidedSectionExtraction.
+ @return FALSE The GuidedSectionGuid could not be identified, or
+ the Guided Section Extraction Ppi has not been installed yet.
+
+**/
+BOOLEAN
+VerifyGuidedSectionGuid (
+ IN EFI_GUID *GuidedSectionGuid,
+ OUT EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI **GuidedSectionExtraction
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_GUID *GuidRecorded;
+ VOID *Interface;
+ EFI_STATUS Status;
+
+ //
+ // Check if there is the Guided Section GUID HOB recorded the GUID itself.
+ //
+ Hob.Raw = GetFirstGuidHob (GuidedSectionGuid);
+ if (Hob.Raw != NULL) {
+ GuidRecorded = (EFI_GUID *) GET_GUID_HOB_DATA (Hob);
+ if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
+ //
+ // Found the recorded GuidedSectionGuid.
+ //
+ Status = PeiServicesLocatePpi (GuidedSectionGuid, 0, NULL, (VOID **) &Interface);
+ if (!EFI_ERROR (Status) && Interface != NULL) {
+ //
+ // Found the supported Guided Section Extraction Ppi for the Guided Section.
+ //
+ *GuidedSectionExtraction = (EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *) Interface;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Go through the file to search SectionType section.
+ Search within encapsulation sections (compression and GUIDed) recursively,
+ until the match section is found.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType Filter to find only section of this type.
+ @param SectionInstance Pointer to the filter to find the specific instance of section.
+ @param Section From where to search.
+ @param SectionSize The file size to search.
+ @param OutputBuffer A pointer to the discovered section, if successful.
+ NULL if section not found
+ @param AuthenticationStatus Updated upon return to point to the authentication status for this section.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @return EFI_NOT_FOUND The match section is not found.
+ @return EFI_SUCCESS The match section is found.
+
+**/
+EFI_STATUS
+ProcessSection (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_COMMON_SECTION_HEADER *Section,
+ IN UINTN SectionSize,
+ OUT VOID **OutputBuffer,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
+ EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
+ VOID *PpiOutput;
+ UINTN PpiOutputSize;
+ UINTN Index;
+ UINT32 Authentication;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_GUID *SectionDefinitionGuid;
+ BOOLEAN SectionCached;
+ VOID *TempOutputBuffer;
+ UINT32 TempAuthenticationStatus;
+ UINT16 GuidedSectionAttributes;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ *OutputBuffer = NULL;
+ ParsedLength = 0;
+ Index = 0;
+ Status = EFI_NOT_FOUND;
+ PpiOutput = NULL;
+ PpiOutputSize = 0;
+ while (ParsedLength < SectionSize) {
+
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
+ SectionLength = SECTION2_SIZE (Section);
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
+ continue;
+ }
+ }
+
+ if (Section->Type == SectionType) {
+ //
+ // The type matches, so check the instance count to see if it's the one we want.
+ //
+ (*SectionInstance)--;
+ if (*SectionInstance == 0) {
+ //
+ // Got it!
+ //
+ if (IS_SECTION2 (Section)) {
+ *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
+ } else {
+ *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (IS_SECTION2 (Section)) {
+ SectionLength = SECTION2_SIZE (Section);
+ } else {
+ SectionLength = SECTION_SIZE (Section);
+ }
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
+ continue;
+ }
+ } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
+ //
+ // Check the encapsulated section is extracted into the cache data.
+ //
+ SectionCached = FALSE;
+ for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
+ if (Section == PrivateData->CacheSection.Section[Index]) {
+ SectionCached = TRUE;
+ PpiOutput = PrivateData->CacheSection.SectionData[Index];
+ PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
+ Authentication = PrivateData->CacheSection.AuthenticationStatus[Index];
+ //
+ // Search section directly from the cache data.
+ //
+ TempAuthenticationStatus = 0;
+ Status = ProcessSection (
+ PeiServices,
+ SectionType,
+ SectionInstance,
+ PpiOutput,
+ PpiOutputSize,
+ &TempOutputBuffer,
+ &TempAuthenticationStatus,
+ IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ *OutputBuffer = TempOutputBuffer;
+ *AuthenticationStatus = TempAuthenticationStatus | Authentication;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // If SectionCached is TRUE, the section data has been cached and scanned.
+ //
+ if (!SectionCached) {
+ Status = EFI_NOT_FOUND;
+ Authentication = 0;
+ if (Section->Type == EFI_SECTION_GUID_DEFINED) {
+ if (IS_SECTION2 (Section)) {
+ SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)Section)->Attributes;
+ } else {
+ SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION *)Section)->Attributes;
+ }
+ if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
+ Status = GuidSectionPpi->ExtractSection (
+ GuidSectionPpi,
+ Section,
+ &PpiOutput,
+ &PpiOutputSize,
+ &Authentication
+ );
+ } else if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ //
+ // Figure out the proper authentication status for GUIDED section without processing required
+ //
+ Status = EFI_SUCCESS;
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ Authentication |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
+ }
+ if (IS_SECTION2 (Section)) {
+ PpiOutputSize = SECTION2_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
+ PpiOutput = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
+ } else {
+ PpiOutputSize = SECTION_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
+ PpiOutput = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
+ }
+ }
+ } else if (Section->Type == EFI_SECTION_COMPRESSION) {
+ Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
+ if (!EFI_ERROR (Status)) {
+ Status = DecompressPpi->Decompress (
+ DecompressPpi,
+ (CONST EFI_COMPRESSION_SECTION*) Section,
+ &PpiOutput,
+ &PpiOutputSize
+ );
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if ((Authentication & EFI_AUTH_STATUS_NOT_TESTED) == 0) {
+ //
+ // Update cache section data.
+ //
+ if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
+ PrivateData->CacheSection.AllSectionCount ++;
+ }
+ PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
+ PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
+ PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
+ PrivateData->CacheSection.AuthenticationStatus [PrivateData->CacheSection.SectionIndex] = Authentication;
+ PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
+ }
+
+ TempAuthenticationStatus = 0;
+ Status = ProcessSection (
+ PeiServices,
+ SectionType,
+ SectionInstance,
+ PpiOutput,
+ PpiOutputSize,
+ &TempOutputBuffer,
+ &TempAuthenticationStatus,
+ IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ *OutputBuffer = TempOutputBuffer;
+ *AuthenticationStatus = TempAuthenticationStatus | Authentication;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (IS_SECTION2 (Section)) {
+ SectionLength = SECTION2_SIZE (Section);
+ } else {
+ SectionLength = SECTION_SIZE (Section);
+ }
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param SectionType Filter to find only sections of this type.
+ @param FileHandle Pointer to the current file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ NULL if section not found
+
+ @retval EFI_NOT_FOUND The section was not found.
+ @retval EFI_SUCCESS The section was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindSectionByType (CoreFvHandle->FvPpi, SectionType, FileHandle, SectionData);
+}
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType The value of the section type to find.
+ @param SectionInstance Section instance to find.
+ @param FileHandle Handle of the firmware file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ @param AuthenticationStatus A pointer to the authentication status for this section.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData3 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
+ }
+ //
+ // The old FvPpi doesn't support to find section by section instance
+ // and return authentication status, so return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Searches for the next matching file in the firmware volume.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FvHandle Handle of firmware volume in which to search.
+ @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
+ at the beginning of the firmware volume. On exit, points the file handle of the next file
+ in the volume or NULL if there are no more files.
+
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+ @retval EFI_SUCCESS The file was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextFile (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FvHandleToCoreHandle (FvHandle);
+
+ //
+ // To make backward compatiblity, if can not find corresponding the handle of FV
+ // then treat FV as build-in FFS2/FFS3 format and memory mapped FV that FV handle is pointed
+ // to the address of first byte of FV.
+ //
+ if ((CoreFvHandle == NULL) && FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
+ return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
+ }
+
+ if ((CoreFvHandle == NULL) || CoreFvHandle->FvPpi == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindFileByType (CoreFvHandle->FvPpi, SearchType, FvHandle, FileHandle);
+}
+
+
+/**
+ Search the firmware volumes by index
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
+ Volume (BFV).
+ @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
+ @retval EFI_NOT_FOUND The volume was not found.
+ @retval EFI_SUCCESS The volume was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextVolume (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ )
+{
+ PEI_CORE_INSTANCE *Private;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if (VolumeHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ CoreFvHandle = FindNextCoreFvHandle (Private, Instance);
+ if (CoreFvHandle == NULL) {
+ *VolumeHandle = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ *VolumeHandle = CoreFvHandle->FvHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find a file within a volume by its name.
+
+ @param FileName A pointer to the name of the file to find within the firmware volume.
+ @param VolumeHandle The firmware volume to search
+ @param FileHandle Upon exit, points to the found file's handle
+ or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreFvHandle = FvHandleToCoreHandle (VolumeHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindFileByName (CoreFvHandle->FvPpi, FileName, &VolumeHandle, FileHandle);
+}
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, FileHandle, FileInfo);
+}
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo2 (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ return CoreFvHandle->FvPpi->GetFileInfo2 (CoreFvHandle->FvPpi, FileHandle, FileInfo);
+ }
+ //
+ // The old FvPpi doesn't support to return file info with authentication status,
+ // so return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Returns information about the specified volume.
+
+ This function returns information about a specific firmware
+ volume, including its name, type, attributes, starting address
+ and size.
+
+ @param VolumeHandle Handle of the volume.
+ @param VolumeInfo Upon exit, points to the volume's information.
+
+ @retval EFI_SUCCESS Volume information returned.
+ @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
+ @retval EFI_INVALID_PARAMETER If VolumeHandle is NULL.
+ @retval EFI_SUCCESS Information successfully returned.
+ @retval EFI_INVALID_PARAMETER The volume designated by the VolumeHandle is not available.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreHandle;
+
+ if ((VolumeInfo == NULL) || (VolumeHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreHandle = FvHandleToCoreHandle (VolumeHandle);
+
+ if ((CoreHandle == NULL) || (CoreHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreHandle->FvPpi->GetVolumeInfo (CoreHandle->FvPpi, VolumeHandle, VolumeInfo);
+}
+
+/**
+ Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
+
+ @param[in] FvHeader Pointer to FV header.
+ @param[out] FvUsedSize Pointer to FV used size returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+ @param[out] EraseByte Pointer to erase byte returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+
+ @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
+ FV used size and erase byte are returned.
+ @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
+
+**/
+BOOLEAN
+GetFvUsedSize (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ OUT UINT32 *FvUsedSize,
+ OUT UINT8 *EraseByte
+ )
+{
+ UINT16 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
+
+ ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
+ if (ExtHeaderOffset != 0) {
+ ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + ExtHeaderOffset);
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *) (ExtHeader + 1);
+ while ((UINTN) ExtEntryList < ((UINTN) ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
+ if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
+ //
+ // USED_SIZE FV_EXT_TYPE entry is found.
+ //
+ ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *) ExtEntryList;
+ *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
+ *EraseByte = 0xFF;
+ } else {
+ *EraseByte = 0;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
+ FvHeader,
+ *FvUsedSize,
+ *EraseByte
+ ));
+ return TRUE;
+ }
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
+ ((UINT8 *) ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
+ }
+ }
+
+ //
+ // No USED_SIZE FV_EXT_TYPE entry found.
+ //
+ return FALSE;
+}
+
+/**
+ Get Fv image from the FV type file, then install FV INFO(2) ppi, Build FV hob.
+
+ @param PrivateData PeiCore's private data structure
+ @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
+ @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
+
+**/
+EFI_STATUS
+ProcessFvFile (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
+ IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_INFO ParentFvImageInfo;
+ UINT32 FvAlignment;
+ VOID *NewFvBuffer;
+ EFI_PEI_HOB_POINTERS HobPtr;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *ParentFvPpi;
+ EFI_PEI_FV_HANDLE ParentFvHandle;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FV_FILE_INFO FileInfo;
+ UINT64 FvLength;
+ UINT32 AuthenticationStatus;
+ UINT32 FvUsedSize;
+ UINT8 EraseByte;
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ HobPtr.Raw = GetHobList ();
+ while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
+ if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
+ //
+ // this FILE has been dispatched, it will not be dispatched again.
+ //
+ DEBUG ((EFI_D_INFO, "FV file %p has been dispatched!\r\n", ParentFvFileHandle));
+ return EFI_SUCCESS;
+ }
+ HobPtr.Raw = GET_NEXT_HOB (HobPtr);
+ }
+
+ ParentFvHandle = ParentFvCoreHandle->FvHandle;
+ ParentFvPpi = ParentFvCoreHandle->FvPpi;
+
+ //
+ // Find FvImage in FvFile
+ //
+ AuthenticationStatus = 0;
+ if ((ParentFvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (ParentFvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ Status = ParentFvPpi->FindSectionByType2 (
+ ParentFvPpi,
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+ 0,
+ ParentFvFileHandle,
+ (VOID **)&FvHeader,
+ &AuthenticationStatus
+ );
+ } else {
+ Status = ParentFvPpi->FindSectionByType (
+ ParentFvPpi,
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+ ParentFvFileHandle,
+ (VOID **)&FvHeader
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = VerifyPeim (PrivateData, ParentFvHandle, ParentFvFileHandle, AuthenticationStatus);
+ if (Status == EFI_SECURITY_VIOLATION) {
+ return Status;
+ }
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
+ __FUNCTION__,
+ FvHeader,
+ FvAlignment
+ ));
+
+ //
+ // Check FvImage alignment.
+ //
+ if ((UINTN) FvHeader % FvAlignment != 0) {
+ FvLength = ReadUnaligned64 (&FvHeader->FvLength);
+ NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvLength), FvAlignment);
+ if (NewFvBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
+ //
+ // Copy the used bytes and fill the rest with the erase value.
+ //
+ CopyMem (NewFvBuffer, FvHeader, (UINTN) FvUsedSize);
+ SetMem (
+ (UINT8 *) NewFvBuffer + FvUsedSize,
+ (UINTN) (FvLength - FvUsedSize),
+ EraseByte
+ );
+ } else {
+ CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
+ }
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
+ }
+ }
+
+ Status = ParentFvPpi->GetVolumeInfo (ParentFvPpi, ParentFvHandle, &ParentFvImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ParentFvPpi->GetFileInfo (ParentFvPpi, ParentFvFileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install FvInfo(2) Ppi
+ // NOTE: FvInfo2 must be installed before FvInfo so that recursive processing of encapsulated
+ // FVs inherit the proper AuthenticationStatus.
+ //
+ PeiServicesInstallFvInfo2Ppi(
+ &FvHeader->FileSystemGuid,
+ (VOID**)FvHeader,
+ (UINT32)FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName,
+ AuthenticationStatus
+ );
+
+ PeiServicesInstallFvInfoPpi (
+ &FvHeader->FileSystemGuid,
+ (VOID**) FvHeader,
+ (UINT32) FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ //
+ // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
+ //
+ BuildFvHob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength
+ );
+
+ //
+ // Makes the encapsulated volume show up in DXE phase to skip processing of
+ // encapsulated file again.
+ //
+ BuildFv2Hob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ //
+ // Build FV3 HOB with authentication status to be propagated to DXE.
+ //
+ BuildFv3Hob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength,
+ AuthenticationStatus,
+ TRUE,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process a firmware volume and create a volume handle.
+
+ Create a volume handle from the information in the buffer. For
+ memory-mapped firmware volumes, Buffer and BufferSize refer to
+ the start of the firmware volume and the firmware volume size.
+ For non memory-mapped firmware volumes, this points to a
+ buffer which contains the necessary information for creating
+ the firmware volume handle. Normally, these values are derived
+ from the EFI_FIRMWARE_VOLUME_INFO_PPI.
+
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param Buffer Points to the start of the buffer.
+ @param BufferSize Size of the buffer.
+ @param FvHandle Points to the returned firmware volume
+ handle. The firmware volume handle must
+ be unique within the system.
+
+ @retval EFI_SUCCESS Firmware volume handle created.
+ @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiProcessVolume (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_PEI_FV_HANDLE *FvHandle
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FvHandle != NULL);
+
+ if (Buffer == NULL) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
+ // FV image and the handle is pointed to Fv image's buffer.
+ //
+ *FvHandle = (EFI_PEI_FV_HANDLE) Buffer;
+
+ //
+ // Do verify for given FV buffer.
+ //
+ Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*) Buffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds the next file of the specified type.
+
+ This service enables PEI modules to discover additional firmware files.
+ The FileHandle must be unique within the system.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only files of this type. Type
+ EFI_FV_FILETYPE_ALL causes no filtering to be
+ done.
+ @param FvHandle Handle of firmware volume in which to
+ search.
+ @param FileHandle Points to the current handle from which to
+ begin searching or NULL to start at the
+ beginning of the firmware volume. Updated
+ upon return to reflect the file found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
+}
+
+/**
+ Find a file within a volume by its name.
+
+ This service searches for files with a specific name, within
+ either the specified firmware volume or all firmware volumes.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileName A pointer to the name of the file to find
+ within the firmware volume.
+ @param FvHandle Upon entry, the pointer to the firmware
+ volume to search or NULL if all firmware
+ volumes should be searched. Upon exit, the
+ actual firmware volume in which the file was
+ found.
+ @param FileHandle Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
+ FileName was NULL.
+
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByName (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE *FvHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_INSTANCE *PrivateData;
+ UINTN Index;
+
+ if ((FvHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*FvHandle != NULL) {
+ Status = FindFileEx (*FvHandle, FileName, 0, FileHandle, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ *FileHandle = NULL;
+ }
+ } else {
+ //
+ // If *FvHandle = NULL, so search all FV for given filename
+ //
+ Status = EFI_NOT_FOUND;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ //
+ // Only search the FV which is associated with a EFI_PEI_FIRMWARE_VOLUME_PPI instance.
+ //
+ if (PrivateData->Fv[Index].FvPpi != NULL) {
+ Status = FindFileEx (PrivateData->Fv[Index].FvHandle, FileName, 0, FileHandle, NULL);
+ if (!EFI_ERROR (Status)) {
+ *FvHandle = PrivateData->Fv[Index].FvHandle;
+ break;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address and size.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ )
+{
+ UINT8 FileState;
+ UINT8 ErasePolarity;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+ PEI_FW_VOL_INSTANCE *FwVolInstance;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
+
+ if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
+
+ switch (FileState) {
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
+ if (IS_FFS_FILE2 (FileHeader)) {
+ ASSERT (FFS_FILE2_SIZE (FileHeader) > 0x00FFFFFF);
+ if (!FwVolInstance->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FileHeader->Name));
+ return EFI_INVALID_PARAMETER;
+ }
+ FileInfo->BufferSize = FFS_FILE2_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileInfo->BufferSize = FFS_FILE_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
+ FileInfo->FileType = FileHeader->Type;
+ FileInfo->FileAttributes = FfsAttributes2FvFileAttributes (FileHeader->Attributes);
+ if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ FileInfo->FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address, size and authentication status.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PeiFfsFvPpiGetFileInfo (This, FileHandle, (EFI_FV_FILE_INFO *) FileInfo);
+ if (!EFI_ERROR (Status)) {
+ FileInfo->AuthenticationStatus = CoreFvHandle->AuthenticationStatus;
+ }
+
+ return Status;
+}
+
+/**
+ This function returns information about the firmware volume.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FvHandle Handle to the firmware handle.
+ @param VolumeInfo Points to the returned firmware volume
+ information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
+ firmware volume or VolumeInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetVolumeInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
+
+ if ((VolumeInfo == NULL) || (FvHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // VolumeHandle may not align at 8 byte,
+ // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
+ // So, Copy FvHeader into the local FvHeader structure.
+ //
+ CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ //
+ // Check Fv Image Signature
+ //
+ if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
+ VolumeInfo->FvAttributes = FwVolHeader.Attributes;
+ VolumeInfo->FvStart = (VOID *) FvHandle;
+ VolumeInfo->FvSize = FwVolHeader.FvLength;
+ CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
+
+ if (FwVolHeader.ExtHeaderOffset != 0) {
+ FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)FvHandle) + FwVolHeader.ExtHeaderOffset);
+ CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ )
+{
+ UINT32 AuthenticationStatus;
+ return PeiFfsFvPpiFindSectionByType2 (This, SearchType, 0, FileHandle, SectionData, &AuthenticationStatus);
+}
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given instance and type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param SearchInstance A filter to find the specific instance
+ of sections.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+ @param AuthenticationStatus Updated upon return to point to the
+ authentication status for this section.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN UINTN SearchInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ PEI_FW_VOL_INSTANCE *FwVolInstance;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+ UINTN Instance;
+ UINT32 ExtractedAuthenticationStatus;
+
+ if (SectionData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
+
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
+ if (!FwVolInstance->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ return EFI_NOT_FOUND;
+ }
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Instance = SearchInstance + 1;
+ ExtractedAuthenticationStatus = 0;
+ Status = ProcessSection (
+ GetPeiServicesTablePointer (),
+ SearchType,
+ &Instance,
+ Section,
+ FileSize,
+ SectionData,
+ &ExtractedAuthenticationStatus,
+ FwVolInstance->IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus = ExtractedAuthenticationStatus | CoreFvHandle->AuthenticationStatus;
+ }
+ return Status;
+}
+
+/**
+ Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
+
+ @param FvHandle The handle of a FV.
+
+ @retval NULL if can not find.
+ @return Pointer of corresponding PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FvHandleToCoreHandle (
+ IN EFI_PEI_FV_HANDLE FvHandle
+ )
+{
+ UINTN Index;
+ PEI_CORE_INSTANCE *PrivateData;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ if (FvHandle == PrivateData->Fv[Index].FvHandle) {
+ return &PrivateData->Fv[Index];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Get instance of PEI_CORE_FV_HANDLE for next volume according to given index.
+
+ This routine also will install FvInfo ppi for FV hob in PI ways.
+
+ @param Private Pointer of PEI_CORE_INSTANCE
+ @param Instance The index of FV want to be searched.
+
+ @return Instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FindNextCoreFvHandle (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN Instance
+ )
+{
+ UINTN Index;
+ BOOLEAN Match;
+ EFI_HOB_FIRMWARE_VOLUME *FvHob;
+
+ //
+ // Handle Framework FvHob and Install FvInfo Ppi for it.
+ //
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
+ //
+ // Loop to search the wanted FirmwareVolume which supports FFS
+ //
+ FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
+ while (FvHob != NULL) {
+ //
+ // Search whether FvHob has been installed into PeiCore's FV database.
+ // If found, no need install new FvInfoPpi for it.
+ //
+ for (Index = 0, Match = FALSE; Index < Private->FvCount; Index++) {
+ if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->Fv[Index].FvHeader) {
+ Match = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Search whether FvHob has been cached into PeiCore's Unknown FV database.
+ // If found, no need install new FvInfoPpi for it.
+ //
+ if (!Match) {
+ for (Index = 0; Index < Private->UnknownFvInfoCount; Index ++) {
+ if ((UINTN)FvHob->BaseAddress == (UINTN)Private->UnknownFvInfo[Index].FvInfo) {
+ Match = TRUE;
+ break;
+ }
+ }
+ }
+
+ //
+ // If the Fv in FvHob has not been installed into PeiCore's FV database and has
+ // not been cached into PeiCore's Unknown FV database, install a new FvInfoPpi
+ // for it then PeiCore will dispatch it in callback of FvInfoPpi.
+ //
+ if (!Match) {
+ PeiServicesInstallFvInfoPpi (
+ &(((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress)->FileSystemGuid),
+ (VOID *)(UINTN)FvHob->BaseAddress,
+ (UINT32)FvHob->Length,
+ NULL,
+ NULL
+ );
+ }
+
+ FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
+ }
+ }
+
+ ASSERT (Private->FvCount <= PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (Instance >= Private->FvCount) {
+ return NULL;
+ }
+
+ return &Private->Fv[Instance];
+}
+
+/**
+ After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
+ be re-installed with the instance in permanent memory and all cached FvPpi pointers in
+ PrivateData->Fv[] array should be fixed up to be pointed to the one in permanent
+ memory.
+
+ @param PrivateData Pointer to PEI_CORE_INSTANCE.
+**/
+VOID
+PeiReinitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ VOID *OldFfsFvPpi;
+ EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Locate old build-in Ffs2 EFI_PEI_FIRMWARE_VOLUME_PPI which
+ // in flash.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiFirmwareFileSystem2Guid,
+ 0,
+ &OldDescriptor,
+ &OldFfsFvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs2
+ // which is shadowed from flash to permanent memory within PeiCore image.
+ //
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs2FvPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
+ //
+ for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
+ if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
+ PrivateData->Fv[Index].FvPpi = &mPeiFfs2FwVol.Fv;
+ }
+ }
+
+ //
+ // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which
+ // in flash.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiFirmwareFileSystem3Guid,
+ 0,
+ &OldDescriptor,
+ &OldFfsFvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3
+ // which is shadowed from flash to permanent memory within PeiCore image.
+ //
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
+ //
+ for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
+ if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
+ PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;
+ }
+ }
+}
+
+/**
+ Report the information for a new discoveried FV in unknown third-party format.
+
+ If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for third-party FV format, but
+ the FV in this format has been discoveried, then this FV's information will be cached into
+ PEI_CORE_INSTANCE's UnknownFvInfo array.
+ Also a notification would be installed for unknown third-party FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI
+ is installed later by platform's PEIM, the original unknown third-party FV will be processed by
+ using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param FvInfo2Ppi Point to FvInfo2 PPI.
+
+ @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
+ @retval EFI_SUCCESS Success to add the information for unknown FV.
+**/
+EFI_STATUS
+AddUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI *FvInfo2Ppi
+ )
+{
+ PEI_CORE_UNKNOW_FORMAT_FV_INFO *NewUnknownFv;
+
+ if (PrivateData->UnknownFvInfoCount + 1 >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];
+ PrivateData->UnknownFvInfoCount ++;
+
+ CopyGuid (&NewUnknownFv->FvFormat, &FvInfo2Ppi->FvFormat);
+ NewUnknownFv->FvInfo = FvInfo2Ppi->FvInfo;
+ NewUnknownFv->FvInfoSize = FvInfo2Ppi->FvInfoSize;
+ NewUnknownFv->AuthenticationStatus = FvInfo2Ppi->AuthenticationStatus;
+ NewUnknownFv->NotifyDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ NewUnknownFv->NotifyDescriptor.Guid = &NewUnknownFv->FvFormat;
+ NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;
+
+ PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the FV information according to third-party FV format guid.
+
+ This routine also will remove the FV information found by given FV format guid from
+ PrivateData->UnknownFvInfo[].
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param Format Point to given FV format guid
+ @param FvInfo On return, the pointer of FV information buffer
+ @param FvInfoSize On return, the size of FV information buffer.
+ @param AuthenticationStatus On return, the authentication status of FV information buffer.
+
+ @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
+ @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+**/
+EFI_STATUS
+FindUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_GUID *Format,
+ OUT VOID **FvInfo,
+ OUT UINT32 *FvInfoSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+
+ Index = 0;
+ for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {
+ if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {
+ break;
+ }
+ }
+
+ if (Index == PrivateData->UnknownFvInfoCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ *FvInfo = PrivateData->UnknownFvInfo[Index].FvInfo;
+ *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;
+ *AuthenticationStatus = PrivateData->UnknownFvInfo[Index].AuthenticationStatus;
+
+ //
+ // Remove an entry from UnknownFvInfo array.
+ //
+ Index2 = Index + 1;
+ for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {
+ CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));
+ }
+ PrivateData->UnknownFvInfoCount --;
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
+ routine is called to process all discoveried FVs in this format.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The notification callback is processed correctly.
+**/
+EFI_STATUS
+EFIAPI
+ThirdPartyFvPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ VOID *FvInfo;
+ UINT32 FvInfoSize;
+ UINT32 AuthenticationStatus;
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE FvHandle;
+ BOOLEAN IsProcessed;
+ UINTN FvIndex;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *DepexData;
+ UINTN CurFvCount;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;
+
+ do {
+ Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize, &AuthenticationStatus);
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Process new found FV and get FV handle.
+ //
+ Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));
+ continue;
+ }
+
+ //
+ // Check whether the FV has already been processed.
+ //
+ IsProcessed = FALSE;
+ for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
+ if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
+ DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo));
+ IsProcessed = TRUE;
+ break;
+ }
+ }
+
+ if (IsProcessed) {
+ continue;
+ }
+
+ if (PrivateData->FvCount >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, PcdGet32 (PcdPeiCoreMaxFvSupported)));
+ DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
+ ASSERT (FALSE);
+ }
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = AuthenticationStatus;
+ CurFvCount = PrivateData->FvCount;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) CurFvCount,
+ (VOID *) FvInfo,
+ FvInfoSize,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+ FileHandle = NULL;
+ do {
+ Status = FvPpi->FindFileByType (
+ FvPpi,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+ FvHandle,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FvPpi->FindSectionByType (
+ FvPpi,
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID**)&DepexData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!PeimDispatchReadiness (PeiServices, DepexData)) {
+ //
+ // Dependency is not satisfied.
+ //
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
+ }
+ } while (FileHandle != NULL);
+ } while (TRUE);
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h
new file mode 100644
index 0000000000..1daeb6d97b
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h
@@ -0,0 +1,377 @@
+/** @file
+ The internal header file for firmware volume related definitions.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _FWVOL_H_
+#define _FWVOL_H_
+
+#include "PeiMain.h"
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+
+#define PEI_FW_VOL_SIGNATURE SIGNATURE_32('P','F','W','V')
+
+typedef struct {
+ UINTN Signature;
+ BOOLEAN IsFfs3Fv;
+ EFI_PEI_FIRMWARE_VOLUME_PPI Fv;
+} PEI_FW_VOL_INSTANCE;
+
+#define PEI_FW_VOL_INSTANCE_FROM_FV_THIS(a) \
+ CR(a, PEI_FW_VOL_INSTANCE, Fv, PEI_FW_VOL_SIGNATURE)
+
+
+/**
+ Process a firmware volume and create a volume handle.
+
+ Create a volume handle from the information in the buffer. For
+ memory-mapped firmware volumes, Buffer and BufferSize refer to
+ the start of the firmware volume and the firmware volume size.
+ For non memory-mapped firmware volumes, this points to a
+ buffer which contains the necessary information for creating
+ the firmware volume handle. Normally, these values are derived
+ from the EFI_FIRMWARE_VOLUME_INFO_PPI.
+
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param Buffer Points to the start of the buffer.
+ @param BufferSize Size of the buffer.
+ @param FvHandle Points to the returned firmware volume
+ handle. The firmware volume handle must
+ be unique within the system.
+
+ @retval EFI_SUCCESS Firmware volume handle created.
+ @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiProcessVolume (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_PEI_FV_HANDLE *FvHandle
+ );
+
+/**
+ Finds the next file of the specified type.
+
+ This service enables PEI modules to discover additional firmware files.
+ The FileHandle must be unique within the system.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only files of this type. Type
+ EFI_FV_FILETYPE_ALL causes no filtering to be
+ done.
+ @param FvHandle Handle of firmware volume in which to
+ search.
+ @param FileHandle Points to the current handle from which to
+ begin searching or NULL to start at the
+ beginning of the firmware volume. Updated
+ upon return to reflect the file found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Find a file within a volume by its name.
+
+ This service searches for files with a specific name, within
+ either the specified firmware volume or all firmware volumes.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileName A pointer to the name of the file to find
+ within the firmware volume.
+ @param FvHandle Upon entry, the pointer to the firmware
+ volume to search or NULL if all firmware
+ volumes should be searched. Upon exit, the
+ actual firmware volume in which the file was
+ found.
+ @param FileHandle Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
+ FileName was NULL.
+
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByName (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE *FvHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ );
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given instance and type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param SearchInstance A filter to find the specific instance
+ of sections.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+ @param AuthenticationStatus Updated upon return to point to the
+ authentication status for this section.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN UINTN SearchInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address and size.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ );
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address, size and authentication status.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ );
+
+/**
+ This function returns information about the firmware volume.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FvHandle Handle to the firmware handle.
+ @param VolumeInfo Points to the returned firmware volume
+ information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
+ firmware volume or VolumeInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetVolumeInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ );
+
+/**
+ Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
+
+ @param FvHandle The handle of a FV.
+
+ @retval NULL if can not find.
+ @return Pointer of corresponding PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FvHandleToCoreHandle (
+ IN EFI_PEI_FV_HANDLE FvHandle
+ );
+
+/**
+ Given the input file pointer, search for the next matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+
+
+ @param FvHandle Pointer to the FV header of the volume to search
+ @param FileName File name
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FileHandle This parameter must point to a valid FFS volume.
+ @param AprioriFile Pointer to AprioriFile image in this FV if has
+
+ @return EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+FindFileEx (
+ IN CONST EFI_PEI_FV_HANDLE FvHandle,
+ IN CONST EFI_GUID *FileName, OPTIONAL
+ IN EFI_FV_FILETYPE SearchType,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
+ IN OUT EFI_PEI_FV_HANDLE *AprioriFile OPTIONAL
+ );
+
+/**
+ Report the information for a new discoveried FV in unknown format.
+
+ If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for specifical FV format, but
+ the FV in this FV format has been discoveried, then the information of this FV
+ will be cached into PEI_CORE_INSTANCE's UnknownFvInfo array.
+ Also a notification would be installed for unknown FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI
+ is installed later by platform's PEIM, the original unknown FV will be processed by
+ using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param FvInfo2Ppi Point to FvInfo2 PPI.
+
+ @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
+ @retval EFI_SUCCESS Success to add the information for unknown FV.
+**/
+EFI_STATUS
+AddUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI *FvInfo2Ppi
+ );
+
+/**
+ Find the FV information according to FV format guid.
+
+ This routine also will remove the FV information found by given FV format guid from
+ PrivateData->UnknownFvInfo[].
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param Format Point to given FV format guid
+ @param FvInfo On return, the pointer of FV information buffer in given FV format guid
+ @param FvInfoSize On return, the size of FV information buffer.
+ @param AuthenticationStatus On return, the authentication status of FV information buffer.
+
+ @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
+ @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+**/
+EFI_STATUS
+FindUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_GUID *Format,
+ OUT VOID **FvInfo,
+ OUT UINT32 *FvInfoSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
+ routine is called to process all discoveried FVs in this format.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The notification callback is processed correctly.
+**/
+EFI_STATUS
+EFIAPI
+ThirdPartyFvPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c
new file mode 100644
index 0000000000..bb9f3f744e
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c
@@ -0,0 +1,240 @@
+/** @file
+ This module provide Hand-Off Block manupulation.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Gets the pointer to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param HobList Pointer to the HOB List.
+
+ @retval EFI_SUCCESS Get the pointer of HOB List
+ @retval EFI_NOT_AVAILABLE_YET the HOB List is not yet published
+ @retval EFI_INVALID_PARAMETER HobList is NULL (in debug mode)
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetHobList (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **HobList
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ //
+ // Only check this parameter in debug mode
+ //
+
+ DEBUG_CODE_BEGIN ();
+ if (HobList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ DEBUG_CODE_END ();
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ *HobList = PrivateData->HobList.Raw;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add a new HOB to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Type Type of the new HOB.
+ @param Length Length of the new HOB to allocate.
+ @param Hob Pointer to the new HOB.
+
+ @return EFI_SUCCESS Success to create hob.
+ @retval EFI_INVALID_PARAMETER if Hob is NULL
+ @retval EFI_NOT_AVAILABLE_YET if HobList is still not available.
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCreateHob (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT16 Type,
+ IN UINT16 Length,
+ IN OUT VOID **Hob
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+
+
+ Status = PeiGetHobList (PeiServices, Hob);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ HandOffHob = *Hob;
+
+ //
+ // Check Length to avoid data overflow.
+ //
+ if (0x10000 - Length <= 0x7) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Length = (UINT16)((Length + 0x7) & (~0x7));
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop -
+ HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < Length) {
+ DEBUG ((EFI_D_ERROR, "PeiCreateHob fail: Length - 0x%08x\n", (UINTN)Length));
+ DEBUG ((EFI_D_ERROR, " FreeMemoryTop - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryTop));
+ DEBUG ((EFI_D_ERROR, " FreeMemoryBottom - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryBottom));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobType = Type;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobLength = Length;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->Reserved = 0;
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN) *Hob + Length);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install SEC HOB data to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SecHobList Pointer to SEC HOB List.
+
+ @return EFI_SUCCESS Success to install SEC HOB data.
+ @retval EFI_OUT_OF_RESOURCES If there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+PeiInstallSecHobData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_HOB_GENERIC_HEADER *SecHobList
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_PEI_HOB_POINTERS HobStart;
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN SecHobListLength;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ HandOffHob = NULL;
+ Status = PeiGetHobList (PeiServices, (VOID **) &HandOffHob);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ ASSERT (HandOffHob != NULL);
+
+ HobStart.Raw = (UINT8 *) SecHobList;
+ //
+ // The HobList must not contain a EFI_HOB_HANDOFF_INFO_TABLE HOB (PHIT) HOB.
+ //
+ ASSERT (HobStart.Header->HobType != EFI_HOB_TYPE_HANDOFF);
+ //
+ // Calculate the SEC HOB List length,
+ // not including the terminated HOB(EFI_HOB_TYPE_END_OF_HOB_LIST).
+ //
+ for (Hob.Raw = HobStart.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob));
+ SecHobListLength = (UINTN) Hob.Raw - (UINTN) HobStart.Raw;
+ //
+ // The length must be 8-bytes aligned.
+ //
+ ASSERT ((SecHobListLength & 0x7) == 0);
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop -
+ HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < SecHobListLength) {
+ DEBUG ((DEBUG_ERROR, "PeiInstallSecHobData fail: SecHobListLength - 0x%08x\n", SecHobListLength));
+ DEBUG ((DEBUG_ERROR, " FreeMemoryTop - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryTop));
+ DEBUG ((DEBUG_ERROR, " FreeMemoryBottom - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryBottom));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Hob.Raw = (UINT8 *) (UINTN) HandOffHob->EfiEndOfHobList;
+ CopyMem (Hob.Raw, HobStart.Raw, SecHobListLength);
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER *) ((UINTN) Hob.Raw + SecHobListLength);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Builds a Handoff Information Table HOB
+
+ @param BootMode - Current Bootmode
+ @param MemoryBegin - Start Memory Address.
+ @param MemoryLength - Length of Memory.
+
+ @return EFI_SUCCESS Always success to initialize HOB.
+
+**/
+EFI_STATUS
+PeiCoreBuildHobHandoffInfoTable (
+ IN EFI_BOOT_MODE BootMode,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *Hob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ Hob = (VOID *)(UINTN)MemoryBegin;
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) (Hob+1);
+ Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
+ Hob->Header.HobLength = (UINT16) sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
+ Hob->Header.Reserved = 0;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+
+ Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
+ Hob->BootMode = BootMode;
+
+ Hob->EfiMemoryTop = MemoryBegin + MemoryLength;
+ Hob->EfiMemoryBottom = MemoryBegin;
+ Hob->EfiFreeMemoryTop = MemoryBegin + MemoryLength;
+ Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) (HobEnd + 1);
+ Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c
new file mode 100644
index 0000000000..1985411285
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c
@@ -0,0 +1,932 @@
+/** @file
+ Pei Core Load Image Support
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+
+EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
+ PeiLoadImageLoadImageWrapper
+};
+
+
+EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiLoadFilePpiGuid,
+ &mPeiLoadImagePpi
+};
+
+/**
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
+ The function is used for XIP code to have optimized memory copy.
+
+ @param FileHandle - The handle to the PE/COFF file
+ @param FileOffset - The offset, in bytes, into the file to read
+ @param ReadSize - The number of bytes to read from the file starting at FileOffset
+ @param Buffer - A pointer to the buffer to read the data into.
+
+ @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+**/
+EFI_STATUS
+EFIAPI
+PeiImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ if (Destination8 != Source8) {
+ CopyMem (Destination8, Source8, *ReadSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
+ The function is implemented as PIC so as to support shadowing.
+
+ @param FileHandle - The handle to the PE/COFF file
+ @param FileOffset - The offset, in bytes, into the file to read
+ @param ReadSize - The number of bytes to read from the file starting at FileOffset
+ @param Buffer - A pointer to the buffer to read the data into.
+
+ @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+**/
+EFI_STATUS
+EFIAPI
+PeiImageReadForShadow (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ volatile CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINTN Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ if (Destination8 != Source8) {
+ Length = *ReadSize;
+ while ((Length--) > 0) {
+ *(Destination8++) = *(Source8++);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Support routine to get the Image read file function.
+
+ @param ImageContext - The context of the image being loaded
+
+ @retval EFI_SUCCESS - If Image function location is found
+
+**/
+EFI_STATUS
+GetImageReadFunction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+ PEI_CORE_INSTANCE *Private;
+ EFI_PHYSICAL_ADDRESS MemoryBuffer;
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+ MemoryBuffer = 0;
+
+ if (Private->PeiMemoryInstalled && (((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)) ||
+ ((Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
+ //
+ // Shadow algorithm makes lots of non ANSI C assumptions and only works for IA32 and X64
+ // compilers that have been tested
+ //
+ if (Private->ShadowedImageRead == NULL) {
+ PeiServicesAllocatePages (EfiBootServicesCode, 0x400 / EFI_PAGE_SIZE + 1, &MemoryBuffer);
+ ASSERT (MemoryBuffer != 0);
+ CopyMem ((VOID *)(UINTN)MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400);
+ Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;
+ }
+
+ ImageContext->ImageRead = Private->ShadowedImageRead;
+ } else {
+ ImageContext->ImageRead = PeiImageRead;
+ }
+#else
+ ImageContext->ImageRead = PeiImageRead;
+#endif
+ return EFI_SUCCESS;
+}
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param Private Pointer to the private data passed in from caller
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT32 ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 ReservedCodeSize;
+ EFI_PHYSICAL_ADDRESS PeiCodeBase;
+ UINT32 BaseOffsetPageNumber;
+ UINT32 TopOffsetPageNumber;
+ UINT32 Index;
+ UINT64 *MemoryUsageBitMap;
+
+
+ //
+ // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
+ //
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
+
+ //
+ // Test the memory range for loading the image in the PEI code range.
+ //
+ if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||
+ (PeiCodeBase > ImageBase)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is avalaible or not.
+ //
+ MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap;
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @param Private Pointer to the private data passed in from caller
+
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ if (ImageContext->IsTeImage) {
+ //
+ // for TE image, the fix loading address is saved in first section header that doesn't point
+ // to code section.
+ //
+ SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
+ NumberOfSections = ImgHdr->Te.NumberOfSections;
+ } else {
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+ }
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
+ // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
+ // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
+ // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a
+ // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
+ // else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section.
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {
+ //
+ // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the absolute address of image base running in memory
+ //
+ FixLoadingAddress = ValueInSectionHeader;
+ } else {
+ //
+ // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the offset relative to a platform-specific top address.
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
+ }
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32) ImageContext->ImageSize);
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status));
+ return Status;
+}
+/**
+
+ Loads and relocates a PE/COFF image into memory.
+ If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
+
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress - The base address of the relocated PE/COFF image
+ @param ImageSize - The size of the relocated PE/COFF image
+ @param EntryPoint - The entry point of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImage (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN VOID *Pe32Data,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
+ OUT UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PEI_CORE_INSTANCE *Private;
+ UINT64 AlignImageSize;
+ BOOLEAN IsXipImage;
+ EFI_STATUS ReturnStatus;
+ BOOLEAN IsS3Boot;
+ BOOLEAN IsPeiModule;
+ BOOLEAN IsRegisterForShadow;
+ EFI_FV_FILE_INFO FileInfo;
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ ReturnStatus = EFI_SUCCESS;
+ IsXipImage = FALSE;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+ Status = GetImageReadFunction (&ImageContext);
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initilize local IsS3Boot and IsRegisterForShadow variable
+ //
+ IsS3Boot = FALSE;
+ if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
+ IsS3Boot = TRUE;
+ }
+ IsRegisterForShadow = FALSE;
+ if ((Private->CurrentFileHandle == FileHandle)
+ && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW)) {
+ IsRegisterForShadow = TRUE;
+ }
+
+ //
+ // XIP image that ImageAddress is same to Image handle.
+ //
+ if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ IsXipImage = TRUE;
+ }
+
+ //
+ // Get file type first
+ //
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check whether the file type is PEI module.
+ //
+ IsPeiModule = FALSE;
+ if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE ||
+ FileInfo.FileType == EFI_FV_FILETYPE_PEIM ||
+ FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) {
+ IsPeiModule = TRUE;
+ }
+
+ //
+ // When Image has no reloc section, it can't be relocated into memory.
+ //
+ if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
+ }
+
+ //
+ // Set default base address to current image address.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
+
+ //
+ // Allocate Memory for the image when memory is ready, and image is relocatable.
+ // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
+ // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
+ //
+ if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
+ //
+ // Allocate more buffer to avoid buffer overflow.
+ //
+ if (ImageContext.IsTeImage) {
+ AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
+ } else {
+ AlignImageSize = ImageContext.ImageSize;
+ }
+
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ AlignImageSize += ImageContext.SectionAlignment;
+ }
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
+ if (EFI_ERROR (Status)){
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // The PEIM is not assiged valid address, try to allocate page to load it.
+ //
+ Status = PeiServicesAllocatePages (EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize),
+ &ImageContext.ImageAddress);
+ }
+ } else {
+ Status = PeiServicesAllocatePages (EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize),
+ &ImageContext.ImageAddress);
+ }
+ if (!EFI_ERROR (Status)) {
+ //
+ // Adjust the Image Address to make sure it is section alignment.
+ //
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ ImageContext.ImageAddress =
+ (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
+ ~((UINTN)ImageContext.SectionAlignment - 1);
+ }
+ //
+ // Fix alignment requirement when Load IPF TeImage into memory.
+ // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
+ //
+ if (ImageContext.IsTeImage) {
+ ImageContext.ImageAddress = ImageContext.ImageAddress +
+ ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
+ sizeof (EFI_TE_IMAGE_HEADER);
+ }
+ } else {
+ //
+ // No enough memory resource.
+ //
+ if (IsXipImage) {
+ //
+ // XIP image can still be invoked.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
+ ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Non XIP image can't be loaded because no enough memory is allocated.
+ //
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ }
+
+ *ImageAddress = ImageContext.ImageAddress;
+ *ImageSize = ImageContext.ImageSize;
+ *EntryPoint = ImageContext.EntryPoint;
+
+ return ReturnStatus;
+}
+
+/**
+ Loads a PEIM into memory for subsequent execution. If there are compressed
+ images or images that need to be relocated into memory for performance reasons,
+ this service performs that transformation.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param ImageAddressArg Pointer to PE/TE image.
+ @param ImageSizeArg Size of PE/TE image.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate necessary PPI.
+ @retval EFI_UNSUPPORTED Image Machine Type is not supported.
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+PeiLoadImageLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS Status;
+ VOID *Pe32Data;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ EFI_PHYSICAL_ADDRESS ImageEntryPoint;
+ UINT16 Machine;
+ EFI_SECTION_TYPE SearchType1;
+ EFI_SECTION_TYPE SearchType2;
+
+ *EntryPoint = 0;
+ ImageSize = 0;
+ *AuthenticationState = 0;
+
+ if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
+ SearchType1 = EFI_SECTION_TE;
+ SearchType2 = EFI_SECTION_PE32;
+ } else {
+ SearchType1 = EFI_SECTION_PE32;
+ SearchType2 = EFI_SECTION_TE;
+ }
+
+ //
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // is true, TE will be searched first).
+ //
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType1,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ //
+ // If we didn't find a first exe section, try to find the second exe section.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType2,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // PEI core only carry the loader function for TE and PE32 executables
+ // If this two section does not exist, just return.
+ //
+ return Status;
+ }
+ }
+
+ //
+ // If memory is installed, perform the shadow operations
+ //
+ Status = LoadAndRelocatePeCoffImage (
+ FileHandle,
+ Pe32Data,
+ &ImageAddress,
+ &ImageSize,
+ &ImageEntryPoint
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Got the entry point from the loaded Pe32Data
+ //
+ Pe32Data = (VOID *) ((UINTN) ImageAddress);
+ *EntryPoint = ImageEntryPoint;
+
+ Machine = PeCoffLoaderGetMachineType (Pe32Data);
+
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
+ if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (ImageAddressArg != NULL) {
+ *ImageAddressArg = ImageAddress;
+ }
+
+ if (ImageSizeArg != NULL) {
+ *ImageSizeArg = ImageSize;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR8 *AsciiString;
+ CHAR8 EfiFileName[512];
+ INT32 Index;
+ INT32 StartIndex;
+
+ //
+ // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
+ //
+ if (Machine != EFI_IMAGE_MACHINE_IA64) {
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
+ } else {
+ //
+ // For IPF Image, the real entry point should be print.
+ //
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
+ }
+
+ //
+ // Print Module Name by PeImage PDB file name.
+ //
+ AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
+
+ if (AsciiString != NULL) {
+ StartIndex = 0;
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~511.
+ // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = AsciiString[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
+ }
+
+ DEBUG_CODE_END ();
+
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ The wrapper function of PeiLoadImageLoadImage().
+
+ @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param ImageAddressArg - Pointer to PE/TE image.
+ @param ImageSizeArg - Size of PE/TE image.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @return Status of PeiLoadImageLoadImage().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadImageLoadImageWrapper (
+ IN CONST EFI_PEI_LOAD_FILE_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ return PeiLoadImageLoadImage (
+ GetPeiServicesTablePointer (),
+ FileHandle,
+ ImageAddressArg,
+ ImageSizeArg,
+ EntryPoint,
+ AuthenticationState
+ );
+}
+
+/**
+ Check whether the input image has the relocation.
+
+ @param Pe32Data Pointer to the PE/COFF or TE image.
+
+ @retval TRUE Relocation is stripped.
+ @retval FALSE Relocation is not stripped.
+
+**/
+BOOLEAN
+RelocationIsStrip (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
+ }
+
+ //
+ // Three cases with regards to relocations:
+ // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
+ // has no base relocs to apply
+ // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
+ //
+ // Look at the file header to determine if relocations have been stripped, and
+ // save this info in the image context for later use.
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Routine to load image file for subsequent execution by LoadFile Ppi.
+ If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
+ XIP image format is used.
+
+ @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param PeimState - The dispatch state of the input PEIM handle.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS - Image is successfully loaded.
+ @retval EFI_NOT_FOUND - Fail to locate necessary PPI
+ @retval Others - Fail to load file.
+
+**/
+EFI_STATUS
+PeiLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT8 PeimState,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS PpiStatus;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ BOOLEAN IsStrip;
+
+ IsStrip = FALSE;
+ //
+ // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
+ // one at a time, until one reports EFI_SUCCESS.
+ //
+ Index = 0;
+ do {
+ PpiStatus = PeiServicesLocatePpi (
+ &gEfiPeiLoadFilePpiGuid,
+ Index,
+ NULL,
+ (VOID **)&LoadFile
+ );
+ if (!EFI_ERROR (PpiStatus)) {
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &ImageAddress,
+ &ImageSize,
+ EntryPoint,
+ AuthenticationState
+ );
+ if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) {
+ //
+ // The shadowed PEIM must be relocatable.
+ //
+ if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {
+ IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
+ ASSERT (!IsStrip);
+ if (IsStrip) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // The image to be started must have the machine type supported by PeiCore.
+ //
+ ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ Index++;
+ } while (!EFI_ERROR (PpiStatus));
+
+ return PpiStatus;
+}
+
+
+/**
+
+ Install Pei Load File PPI.
+
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
+
+**/
+VOID
+InitializeImageServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ //
+ // The first time we are XIP (running from FLASH). We need to remember the
+ // FLASH address so we can reinstall the memory version that runs faster
+ //
+ PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
+ PeiServicesInstallPpi (PrivateData->XipLoadFile);
+ } else {
+ //
+ // 2nd time we are running from memory so replace the XIP version with the
+ // new memory version.
+ //
+ PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
+ }
+}
+
+
+
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
new file mode 100644
index 0000000000..516311d091
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
@@ -0,0 +1,814 @@
+/** @file
+ EFI PEI Core memory services
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Initialize the memory services.
+
+ @param PrivateData Points to PeiCore's private instance data.
+ @param 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.
+ @param OldCoreData Pointer to the PEI Core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializeMemoryServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+
+ PrivateData->SwitchStackSignal = FALSE;
+
+ //
+ // First entering PeiCore, following code will initialized some field
+ // in PeiCore's private data according to hand off data from sec core.
+ //
+ if (OldCoreData == NULL) {
+
+ PrivateData->PeiMemoryInstalled = FALSE;
+ PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;
+
+ PeiCoreBuildHobHandoffInfoTable (
+ BOOT_WITH_FULL_CONFIGURATION,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
+ (UINTN) SecCoreData->PeiTemporaryRamSize
+ );
+
+ //
+ // Set Ps to point to ServiceTableShadow in Cache
+ //
+ PrivateData->Ps = &(PrivateData->ServiceTableShadow);
+ }
+
+ return;
+}
+
+/**
+
+ This function registers the found memory configuration with the PEI Foundation.
+
+ The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
+ This routine will hold discoveried memory information into PeiCore's private data,
+ and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
+ PeiDispatcher will migrate temporary memory to permenement memory.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryBegin Start of memory address.
+ @param MemoryLength Length of memory.
+
+ @return EFI_SUCCESS Always success.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPeiMemory (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ //
+ // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
+ // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
+ // simply return EFI_SUCESS in release tip to ignore it.
+ //
+ if (PrivateData->PeiMemoryInstalled) {
+ DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+ }
+
+ PrivateData->PhysicalMemoryBegin = MemoryBegin;
+ PrivateData->PhysicalMemoryLength = MemoryLength;
+ PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
+
+ PrivateData->SwitchStackSignal = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Migrate memory pages allocated in pre-memory phase.
+ Copy memory pages at temporary heap top to permanent heap top.
+
+ @param[in] Private Pointer to the private data passed in from caller.
+ @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
+
+**/
+VOID
+MigrateMemoryPages (
+ IN PEI_CORE_INSTANCE *Private,
+ IN BOOLEAN TemporaryRamMigrated
+ )
+{
+ EFI_PHYSICAL_ADDRESS NewMemPagesBase;
+ EFI_PHYSICAL_ADDRESS MemPagesBase;
+
+ Private->MemoryPages.Size = (UINTN) (Private->HobList.HandoffInformationTable->EfiMemoryTop -
+ Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
+ if (Private->MemoryPages.Size == 0) {
+ //
+ // No any memory page allocated in pre-memory phase.
+ //
+ return;
+ }
+ Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;
+
+ ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);
+ NewMemPagesBase = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;
+ NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;
+ ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);
+ //
+ // Copy memory pages at temporary heap top to permanent heap top.
+ //
+ if (TemporaryRamMigrated) {
+ //
+ // Memory pages at temporary heap top has been migrated to permanent heap,
+ // Here still needs to copy them from permanent heap to permanent heap top.
+ //
+ MemPagesBase = Private->MemoryPages.Base;
+ if (Private->HeapOffsetPositive) {
+ MemPagesBase += Private->HeapOffset;
+ } else {
+ MemPagesBase -= Private->HeapOffset;
+ }
+ CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
+ } else {
+ CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
+ }
+
+ if (NewMemPagesBase >= Private->MemoryPages.Base) {
+ Private->MemoryPages.OffsetPositive = TRUE;
+ Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
+ } else {
+ Private->MemoryPages.OffsetPositive = FALSE;
+ Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
+ }
+
+ DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64) Private->MemoryPages.Offset));
+
+ Private->FreePhysicalMemoryTop = NewMemPagesBase;
+}
+
+/**
+ Migrate MemoryBaseAddress in memory allocation HOBs
+ from the temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertMemoryAllocationHobs (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ EFI_PHYSICAL_ADDRESS OldMemPagesBase;
+ UINTN OldMemPagesSize;
+
+ if (PrivateData->MemoryPages.Size == 0) {
+ //
+ // No any memory page allocated in pre-memory phase.
+ //
+ return;
+ }
+
+ OldMemPagesBase = PrivateData->MemoryPages.Base;
+ OldMemPagesSize = PrivateData->MemoryPages.Size;
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ if ((MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress >= OldMemPagesBase) &&
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress < (OldMemPagesBase + OldMemPagesSize))
+ ) {
+ if (PrivateData->MemoryPages.OffsetPositive) {
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;
+ } else {
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;
+ }
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+}
+
+/**
+ Internal function to build a HOB for the memory allocation.
+ It will search and reuse the unused(freed) memory allocation HOB,
+ or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.
+
+ @param[in] BaseAddress The 64 bit physical address of the memory.
+ @param[in] Length The length of the memory allocation in bytes.
+ @param[in] MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+InternalBuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ //
+ // Search unused(freed) memory allocation HOB.
+ //
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_UNUSED);
+ while (Hob.Raw != NULL) {
+ if (Hob.Header->HobLength == sizeof (EFI_HOB_MEMORY_ALLOCATION)) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ //
+ // Reuse the unused(freed) memory allocation HOB.
+ //
+ MemoryAllocationHob->Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION;
+ ZeroMem (&(MemoryAllocationHob->AllocDescriptor.Name), sizeof (EFI_GUID));
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ MemoryAllocationHob->AllocDescriptor.MemoryLength = Length;
+ MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));
+ } else {
+ //
+ // No unused(freed) memory allocation HOB found.
+ // Build memory allocation HOB normally.
+ //
+ BuildMemoryAllocationHob (
+ BaseAddress,
+ Length,
+ MemoryType
+ );
+ }
+}
+
+/**
+ Update or split memory allocation HOB for memory pages allocate and free.
+
+ @param[in, out] MemoryAllocationHob Pointer to the memory allocation HOB
+ that needs to be updated or split.
+ On output, it will be filled with
+ the input Memory, Bytes and MemoryType.
+ @param[in] Memory Memory to allocate or free.
+ @param[in] Bytes Bytes to allocate or free.
+ @param[in] MemoryType EfiConventionalMemory for pages free,
+ others for pages allocate.
+
+**/
+VOID
+UpdateOrSplitMemoryAllocationHob (
+ IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Bytes,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ if ((Memory + Bytes) <
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength)) {
+ //
+ // Last pages need to be split out.
+ //
+ InternalBuildMemoryAllocationHob (
+ Memory + Bytes,
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),
+ MemoryAllocationHob->AllocDescriptor.MemoryType
+ );
+ }
+
+ if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+ //
+ // First pages need to be split out.
+ //
+ InternalBuildMemoryAllocationHob (
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
+ Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
+ MemoryAllocationHob->AllocDescriptor.MemoryType
+ );
+ }
+
+ //
+ // Update the memory allocation HOB.
+ //
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;
+ MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;
+ MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
+}
+
+/**
+ Merge adjacent free memory ranges in memory allocation HOBs.
+
+ @retval TRUE There are free memory ranges merged.
+ @retval FALSE No free memory ranges merged.
+
+**/
+BOOLEAN
+MergeFreeMemoryInMemoryAllocationHob (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_HOB_POINTERS Hob2;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob2;
+ UINT64 Start;
+ UINT64 End;
+ BOOLEAN Merged;
+
+ Merged = FALSE;
+
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {
+ MemoryHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ Start = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ End = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
+
+ Hob2.Raw = GET_NEXT_HOB (Hob);
+ Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ while (Hob2.Raw != NULL) {
+ if (Hob2.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {
+ MemoryHob2 = (EFI_HOB_MEMORY_ALLOCATION *) Hob2.Raw;
+ if (Start == (MemoryHob2->AllocDescriptor.MemoryBaseAddress + MemoryHob2->AllocDescriptor.MemoryLength)) {
+ //
+ // Merge adjacent two free memory ranges.
+ //
+ MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
+ Merged = TRUE;
+ //
+ // Mark MemoryHob to be unused(freed).
+ //
+ MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
+ break;
+ } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {
+ //
+ // Merge adjacent two free memory ranges.
+ //
+ MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
+ Merged = TRUE;
+ //
+ // Mark MemoryHob to be unused(freed).
+ //
+ MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
+ break;
+ }
+ }
+ Hob2.Raw = GET_NEXT_HOB (Hob2);
+ Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ return Merged;
+}
+
+/**
+ Find free memory by searching memory allocation HOBs.
+
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of contiguous 4 KB pages to allocate.
+ @param[in] Granularity Page allocation granularity.
+ @param[out] Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_NOT_FOUND No memory allocation HOB with big enough free memory found.
+
+**/
+EFI_STATUS
+FindFreeMemoryFromMemoryAllocationHob (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Granularity,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ UINT64 Bytes;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
+
+ BaseAddress = 0;
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&
+ (Hob.MemoryAllocation->AllocDescriptor.MemoryLength >= Bytes)) {
+ //
+ // Found one memory allocation HOB with big enough free memory.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ BaseAddress = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +
+ MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;
+ //
+ // Make sure the granularity could be satisfied.
+ //
+ BaseAddress &= ~((EFI_PHYSICAL_ADDRESS) Granularity - 1);
+ if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+ break;
+ }
+ BaseAddress = 0;
+ MemoryAllocationHob = NULL;
+ }
+ //
+ // Continue to find.
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);
+ *Memory = BaseAddress;
+ return EFI_SUCCESS;
+ } else {
+ if (MergeFreeMemoryInMemoryAllocationHob ()) {
+ //
+ // Retry if there are free memory ranges merged.
+ //
+ return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
+ }
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ The purpose of the service is to publish an interface that allows
+ PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+ Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+ After InstallPeiMemory() is called, PEI will allocate pages within the region
+ of memory provided by InstallPeiMemory() service in a best-effort fashion.
+ Location-specific allocations are not managed by the PEI foundation code.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+ EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+ EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;
+ UINTN RemainingPages;
+ UINTN Granularity;
+ UINTN Padding;
+
+ if ((MemoryType != EfiLoaderCode) &&
+ (MemoryType != EfiLoaderData) &&
+ (MemoryType != EfiRuntimeServicesCode) &&
+ (MemoryType != EfiRuntimeServicesData) &&
+ (MemoryType != EfiBootServicesCode) &&
+ (MemoryType != EfiBootServicesData) &&
+ (MemoryType != EfiACPIReclaimMemory) &&
+ (MemoryType != EfiReservedMemoryType) &&
+ (MemoryType != EfiACPIMemoryNVS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (Hob.Raw == NULL) {
+ //
+ // HOB is not initialized yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ if (RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY &&
+ (MemoryType == EfiACPIReclaimMemory ||
+ MemoryType == EfiACPIMemoryNVS ||
+ MemoryType == EfiRuntimeServicesCode ||
+ MemoryType == EfiRuntimeServicesData)) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+
+ DEBUG ((DEBUG_INFO, "AllocatePages: aligning allocation to %d KB\n",
+ Granularity / SIZE_1KB));
+ }
+
+ if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
+ //
+ // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
+ // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
+ //
+ FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
+ FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);
+ } else {
+ FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
+ FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
+ }
+
+ //
+ // Check to see if on correct boundary for the memory type.
+ // If not aligned, make the allocation aligned.
+ //
+ Padding = *(FreeMemoryTop) & (Granularity - 1);
+ if ((UINTN) (*FreeMemoryTop - *FreeMemoryBottom) < Padding) {
+ DEBUG ((DEBUG_ERROR, "AllocatePages failed: Out of space after padding.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(FreeMemoryTop) -= Padding;
+ if (Padding >= EFI_PAGE_SIZE) {
+ //
+ // Create a memory allocation HOB to cover
+ // the pages that we will lose to rounding
+ //
+ InternalBuildMemoryAllocationHob (
+ *(FreeMemoryTop),
+ Padding & ~(UINTN)EFI_PAGE_MASK,
+ EfiConventionalMemory
+ );
+ }
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation.
+ //
+ RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;
+ //
+ // The number of remaining pages needs to be greater than or equal to that of the request pages.
+ //
+ Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));
+ if (RemainingPages < Pages) {
+ //
+ // Try to find free memory by searching memory allocation HOBs.
+ //
+ Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64) Pages));
+ DEBUG ((EFI_D_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64) RemainingPages));
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Update the PHIT to reflect the memory usage
+ //
+ *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
+
+ //
+ // Update the value for the caller
+ //
+ *Memory = *(FreeMemoryTop);
+
+ //
+ // Create a memory allocation HOB.
+ //
+ InternalBuildMemoryAllocationHob (
+ *(FreeMemoryTop),
+ Pages * EFI_PAGE_SIZE,
+ MemoryType
+ );
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
+ if MemoryBaseAddress == *FreeMemoryTop.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+ @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
+
+**/
+VOID
+FreeMemoryAllocationHob (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHobToFree
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
+ //
+ // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
+ // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.
+ //
+ FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
+ } else {
+ FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
+ }
+
+ if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {
+ //
+ // Update *FreeMemoryTop.
+ //
+ *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;
+ //
+ // Mark the memory allocation HOB to be unused(freed).
+ //
+ MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&
+ (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop)) {
+ //
+ // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
+ // MemoryBaseAddress == new *FreeMemoryTop.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+ //
+ // Free memory allocation HOB iteratively.
+ //
+ if (MemoryAllocationHob != NULL) {
+ FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
+ }
+ }
+}
+
+/**
+ Frees memory pages.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] Memory The base physical address of the pages to be freed.
+ @param[in] Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFreePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ UINT64 Bytes;
+ UINT64 Start;
+ UINT64 End;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
+ Start = Memory;
+ End = Start + Bytes - 1;
+
+ if (Pages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (Hob.Raw == NULL) {
+ //
+ // HOB is not initialized yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType != EfiConventionalMemory) &&
+ (Memory >= Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress) &&
+ ((Memory + Bytes) <= (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength))) {
+ //
+ // Found the memory allocation HOB that includes the memory pages to be freed.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);
+ FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+
+ Pool allocation service. Before permanent memory is discoveried, the pool will
+ be allocated the heap in the temporary memory. Genenrally, the size of heap in temporary
+ memory does not exceed to 64K, so the biggest pool size could be allocated is
+ 64K.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Size Amount of memory required
+ @param Buffer Address of pointer to the buffer
+
+ @retval EFI_SUCCESS The allocation was successful
+ @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
+ to allocate the requested size.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePool (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_MEMORY_POOL *Hob;
+
+ //
+ // If some "post-memory" PEIM wishes to allocate larger pool,
+ // it should use AllocatePages service instead.
+ //
+
+ //
+ // Generally, the size of heap in temporary memory does not exceed to 64K,
+ // HobLength is multiples of 8 bytes, so the maxmium size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
+ //
+ if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = PeiServicesCreateHob (
+ EFI_HOB_TYPE_MEMORY_POOL,
+ (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
+ (VOID **)&Hob
+ );
+ ASSERT_EFI_ERROR (Status);
+ *Buffer = Hob+1;
+
+ return Status;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c
new file mode 100644
index 0000000000..a20e7c00c5
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c
@@ -0,0 +1,128 @@
+/** @file
+ The default version of EFI_PEI_PCI_CFG2_PPI support published by PeiServices in
+ PeiCore initialization phase.
+
+ EFI_PEI_PCI_CFG2_PPI is installed by the PEIM which supports a PCI root bridge.
+ When PeiCore is started, the default version of EFI_PEI_PCI_CFG2_PPI will be assigned
+ to PeiServices table.
+
+Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+///
+/// This default instance of EFI_PEI_PCI_CFG2_PPI install assigned to EFI_PEI_SERVICE.PciCfg
+/// when PeiCore's initialization.
+///
+EFI_PEI_PCI_CFG2_PPI gPeiDefaultPciCfg2Ppi = {
+ PeiDefaultPciCfg2Read,
+ PeiDefaultPciCfg2Write,
+ PeiDefaultPciCfg2Modify
+};
+
+/**
+ Reads from a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Read (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Write to a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Write (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ This function performs a read-modify-write operation on the contents from a given
+ location in the PCI configuration space.
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes. Type
+ EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
+ @param Address The physical address of the access.
+ @param SetBits Points to value to bitwise-OR with the read configuration value.
+ The size of the value is determined by Width.
+ @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
+ The size of the value is determined by Width.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Modify (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *SetBits,
+ IN VOID *ClearBits
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.uni
new file mode 100644
index 0000000000..79db0cc791
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.uni
@@ -0,0 +1,27 @@
+// /** @file
+// PeiMain module is core module in PEI phase.
+//
+// It takes responsibilities of:
+// 1) Initialize memory, PPI, image services etc, to establish PEIM runtime environment.
+// 2) Dispatch PEIM from discovered FV.
+// 3) Handoff control to DxeIpl to load DXE core and enter DXE phase.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Core module in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It takes responsibilities of:<BR>\n"
+ "1) Initializing memory, PPI, image services etc., to establish the PEIM runtime environment.<BR>\n"
+ "2) Dispatches PEIM from discovered FV.<BR>\n"
+ "3) Handsoff control to DxeIpl to load DXE core and enters DXE phase.<BR>"
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.uni
new file mode 100644
index 0000000000..ec430fccae
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// PeiCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core PEI Services Module"
+
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h
new file mode 100644
index 0000000000..fef3753e4b
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h
@@ -0,0 +1,1831 @@
+/** @file
+ Definition of Pei Core Structures and Services
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_MAIN_H_
+#define _PEI_MAIN_H_
+
+#include <PiPei.h>
+#include <Ppi/DxeIpl.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/StatusCode.h>
+#include <Ppi/Reset.h>
+#include <Ppi/Reset2.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/Decompress.h>
+#include <Ppi/GuidedSectionExtraction.h>
+#include <Ppi/LoadFile.h>
+#include <Ppi/Security2.h>
+#include <Ppi/TemporaryRamSupport.h>
+#include <Ppi/TemporaryRamDone.h>
+#include <Ppi/SecHobData.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiCoreEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Guid/AprioriFileName.h>
+
+///
+/// It is an FFS type extension used for PeiFindFileEx. It indicates current
+/// Ffs searching is for all PEIMs can be dispatched by PeiCore.
+///
+#define PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE 0xff
+
+///
+/// Pei Core private data structures
+///
+typedef union {
+ EFI_PEI_PPI_DESCRIPTOR *Ppi;
+ EFI_PEI_NOTIFY_DESCRIPTOR *Notify;
+ VOID *Raw;
+} PEI_PPI_LIST_POINTERS;
+
+///
+/// PPI database structure which contains two link: PpiList and NotifyList. PpiList
+/// is in head of PpiListPtrs array and notify is in end of PpiListPtrs.
+///
+typedef struct {
+ ///
+ /// index of end of PpiList link list.
+ ///
+ INTN PpiListEnd;
+ ///
+ /// index of end of notify link list.
+ ///
+ INTN NotifyListEnd;
+ ///
+ /// index of the dispatched notify list.
+ ///
+ INTN DispatchListEnd;
+ ///
+ /// index of last installed Ppi description in PpiList link list.
+ ///
+ INTN LastDispatchedInstall;
+ ///
+ /// index of last dispatched notify in Notify link list.
+ ///
+ INTN LastDispatchedNotify;
+ ///
+ /// Ppi database has the PcdPeiCoreMaxPpiSupported number of entries.
+ ///
+ PEI_PPI_LIST_POINTERS *PpiListPtrs;
+} PEI_PPI_DATABASE;
+
+
+//
+// PEI_CORE_FV_HANDE.PeimState
+// Do not change these values as there is code doing math to change states.
+// Look for Private->Fv[FvCount].PeimState[PeimCount]++;
+//
+#define PEIM_STATE_NOT_DISPATCHED 0x00
+#define PEIM_STATE_DISPATCHED 0x01
+#define PEIM_STATE_REGISITER_FOR_SHADOW 0x02
+#define PEIM_STATE_DONE 0x03
+
+typedef struct {
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_PEI_FV_HANDLE FvHandle;
+ //
+ // Ponter to the buffer with the PcdPeiCoreMaxPeimPerFv number of Entries.
+ //
+ UINT8 *PeimState;
+ //
+ // Ponter to the buffer with the PcdPeiCoreMaxPeimPerFv number of Entries.
+ //
+ EFI_PEI_FILE_HANDLE *FvFileHandles;
+ BOOLEAN ScanFv;
+ UINT32 AuthenticationStatus;
+} PEI_CORE_FV_HANDLE;
+
+typedef struct {
+ EFI_GUID FvFormat;
+ VOID *FvInfo;
+ UINT32 FvInfoSize;
+ UINT32 AuthenticationStatus;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;
+} PEI_CORE_UNKNOW_FORMAT_FV_INFO;
+
+#define CACHE_SETION_MAX_NUMBER 0x10
+typedef struct {
+ EFI_COMMON_SECTION_HEADER* Section[CACHE_SETION_MAX_NUMBER];
+ VOID* SectionData[CACHE_SETION_MAX_NUMBER];
+ UINTN SectionSize[CACHE_SETION_MAX_NUMBER];
+ UINT32 AuthenticationStatus[CACHE_SETION_MAX_NUMBER];
+ UINTN AllSectionCount;
+ UINTN SectionIndex;
+} CACHE_SECTION_DATA;
+
+#define HOLE_MAX_NUMBER 0x3
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Base;
+ UINTN Size;
+ UINTN Offset;
+ BOOLEAN OffsetPositive;
+} HOLE_MEMORY_DATA;
+
+///
+/// Forward declaration for PEI_CORE_INSTANCE
+///
+typedef struct _PEI_CORE_INSTANCE PEI_CORE_INSTANCE;
+
+
+/**
+ Function Pointer type for PeiCore function.
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. 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
+ @param OldCoreData Pointer to old core data that is used to initialize the
+ core's data areas.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEICORE_FUNCTION_POINTER)(
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+#define PEI_CORE_HANDLE_SIGNATURE SIGNATURE_32('P','e','i','C')
+
+///
+/// Pei Core private data structure instance
+///
+struct _PEI_CORE_INSTANCE {
+ UINTN Signature;
+
+ ///
+ /// Point to ServiceTableShadow
+ ///
+ EFI_PEI_SERVICES *Ps;
+ PEI_PPI_DATABASE PpiData;
+
+ ///
+ /// The count of FVs which contains FFS and could be dispatched by PeiCore.
+ ///
+ UINTN FvCount;
+
+ ///
+ /// Pointer to the buffer with the PcdPeiCoreMaxFvSupported number of entries.
+ /// Each entry is for one FV which contains FFS and could be dispatched by PeiCore.
+ ///
+ PEI_CORE_FV_HANDLE *Fv;
+
+ ///
+ /// Pointer to the buffer with the PcdPeiCoreMaxFvSupported number of entries.
+ /// Each entry is for one FV which could not be dispatched by PeiCore.
+ ///
+ PEI_CORE_UNKNOW_FORMAT_FV_INFO *UnknownFvInfo;
+ UINTN UnknownFvInfoCount;
+
+ ///
+ /// Pointer to the buffer with the PcdPeiCoreMaxPeimPerFv number of entries.
+ ///
+ EFI_PEI_FILE_HANDLE *CurrentFvFileHandles;
+ UINTN AprioriCount;
+ UINTN CurrentPeimFvCount;
+ UINTN CurrentPeimCount;
+ EFI_PEI_FILE_HANDLE CurrentFileHandle;
+ BOOLEAN PeimNeedingDispatch;
+ BOOLEAN PeimDispatchOnThisPass;
+ BOOLEAN PeimDispatcherReenter;
+ EFI_PEI_HOB_POINTERS HobList;
+ BOOLEAN SwitchStackSignal;
+ BOOLEAN PeiMemoryInstalled;
+ VOID *CpuIo;
+ EFI_PEI_SECURITY2_PPI *PrivateSecurityPpi;
+ EFI_PEI_SERVICES ServiceTableShadow;
+ EFI_PEI_PPI_DESCRIPTOR *XipLoadFile;
+ EFI_PHYSICAL_ADDRESS PhysicalMemoryBegin;
+ UINT64 PhysicalMemoryLength;
+ EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;
+ UINTN HeapOffset;
+ BOOLEAN HeapOffsetPositive;
+ UINTN StackOffset;
+ BOOLEAN StackOffsetPositive;
+ //
+ // Information for migrating memory pages allocated in pre-memory phase.
+ //
+ HOLE_MEMORY_DATA MemoryPages;
+ PEICORE_FUNCTION_POINTER ShadowedPeiCore;
+ CACHE_SECTION_DATA CacheSection;
+ //
+ // For Loading modules at fixed address feature to cache the top address below which the
+ // Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field
+ // and Ps should not be changed since maybe user could get this top address by using the offet to Ps.
+ //
+ EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress;
+ //
+ // The field is define for Loading modules at fixed address feature to tracker the PEI code
+ // memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
+ // available or not.
+ //
+ UINT64 *PeiCodeMemoryRangeUsageBitMap;
+ //
+ // This field points to the shadowed image read function
+ //
+ PE_COFF_LOADER_READ_FILE ShadowedImageRead;
+
+ //
+ // Pointer to the temp buffer with the PcdPeiCoreMaxPeimPerFv + 1 number of entries.
+ //
+ EFI_PEI_FILE_HANDLE *FileHandles;
+ //
+ // Pointer to the temp buffer with the PcdPeiCoreMaxPeimPerFv number of entries.
+ //
+ EFI_GUID *FileGuid;
+
+ //
+ // Temp Memory Range is not covered by PeiTempMem and Stack.
+ // Those Memory Range will be migrated into physical memory.
+ //
+ HOLE_MEMORY_DATA HoleData[HOLE_MAX_NUMBER];
+};
+
+///
+/// Pei Core Instance Data Macros
+///
+#define PEI_CORE_INSTANCE_FROM_PS_THIS(a) \
+ CR(a, PEI_CORE_INSTANCE, Ps, PEI_CORE_HANDLE_SIGNATURE)
+
+///
+/// Union of temporarily used function pointers (to save stack space)
+///
+typedef union {
+ PEICORE_FUNCTION_POINTER PeiCore;
+ EFI_PEIM_ENTRY_POINT2 PeimEntry;
+ EFI_PEIM_NOTIFY_ENTRY_POINT PeimNotifyEntry;
+ EFI_DXE_IPL_PPI *DxeIpl;
+ EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
+ VOID *Raw;
+} PEI_CORE_TEMP_POINTERS;
+
+typedef struct {
+ CONST EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_PEI_PPI_DESCRIPTOR *PpiList;
+ VOID *Data;
+} PEI_CORE_PARAMETERS;
+
+//
+// PeiCore function
+//
+/**
+
+ The entry routine to Pei Core, invoked by PeiMain during transition
+ from SEC to PEI. After switching stack in the PEI core, it will restart
+ with the old core data.
+
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. 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
+ @param Data Pointer to old core data that is used to initialize the
+ core's data areas.
+
+**/
+VOID
+EFIAPI
+PeiCore (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN VOID *Data
+ );
+
+//
+// Dispatcher support functions
+//
+
+/**
+
+ This is the POSTFIX version of the dependency evaluator. When a
+ PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on
+ the evaluation stack. When that entry is poped from the evaluation
+ stack, the PPI is checked if it is installed. This method allows
+ some time savings as not all PPIs must be checked for certain
+ operation types (AND, OR).
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param DependencyExpression Pointer to a dependency expression. The Grammar adheres to
+ the BNF described above and is stored in postfix notation.
+
+ @retval TRUE if it is a well-formed Grammar
+ @retval FALSE if the dependency expression overflows the evaluation stack
+ if the dependency expression underflows the evaluation stack
+ if the dependency expression is not a well-formed Grammar.
+
+**/
+BOOLEAN
+PeimDispatchReadiness (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *DependencyExpression
+ );
+
+/**
+ Conduct PEIM dispatch.
+
+ @param SecCoreData Pointer to the data structure containing SEC to PEI handoff data
+ @param PrivateData Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiDispatcher (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+ Initialize the Dispatcher's data members
+
+ @param PrivateData PeiCore's private data structure
+ @param OldCoreData Old data from SecCore
+ NULL if being run in non-permament memory mode.
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+
+**/
+VOID
+InitializeDispatcherData (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ );
+
+/**
+ This routine parses the Dependency Expression, if available, and
+ decides if the module can be executed.
+
+
+ @param Private PeiCore's private data structure
+ @param FileHandle PEIM's file handle
+ @param PeimCount The index of last dispatched PEIM.
+
+ @retval TRUE Can be dispatched
+ @retval FALSE Cannot be dispatched
+
+**/
+BOOLEAN
+DepexSatisfied (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN PeimCount
+ );
+
+//
+// PPI support functions
+//
+/**
+
+ Initialize PPI services.
+
+ @param PrivateData Pointer to the PEI Core data.
+ @param OldCoreData Pointer to old PEI Core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializePpiServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+
+ Migrate the Hob list from the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertPpiPointers (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+
+ Install PPI services. It is implementation of EFI_PEI_SERVICE.InstallPpi.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to ppi array that want to be installed.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ );
+
+/**
+
+ Re-Install PPI services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldPpi Pointer to the old PEI PPI Descriptors.
+ @param NewPpi Pointer to the new PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if the operation was successful
+ @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
+ if NewPpi is not valid
+ @retval EFI_NOT_FOUND if the PPI was not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
+ );
+
+/**
+
+ Locate a given named PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Guid Pointer to GUID of the PPI.
+ @param Instance Instance Number to discover.
+ @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
+ returns a pointer to the descriptor (includes flags, etc)
+ @param Ppi Pointer to reference the found PPI
+
+ @retval EFI_SUCCESS if the PPI is in the database
+ @retval EFI_NOT_FOUND if the PPI is not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLocatePpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ IN OUT VOID **Ppi
+ );
+
+/**
+
+ Install a notification for a given PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good decriptor
+
+**/
+EFI_STATUS
+EFIAPI
+PeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
+ );
+
+/**
+
+ Process the Notify List at dispatch level.
+
+ @param PrivateData PeiCore's private data structure.
+
+**/
+VOID
+ProcessNotifyList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+
+ Dispatch notifications.
+
+ @param PrivateData PeiCore's private data structure
+ @param NotifyType Type of notify to fire.
+ @param InstallStartIndex Install Beginning index.
+ @param InstallStopIndex Install Ending index.
+ @param NotifyStartIndex Notify Beginning index.
+ @param NotifyStopIndex Notify Ending index.
+
+**/
+VOID
+DispatchNotify (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN NotifyType,
+ IN INTN InstallStartIndex,
+ IN INTN InstallStopIndex,
+ IN INTN NotifyStartIndex,
+ IN INTN NotifyStopIndex
+ );
+
+/**
+ Process PpiList from SEC phase.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ These PPI's will be installed and/or immediately signaled if they are notification type.
+
+**/
+VOID
+ProcessPpiListFromSec (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ );
+
+//
+// Boot mode support functions
+//
+/**
+ This service enables PEIMs to ascertain the present value of the boot mode.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode A pointer to contain the value of the boot mode.
+
+ @retval EFI_SUCCESS The boot mode was returned successfully.
+ @retval EFI_INVALID_PARAMETER BootMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT EFI_BOOT_MODE *BootMode
+ );
+
+/**
+ This service enables PEIMs to update the boot mode variable.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode The value of the boot mode to set.
+
+ @return EFI_SUCCESS The value was successfully updated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_BOOT_MODE BootMode
+ );
+
+//
+// Security support functions
+//
+/**
+
+ Initialize the security services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldCoreData Pointer to the old core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializeSecurityServices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+ Verify a Firmware volume.
+
+ @param CurrentFvAddress Pointer to the current Firmware Volume under consideration
+
+ @retval EFI_SUCCESS Firmware Volume is legal
+ @retval EFI_SECURITY_VIOLATION Firmware Volume fails integrity test
+
+**/
+EFI_STATUS
+VerifyFv (
+ IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress
+ );
+
+/**
+ Provide a callout to the security verification service.
+
+ @param PrivateData PeiCore's private data structure
+ @param VolumeHandle Handle of FV
+ @param FileHandle Handle of PEIM's ffs
+ @param AuthenticationStatus Authentication status
+
+ @retval EFI_SUCCESS Image is OK
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval EFI_NOT_FOUND If security PPI is not installed.
+**/
+EFI_STATUS
+VerifyPeim (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT32 AuthenticationStatus
+ );
+
+/**
+
+ Gets the pointer to the HOB List.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param HobList Pointer to the HOB List.
+
+ @retval EFI_SUCCESS Get the pointer of HOB List
+ @retval EFI_NOT_AVAILABLE_YET the HOB List is not yet published
+ @retval EFI_INVALID_PARAMETER HobList is NULL (in debug mode)
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetHobList (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **HobList
+ );
+
+/**
+ Add a new HOB to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Type Type of the new HOB.
+ @param Length Length of the new HOB to allocate.
+ @param Hob Pointer to the new HOB.
+
+ @return EFI_SUCCESS Success to create hob.
+ @retval EFI_INVALID_PARAMETER if Hob is NULL
+ @retval EFI_NOT_AVAILABLE_YET if HobList is still not available.
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCreateHob (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT16 Type,
+ IN UINT16 Length,
+ IN OUT VOID **Hob
+ );
+
+/**
+
+ Builds a Handoff Information Table HOB
+
+ @param BootMode - Current Bootmode
+ @param MemoryBegin - Start Memory Address.
+ @param MemoryLength - Length of Memory.
+
+ @return EFI_SUCCESS Always success to initialize HOB.
+
+**/
+EFI_STATUS
+PeiCoreBuildHobHandoffInfoTable (
+ IN EFI_BOOT_MODE BootMode,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ );
+
+/**
+ Install SEC HOB data to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SecHobList Pointer to SEC HOB List.
+
+ @return EFI_SUCCESS Success to install SEC HOB data.
+ @retval EFI_OUT_OF_RESOURCES If there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+PeiInstallSecHobData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_HOB_GENERIC_HEADER *SecHobList
+ );
+
+
+//
+// FFS Fw Volume support functions
+//
+/**
+ Searches for the next matching file in the firmware volume.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FvHandle Handle of firmware volume in which to search.
+ @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
+ at the beginning of the firmware volume. On exit, points the file handle of the next file
+ in the volume or NULL if there are no more files.
+
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+ @retval EFI_SUCCESS The file was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextFile (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param SectionType Filter to find only sections of this type.
+ @param FileHandle Pointer to the current file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ NULL if section not found
+
+ @retval EFI_NOT_FOUND The section was not found.
+ @retval EFI_SUCCESS The section was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ );
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType The value of the section type to find.
+ @param SectionInstance Section instance to find.
+ @param FileHandle Handle of the firmware file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ @param AuthenticationStatus A pointer to the authentication status for this section.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData3 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Search the firmware volumes by index
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
+ Volume (BFV).
+ @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
+ @retval EFI_NOT_FOUND The volume was not found.
+ @retval EFI_SUCCESS The volume was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextVolume (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ );
+
+//
+// Memory support functions
+//
+/**
+
+ Initialize the memory services.
+
+ @param PrivateData PeiCore's private data structure
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param OldCoreData Pointer to the PEI Core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializeMemoryServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+
+ Install the permanent memory is now available.
+ Creates HOB (PHIT and Stack).
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryBegin Start of memory address.
+ @param MemoryLength Length of memory.
+
+ @return EFI_SUCCESS Always success.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPeiMemory (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ );
+
+/**
+ Migrate memory pages allocated in pre-memory phase.
+ Copy memory pages at temporary heap top to permanent heap top.
+
+ @param[in] Private Pointer to the private data passed in from caller.
+ @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
+
+**/
+VOID
+MigrateMemoryPages (
+ IN PEI_CORE_INSTANCE *Private,
+ IN BOOLEAN TemporaryRamMigrated
+ );
+
+/**
+ Migrate MemoryBaseAddress in memory allocation HOBs
+ from the temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertMemoryAllocationHobs (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+ The purpose of the service is to publish an interface that allows
+ PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+ Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+ After InstallPeiMemory() is called, PEI will allocate pages within the region
+ of memory provided by InstallPeiMemory() service in a best-effort fashion.
+ Location-specific allocations are not managed by the PEI foundation code.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+ EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+ EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees memory pages.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] Memory The base physical address of the pages to be freed.
+ @param[in] Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFreePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ );
+
+/**
+
+ Memory allocation service on the temporary memory.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Size Amount of memory required
+ @param Buffer Address of pointer to the buffer
+
+ @retval EFI_SUCCESS The allocation was successful
+ @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
+ to allocate the requested size.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePool (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+
+ Routine for load image file.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param PeimState The dispatch state of the input PEIM handle.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate necessary PPI
+ @retval Others Fail to load file.
+
+**/
+EFI_STATUS
+PeiLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT8 PeimState,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ );
+
+/**
+
+ Core version of the Status Code reporter
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Type of Status Code.
+ @param Value Value to output for Status Code.
+ @param Instance Instance Number of this status code.
+ @param CallerId ID of the caller of this status code.
+ @param Data Optional data associated with this status code.
+
+ @retval EFI_SUCCESS if status code is successfully reported
+ @retval EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReportStatusCode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+/**
+
+ Core version of the Reset System
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+
+ @retval EFI_NOT_AVAILABLE_YET PPI not available yet.
+ @retval EFI_DEVICE_ERROR Did not reset system.
+ Otherwise, resets the system.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiResetSystem (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset. ResetData is only valid if ResetStatus is something
+ other than EFI_SUCCESS unless the ResetType is EfiResetPlatformSpecific
+ where a minimum amount of ResetData is always required.
+
+**/
+VOID
+EFIAPI
+PeiResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ );
+
+/**
+
+ Initialize PeiCore Fv List.
+
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
+
+**/
+VOID
+PeiInitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ );
+
+/**
+ Process Firmware Volum Information once FvInfoPPI install.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS if the interface could be successfully installed
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolmeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+
+ Given the input VolumeHandle, search for the next matching name file.
+
+ @param FileName File name to search.
+ @param VolumeHandle The current FV to search.
+ @param FileHandle Pointer to the file matching name in VolumeHandle.
+ NULL if file not found
+
+ @retval EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ );
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo2 (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ );
+
+/**
+ Returns information about the specified volume.
+
+ @param VolumeHandle Handle of the volume.
+ @param VolumeInfo Upon exit, points to the volume's information.
+
+ @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
+ @retval EFI_INVALID_PARAMETER If VolumeInfo is NULL.
+ @retval EFI_SUCCESS Volume information returned.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ );
+
+/**
+ This routine enable a PEIM to register itself to shadow when PEI Foundation
+ discovery permanent memory.
+
+ @param FileHandle File handle of a PEIM.
+
+ @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
+ @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
+ @retval EFI_SUCCESS Successfully to register itself.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterForShadow (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ );
+
+/**
+ Initialize image service that install PeiLoadFilePpi.
+
+ @param PrivateData Pointer to PeiCore's private data structure PEI_CORE_INSTANCE.
+ @param OldCoreData Pointer to Old PeiCore's private data.
+ If NULL, PeiCore is entered at first time, stack/heap in temporary memory.
+ If not NULL, PeiCore is entered at second time, stack/heap has been moved
+ to permanent memory.
+
+**/
+VOID
+InitializeImageServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+ The wrapper function of PeiLoadImageLoadImage().
+
+ @param This Pointer to EFI_PEI_LOAD_FILE_PPI.
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param ImageAddressArg Pointer to PE/TE image.
+ @param ImageSizeArg Size of PE/TE image.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState Pointer to attestation authentication state of image.
+
+ @return Status of PeiLoadImageLoadImage().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadImageLoadImageWrapper (
+ IN CONST EFI_PEI_LOAD_FILE_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ );
+
+/**
+
+ Provide a callback for when the security PPI is installed.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor The descriptor for the notification event.
+ @param Ppi Pointer to the PPI in question.
+
+ @return Always success
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Get Fv image from the FV type file, then install FV INFO(2) ppi, Build FV hob.
+
+ @param PrivateData PeiCore's private data structure
+ @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
+ @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
+
+**/
+EFI_STATUS
+ProcessFvFile (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
+ IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
+ );
+
+/**
+ Get instance of PEI_CORE_FV_HANDLE for next volume according to given index.
+
+ This routine also will install FvInfo ppi for FV hob in PI ways.
+
+ @param Private Pointer of PEI_CORE_INSTANCE
+ @param Instance The index of FV want to be searched.
+
+ @return Instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FindNextCoreFvHandle (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN Instance
+ );
+
+//
+// Default EFI_PEI_CPU_IO_PPI support for EFI_PEI_SERVICES table when PeiCore initialization.
+//
+
+/**
+ Memory-based read services.
+
+ This function is to perform the Memory Access Read service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Memory-based write services.
+
+ This function is to perform the Memory Access Write service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ IO-based read services.
+
+ This function is to perform the IO-base read service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ IO-based write services.
+
+ This function is to perform the IO-base write service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ 8-bit I/O read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the I/O space.
+**/
+UINT8
+EFIAPI
+PeiDefaultIoRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 16-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 16-bit value returned from the I/O space.
+**/
+UINT16
+EFIAPI
+PeiDefaultIoRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 32-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 32-bit value returned from the I/O space.
+**/
+UINT32
+EFIAPI
+PeiDefaultIoRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 64-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 64-bit value returned from the I/O space.
+**/
+UINT64
+EFIAPI
+PeiDefaultIoRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 8-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ );
+
+/**
+ 16-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ );
+
+/**
+ 32-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ );
+
+/**
+ 64-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ );
+
+/**
+ 8-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the memory space.
+
+**/
+UINT8
+EFIAPI
+PeiDefaultMemRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 16-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 16-bit value returned from the memory space.
+
+**/
+UINT16
+EFIAPI
+PeiDefaultMemRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 32-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 32-bit value returned from the memory space.
+
+**/
+UINT32
+EFIAPI
+PeiDefaultMemRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 64-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 64-bit value returned from the memory space.
+
+**/
+UINT64
+EFIAPI
+PeiDefaultMemRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 8-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ );
+
+/**
+ 16-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ );
+
+/**
+ 32-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ );
+
+/**
+ 64-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ );
+
+extern EFI_PEI_CPU_IO_PPI gPeiDefaultCpuIoPpi;
+
+//
+// Default EFI_PEI_PCI_CFG2_PPI support for EFI_PEI_SERVICES table when PeiCore initialization.
+//
+
+/**
+ Reads from a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Read (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Write to a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Write (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ This function performs a read-modify-write operation on the contents from a given
+ location in the PCI configuration space.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes. Type
+ EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
+ @param Address The physical address of the access.
+ @param SetBits Points to value to bitwise-OR with the read configuration value.
+ The size of the value is determined by Width.
+ @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
+ The size of the value is determined by Width.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Modify (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *SetBits,
+ IN VOID *ClearBits
+ );
+
+extern EFI_PEI_PCI_CFG2_PPI gPeiDefaultPciCfg2Ppi;
+
+/**
+ After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
+ be re-installed with the instance in permanent memory and all cached FvPpi pointers in
+ PrivateData->Fv[] array should be fixed up to be pointed to the one in permanent
+ memory.
+
+ @param PrivateData Pointer to PEI_CORE_INSTANCE.
+**/
+VOID
+PeiReinitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+#endif
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf
new file mode 100644
index 0000000000..7d9cdaa2f0
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -0,0 +1,136 @@
+## @file
+# PeiMain module is core module in PEI phase.
+#
+# It takes responsibilities of:
+# 1) Initialize memory, PPI, image services etc, to establish PEIM runtime environment.
+# 2) Dispatch PEIM from discovered FV.
+# 3) Handoff control to DxeIpl to load DXE core and enter DXE phase.
+#
+# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCore
+ MODULE_UNI_FILE = PeiCore.uni
+ FILE_GUID = 52C05B14-0B98-496c-BC3B-04B50211D680
+ MODULE_TYPE = PEI_CORE
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeiCore
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ StatusCode/StatusCode.c
+ Security/Security.c
+ Reset/Reset.c
+ Ppi/Ppi.c
+ PeiMain/PeiMain.c
+ Memory/MemoryServices.c
+ Image/Image.c
+ Hob/Hob.c
+ FwVol/FwVol.c
+ FwVol/FwVol.h
+ Dispatcher/Dispatcher.c
+ Dependency/Dependency.c
+ Dependency/Dependency.h
+ BootMode/BootMode.c
+ CpuIo/CpuIo.c
+ PciCfg2/PciCfg2.c
+ PeiMain.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PeCoffGetEntryPointLib
+ ReportStatusCodeLib
+ PeiServicesLib
+ PerformanceLib
+ HobLib
+ BaseLib
+ PeiCoreEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ CacheMaintenanceLib
+ PeCoffLib
+ PeiServicesTablePointerLib
+ PcdLib
+
+[Guids]
+ gPeiAprioriFileNameGuid ## SOMETIMES_CONSUMES ## File
+ ## PRODUCES ## UNDEFINED # Install ppi
+ ## CONSUMES ## UNDEFINED # Locate ppi
+ gEfiFirmwareFileSystem2Guid
+ ## PRODUCES ## UNDEFINED # Install ppi
+ ## CONSUMES ## UNDEFINED # Locate ppi
+ ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gEfiFirmwareFileSystem3Guid
+
+[Ppis]
+ gEfiPeiStatusCodePpiGuid ## SOMETIMES_CONSUMES # PeiReportStatusService is not ready if this PPI doesn't exist
+ gEfiPeiResetPpiGuid ## SOMETIMES_CONSUMES # PeiResetService is not ready if this PPI doesn't exist
+ gEfiDxeIplPpiGuid ## CONSUMES
+ gEfiPeiMemoryDiscoveredPpiGuid ## PRODUCES
+ gEfiPeiDecompressPpiGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_PRODUCES # Produce FvInfoPpi if the encapsulated FvImage is found
+ gEfiPeiFirmwareVolumeInfoPpiGuid
+ ## NOTIFY
+ ## SOMETIMES_PRODUCES # Produce FvInfoPpi2 if the encapsulated FvImage is found
+ gEfiPeiFirmwareVolumeInfo2PpiGuid
+ ## PRODUCES
+ ## CONSUMES
+ gEfiPeiLoadFilePpiGuid
+ gEfiPeiSecurity2PpiGuid ## NOTIFY
+ gEfiTemporaryRamSupportPpiGuid ## SOMETIMES_CONSUMES
+ gEfiTemporaryRamDonePpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiReset2PpiGuid ## SOMETIMES_CONSUMES
+ gEfiSecHobDataPpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnS3Boot ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack ## CONSUMES
+
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+
+# [Hob]
+# PHIT ## PRODUCES
+# RESOURCE_DESCRIPTOR ## SOMETIMES_PRODUCES
+# RESOURCE_DESCRIPTOR ## SOMETIMES_CONSUMES
+# MEMORY_ALLOCATION ## SOMETIMES_CONSUMES
+# FIRMWARE_VOLUME ## SOMETIMES_PRODUCES
+# FIRMWARE_VOLUME ## SOMETIMES_CONSUMES
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES
+# MEMORY_ALLOCATION ## PRODUCES # MEMORY_ALLOCATION_STACK
+# UNDEFINED ## PRODUCES # MEMORY_POOL
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiCoreExtra.uni
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
new file mode 100644
index 0000000000..3cd61906c3
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
@@ -0,0 +1,480 @@
+/** @file
+ Pei Core Main Entry Point
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+EFI_PEI_PPI_DESCRIPTOR mMemoryDiscoveredPpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ NULL
+};
+
+///
+/// Pei service instance
+///
+EFI_PEI_SERVICES gPs = {
+ {
+ PEI_SERVICES_SIGNATURE,
+ PEI_SERVICES_REVISION,
+ sizeof (EFI_PEI_SERVICES),
+ 0,
+ 0
+ },
+ PeiInstallPpi,
+ PeiReInstallPpi,
+ PeiLocatePpi,
+ PeiNotifyPpi,
+
+ PeiGetBootMode,
+ PeiSetBootMode,
+
+ PeiGetHobList,
+ PeiCreateHob,
+
+ PeiFfsFindNextVolume,
+ PeiFfsFindNextFile,
+ PeiFfsFindSectionData,
+
+ PeiInstallPeiMemory,
+ PeiAllocatePages,
+ PeiAllocatePool,
+ (EFI_PEI_COPY_MEM)CopyMem,
+ (EFI_PEI_SET_MEM)SetMem,
+
+ PeiReportStatusCode,
+ PeiResetSystem,
+
+ &gPeiDefaultCpuIoPpi,
+ &gPeiDefaultPciCfg2Ppi,
+
+ PeiFfsFindFileByName,
+ PeiFfsGetFileInfo,
+ PeiFfsGetVolumeInfo,
+ PeiRegisterForShadow,
+ PeiFfsFindSectionData3,
+ PeiFfsGetFileInfo2,
+ PeiResetSystem2,
+ PeiFreePages,
+};
+
+/**
+ Shadow PeiCore module from flash to installed memory.
+
+ @param PrivateData PeiCore's private data structure
+
+ @return PeiCore function address after shadowing.
+**/
+PEICORE_FUNCTION_POINTER
+ShadowPeiCore (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_STATUS Status;
+ UINT32 AuthenticationState;
+
+ PeiCoreFileHandle = NULL;
+
+ //
+ // Find the PEI Core in the BFV
+ //
+ Status = PrivateData->Fv[0].FvPpi->FindFileByType (
+ PrivateData->Fv[0].FvPpi,
+ EFI_FV_FILETYPE_PEI_CORE,
+ PrivateData->Fv[0].FvHandle,
+ &PeiCoreFileHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Shadow PEI Core into memory so it will run faster
+ //
+ Status = PeiLoadImage (
+ GetPeiServicesTablePointer (),
+ *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle),
+ PEIM_STATE_REGISITER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Compute the PeiCore's function address after shaowed PeiCore.
+ // _ModuleEntryPoint is PeiCore main function entry
+ //
+ return (PEICORE_FUNCTION_POINTER)((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);
+}
+
+/**
+ This routine is invoked by main entry of PeiMain module during transition
+ from SEC to PEI. After switching stack in the PEI core, it will restart
+ with the old core data.
+
+ @param SecCoreDataPtr 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.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. 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
+ @param Data Pointer to old core data that is used to initialize the
+ core's data areas.
+ If NULL, it is first PeiCore entering.
+
+**/
+VOID
+EFIAPI
+PeiCore (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreDataPtr,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN VOID *Data
+ )
+{
+ PEI_CORE_INSTANCE PrivateData;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_SEC_PEI_HAND_OFF NewSecCoreData;
+ EFI_STATUS Status;
+ PEI_CORE_TEMP_POINTERS TempPtr;
+ PEI_CORE_INSTANCE *OldCoreData;
+ EFI_PEI_CPU_IO_PPI *CpuIo;
+ EFI_PEI_PCI_CFG2_PPI *PciCfg;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
+ EFI_PEI_TEMPORARY_RAM_DONE_PPI *TemporaryRamDonePpi;
+ UINTN Index;
+
+ //
+ // Retrieve context passed into PEI Core
+ //
+ OldCoreData = (PEI_CORE_INSTANCE *) Data;
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *) SecCoreDataPtr;
+
+ //
+ // Perform PEI Core phase specific actions.
+ //
+ if (OldCoreData == NULL) {
+ //
+ // If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
+ //
+ ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
+ PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
+ CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
+ } else {
+ //
+ // Memory is available to the PEI Core. See if the PEI Core has been shadowed to memory yet.
+ //
+ if (OldCoreData->ShadowedPeiCore == NULL) {
+ //
+ // Fixup the PeiCore's private data
+ //
+ OldCoreData->Ps = &OldCoreData->ServiceTableShadow;
+ OldCoreData->CpuIo = &OldCoreData->ServiceTableShadow.CpuIo;
+ if (OldCoreData->HeapOffsetPositive) {
+ OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw + OldCoreData->HeapOffset);
+ OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo + OldCoreData->HeapOffset);
+ OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles + OldCoreData->HeapOffset);
+ OldCoreData->PpiData.PpiListPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiListPtrs + OldCoreData->HeapOffset);
+ OldCoreData->Fv = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv + OldCoreData->HeapOffset);
+ for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
+ OldCoreData->Fv[Index].PeimState = (UINT8 *) OldCoreData->Fv[Index].PeimState + OldCoreData->HeapOffset;
+ OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles + OldCoreData->HeapOffset);
+ }
+ OldCoreData->FileGuid = (EFI_GUID *) ((UINT8 *) OldCoreData->FileGuid + OldCoreData->HeapOffset);
+ OldCoreData->FileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->FileHandles + OldCoreData->HeapOffset);
+ } else {
+ OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw - OldCoreData->HeapOffset);
+ OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo - OldCoreData->HeapOffset);
+ OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles - OldCoreData->HeapOffset);
+ OldCoreData->PpiData.PpiListPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiListPtrs - OldCoreData->HeapOffset);
+ OldCoreData->Fv = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv - OldCoreData->HeapOffset);
+ for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
+ OldCoreData->Fv[Index].PeimState = (UINT8 *) OldCoreData->Fv[Index].PeimState - OldCoreData->HeapOffset;
+ OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles - OldCoreData->HeapOffset);
+ }
+ OldCoreData->FileGuid = (EFI_GUID *) ((UINT8 *) OldCoreData->FileGuid - OldCoreData->HeapOffset);
+ OldCoreData->FileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->FileHandles - OldCoreData->HeapOffset);
+ }
+
+ //
+ // Fixup for PeiService's address
+ //
+ SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Update HandOffHob for new installed permanent memory
+ //
+ HandoffInformationTable = OldCoreData->HobList.HandoffInformationTable;
+ if (OldCoreData->HeapOffsetPositive) {
+ HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList + OldCoreData->HeapOffset;
+ } else {
+ HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList - OldCoreData->HeapOffset;
+ }
+ HandoffInformationTable->EfiMemoryTop = OldCoreData->PhysicalMemoryBegin + OldCoreData->PhysicalMemoryLength;
+ HandoffInformationTable->EfiMemoryBottom = OldCoreData->PhysicalMemoryBegin;
+ HandoffInformationTable->EfiFreeMemoryTop = OldCoreData->FreePhysicalMemoryTop;
+ HandoffInformationTable->EfiFreeMemoryBottom = HandoffInformationTable->EfiEndOfHobList + sizeof (EFI_HOB_GENERIC_HEADER);
+
+ //
+ // We need convert MemoryBaseAddress in memory allocation HOBs
+ //
+ ConvertMemoryAllocationHobs (OldCoreData);
+
+ //
+ // We need convert the PPI descriptor's pointer
+ //
+ ConvertPpiPointers (SecCoreData, OldCoreData);
+
+ //
+ // After the whole temporary memory is migrated, then we can allocate page in
+ // permanent memory.
+ //
+ OldCoreData->PeiMemoryInstalled = TRUE;
+
+ //
+ // Indicate that PeiCore reenter
+ //
+ OldCoreData->PeimDispatcherReenter = TRUE;
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (OldCoreData->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ //
+ // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.
+ // Every bit in the array indicate the status of the corresponding memory page available or not
+ //
+ OldCoreData->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32(PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof(UINT64));
+ }
+
+ //
+ // Shadow PEI Core. When permanent memory is avaiable, shadow
+ // PEI Core and PEIMs to get high performance.
+ //
+ OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER) (UINTN) PeiCore;
+ if ((HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnS3Boot))
+ || (HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnBoot))) {
+ OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
+ }
+
+ //
+ // PEI Core has now been shadowed to memory. Restart PEI Core in memory.
+ //
+ OldCoreData->ShadowedPeiCore (SecCoreData, PpiList, OldCoreData);
+
+ //
+ // Should never reach here.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop();
+
+ UNREACHABLE ();
+ }
+
+ //
+ // Memory is available to the PEI Core and the PEI Core has been shadowed to memory.
+ //
+ CopyMem (&NewSecCoreData, SecCoreDataPtr, sizeof (NewSecCoreData));
+ SecCoreData = &NewSecCoreData;
+
+ CopyMem (&PrivateData, OldCoreData, sizeof (PrivateData));
+
+ CpuIo = (VOID*)PrivateData.ServiceTableShadow.CpuIo;
+ PciCfg = (VOID*)PrivateData.ServiceTableShadow.PciCfg;
+
+ CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
+
+ PrivateData.ServiceTableShadow.CpuIo = CpuIo;
+ PrivateData.ServiceTableShadow.PciCfg = PciCfg;
+ }
+
+ //
+ // Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
+ //
+ PrivateData.Ps = &PrivateData.ServiceTableShadow;
+
+ //
+ // Save PeiServicePointer so that it can be retrieved anywhere.
+ //
+ SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
+
+ //
+ // Initialize PEI Core Services
+ //
+ InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
+ if (OldCoreData == NULL) {
+ //
+ // Initialize PEI Core Private Data Buffer
+ //
+ PrivateData.PpiData.PpiListPtrs = AllocateZeroPool (sizeof (PEI_PPI_LIST_POINTERS) * PcdGet32 (PcdPeiCoreMaxPpiSupported));
+ ASSERT (PrivateData.PpiData.PpiListPtrs != NULL);
+ PrivateData.Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (PrivateData.Fv != NULL);
+ PrivateData.Fv[0].PeimState = AllocateZeroPool (sizeof (UINT8) * PcdGet32 (PcdPeiCoreMaxPeimPerFv) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (PrivateData.Fv[0].PeimState != NULL);
+ PrivateData.Fv[0].FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (PrivateData.Fv[0].FvFileHandles != NULL);
+ for (Index = 1; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
+ PrivateData.Fv[Index].PeimState = PrivateData.Fv[Index - 1].PeimState + PcdGet32 (PcdPeiCoreMaxPeimPerFv);
+ PrivateData.Fv[Index].FvFileHandles = PrivateData.Fv[Index - 1].FvFileHandles + PcdGet32 (PcdPeiCoreMaxPeimPerFv);
+ }
+ PrivateData.UnknownFvInfo = AllocateZeroPool (sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (PrivateData.UnknownFvInfo != NULL);
+ PrivateData.CurrentFvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
+ ASSERT (PrivateData.CurrentFvFileHandles != NULL);
+ PrivateData.FileGuid = AllocatePool (sizeof (EFI_GUID) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
+ ASSERT (PrivateData.FileGuid != NULL);
+ PrivateData.FileHandles = AllocatePool (sizeof (EFI_PEI_FILE_HANDLE) * (PcdGet32 (PcdPeiCoreMaxPeimPerFv) + 1));
+ ASSERT (PrivateData.FileHandles != NULL);
+ }
+ InitializePpiServices (&PrivateData, OldCoreData);
+
+ //
+ // Update performance measurements
+ //
+ if (OldCoreData == NULL) {
+ PERF_START (NULL, "SEC", NULL, 1);
+ PERF_END (NULL, "SEC", NULL, 0);
+
+ //
+ // If first pass, start performance measurement.
+ //
+ PERF_START (NULL,"PEI", NULL, 0);
+ PERF_START (NULL,"PreMem", NULL, 0);
+
+ } else {
+ PERF_END (NULL,"PreMem", NULL, 0);
+ PERF_START (NULL,"PostMem", NULL, 0);
+ }
+
+ //
+ // Complete PEI Core Service initialization
+ //
+ InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
+ InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);
+ InitializeImageServices (&PrivateData, OldCoreData);
+
+ //
+ // Perform PEI Core Phase specific actions
+ //
+ if (OldCoreData == NULL) {
+ //
+ // Report Status Code EFI_SW_PC_INIT
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
+ );
+
+ //
+ // If SEC provided the PpiList, process it.
+ //
+ if (PpiList != NULL) {
+ ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **) &PrivateData.Ps, PpiList);
+ }
+ } else {
+ //
+ // Try to locate Temporary RAM Done Ppi.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiTemporaryRamDonePpiGuid,
+ 0,
+ NULL,
+ (VOID**)&TemporaryRamDonePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Disable the use of Temporary RAM after the transition from Temporary RAM to Permanent RAM is complete.
+ //
+ TemporaryRamDonePpi->TemporaryRamDone ();
+ }
+
+ //
+ // Alert any listeners that there is permanent memory available
+ //
+ PERF_START (NULL,"DisMem", NULL, 0);
+ Status = PeiServicesInstallPpi (&mMemoryDiscoveredPpi);
+
+ //
+ // Process the Notify list and dispatch any notifies for the Memory Discovered PPI
+ //
+ ProcessNotifyList (&PrivateData);
+
+ PERF_END (NULL,"DisMem", NULL, 0);
+ }
+
+ //
+ // Call PEIM dispatcher
+ //
+ PeiDispatcher (SecCoreData, &PrivateData);
+
+ if (PrivateData.HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) {
+ //
+ // Check if InstallPeiMemory service was called on non-S3 resume boot path.
+ //
+ ASSERT(PrivateData.PeiMemoryInstalled == TRUE);
+ }
+
+ //
+ // Measure PEI Core execution time.
+ //
+ PERF_END (NULL, "PostMem", NULL, 0);
+
+ //
+ // Lookup DXE IPL PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiDxeIplPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&TempPtr.DxeIpl
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Report status code to indicate DXE IPL PPI could not be found.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND)
+ );
+ CpuDeadLoop ();
+ }
+
+ //
+ // Enter DxeIpl to load Dxe core.
+ //
+ DEBUG ((EFI_D_INFO, "DXE IPL Entry\n"));
+ Status = TempPtr.DxeIpl->Entry (
+ TempPtr.DxeIpl,
+ &PrivateData.Ps,
+ PrivateData.HobList
+ );
+ //
+ // Should never reach here.
+ //
+ ASSERT_EFI_ERROR (Status);
+ CpuDeadLoop();
+
+ UNREACHABLE ();
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c
new file mode 100644
index 0000000000..082c379458
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c
@@ -0,0 +1,787 @@
+/** @file
+ EFI PEI Core PPI services
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Initialize PPI services.
+
+ @param PrivateData Pointer to the PEI Core data.
+ @param OldCoreData Pointer to old PEI Core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializePpiServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ PrivateData->PpiData.NotifyListEnd = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
+ PrivateData->PpiData.DispatchListEnd = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
+ PrivateData->PpiData.LastDispatchedNotify = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
+ }
+}
+
+/**
+
+ Migrate Single PPI Pointer from the temporary memory to PEI installed memory.
+
+ @param PpiPointer Pointer to Ppi
+ @param TempBottom Base of old temporary memory
+ @param TempTop Top of old temporary memory
+ @param Offset Offset of new memory to old temporary memory.
+ @param OffsetPositive Positive flag of Offset value.
+
+**/
+VOID
+ConvertSinglePpiPointer (
+ IN PEI_PPI_LIST_POINTERS *PpiPointer,
+ IN UINTN TempBottom,
+ IN UINTN TempTop,
+ IN UINTN Offset,
+ IN BOOLEAN OffsetPositive
+ )
+{
+ if (((UINTN)PpiPointer->Raw < TempTop) &&
+ ((UINTN)PpiPointer->Raw >= TempBottom)) {
+ //
+ // Convert the pointer to the PPI descriptor from the old TempRam
+ // to the relocated physical memory.
+ //
+ if (OffsetPositive) {
+ PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw + Offset);
+ } else {
+ PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw - Offset);
+ }
+
+ //
+ // Only when the PEIM descriptor is in the old TempRam should it be necessary
+ // to try to convert the pointers in the PEIM descriptor
+ //
+
+ if (((UINTN)PpiPointer->Ppi->Guid < TempTop) &&
+ ((UINTN)PpiPointer->Ppi->Guid >= TempBottom)) {
+ //
+ // Convert the pointer to the GUID in the PPI or NOTIFY descriptor
+ // from the old TempRam to the relocated physical memory.
+ //
+ if (OffsetPositive) {
+ PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid + Offset);
+ } else {
+ PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid - Offset);
+ }
+ }
+
+ //
+ // Convert the pointer to the PPI interface structure in the PPI descriptor
+ // from the old TempRam to the relocated physical memory.
+ //
+ if ((UINTN)PpiPointer->Ppi->Ppi < TempTop &&
+ (UINTN)PpiPointer->Ppi->Ppi >= TempBottom) {
+ if (OffsetPositive) {
+ PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi + Offset);
+ } else {
+ PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi - Offset);
+ }
+ }
+ }
+}
+
+/**
+
+ Migrate PPI Pointers from the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertPpiPointers (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ UINT8 Index;
+ UINT8 IndexHole;
+
+ for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxPpiSupported); Index++) {
+ if (Index < PrivateData->PpiData.PpiListEnd || Index > PrivateData->PpiData.NotifyListEnd) {
+ if (PrivateData->MemoryPages.Size != 0) {
+ //
+ // Convert PPI pointer in old memory pages
+ // It needs to be done before Convert PPI pointer in old Heap
+ //
+ ConvertSinglePpiPointer (
+ &PrivateData->PpiData.PpiListPtrs[Index],
+ (UINTN)PrivateData->MemoryPages.Base,
+ (UINTN)PrivateData->MemoryPages.Base + PrivateData->MemoryPages.Size,
+ PrivateData->MemoryPages.Offset,
+ PrivateData->MemoryPages.OffsetPositive
+ );
+ }
+
+ //
+ // Convert PPI pointer in old Heap
+ //
+ ConvertSinglePpiPointer (
+ &PrivateData->PpiData.PpiListPtrs[Index],
+ (UINTN)SecCoreData->PeiTemporaryRamBase,
+ (UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
+ PrivateData->HeapOffset,
+ PrivateData->HeapOffsetPositive
+ );
+
+ //
+ // Convert PPI pointer in old Stack
+ //
+ ConvertSinglePpiPointer (
+ &PrivateData->PpiData.PpiListPtrs[Index],
+ (UINTN)SecCoreData->StackBase,
+ (UINTN)SecCoreData->StackBase + SecCoreData->StackSize,
+ PrivateData->StackOffset,
+ PrivateData->StackOffsetPositive
+ );
+
+ //
+ // Convert PPI pointer in old TempRam Hole
+ //
+ for (IndexHole = 0; IndexHole < HOLE_MAX_NUMBER; IndexHole ++) {
+ if (PrivateData->HoleData[IndexHole].Size == 0) {
+ continue;
+ }
+
+ ConvertSinglePpiPointer (
+ &PrivateData->PpiData.PpiListPtrs[Index],
+ (UINTN)PrivateData->HoleData[IndexHole].Base,
+ (UINTN)PrivateData->HoleData[IndexHole].Base + PrivateData->HoleData[IndexHole].Size,
+ PrivateData->HoleData[IndexHole].Offset,
+ PrivateData->HoleData[IndexHole].OffsetPositive
+ );
+ }
+ }
+ }
+}
+
+/**
+
+ This function installs an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties
+ can use to call additional PEIMs.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to a list of PEI PPI Descriptors.
+ @param Single TRUE if only single entry in the PpiList.
+ FALSE if the PpiList is ended with an entry which has the
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+InternalPeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN BOOLEAN Single
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+ INTN LastCallbackInstall;
+
+
+ if (PpiList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ Index = PrivateData->PpiData.PpiListEnd;
+ LastCallbackInstall = Index;
+
+ //
+ // This is loop installs all PPI descriptors in the PpiList. It is terminated
+ // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
+ // EFI_PEI_PPI_DESCRIPTOR in the list.
+ //
+
+ for (;;) {
+ //
+ // Since PpiData is used for NotifyList and PpiList, max resource
+ // is reached if the Install reaches the NotifyList
+ // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more PPI requirement.
+ //
+ if (Index == PrivateData->PpiData.NotifyListEnd + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Check if it is a valid PPI.
+ // If not, rollback list to exclude all in this list.
+ // Try to indicate which item failed.
+ //
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
+ PrivateData->PpiData.PpiListEnd = LastCallbackInstall;
+ DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
+ PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR*) PpiList;
+ PrivateData->PpiData.PpiListEnd++;
+
+ if (Single) {
+ //
+ // Only single entry in the PpiList.
+ //
+ break;
+ } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the PPI List.
+ //
+ break;
+ }
+ PpiList++;
+ Index++;
+ }
+
+ //
+ // Dispatch any callback level notifies for newly installed PPIs.
+ //
+ DispatchNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ LastCallbackInstall,
+ PrivateData->PpiData.PpiListEnd,
+ PrivateData->PpiData.DispatchListEnd,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function installs an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties
+ can use to call additional PEIMs.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to a list of PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ )
+{
+ return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
+}
+
+/**
+
+ This function reinstalls an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties can
+ use to replace an interface of the same name in the protocol database with a
+ different interface.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldPpi Pointer to the old PEI PPI Descriptors.
+ @param NewPpi Pointer to the new PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if the operation was successful
+ @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
+ @retval EFI_INVALID_PARAMETER if NewPpi is not valid
+ @retval EFI_NOT_FOUND if the PPI was not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+
+
+ if ((OldPpi == NULL) || (NewPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ //
+ // Find the old PPI instance in the database. If we can not find it,
+ // return the EFI_NOT_FOUND error.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
+ if (OldPpi == PrivateData->PpiData.PpiListPtrs[Index].Ppi) {
+ break;
+ }
+ }
+ if (Index == PrivateData->PpiData.PpiListEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Remove the old PPI from the database, add the new one.
+ //
+ DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
+ ASSERT (Index < (INTN)(PcdGet32 (PcdPeiCoreMaxPpiSupported)));
+ PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) NewPpi;
+
+ //
+ // Dispatch any callback level notifies for the newly installed PPI.
+ //
+ DispatchNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ Index,
+ Index+1,
+ PrivateData->PpiData.DispatchListEnd,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Locate a given named PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Guid Pointer to GUID of the PPI.
+ @param Instance Instance Number to discover.
+ @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
+ returns a pointer to the descriptor (includes flags, etc)
+ @param Ppi Pointer to reference the found PPI
+
+ @retval EFI_SUCCESS if the PPI is in the database
+ @retval EFI_NOT_FOUND if the PPI is not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLocatePpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ IN OUT VOID **Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+ EFI_GUID *CheckGuid;
+ EFI_PEI_PPI_DESCRIPTOR *TempPtr;
+
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ //
+ // Search the data base for the matching instance of the GUIDed PPI.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
+ TempPtr = PrivateData->PpiData.PpiListPtrs[Index].Ppi;
+ CheckGuid = TempPtr->Guid;
+
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID as INT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
+ (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
+ (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
+ (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3])) {
+ if (Instance == 0) {
+
+ if (PpiDescriptor != NULL) {
+ *PpiDescriptor = TempPtr;
+ }
+
+ if (Ppi != NULL) {
+ *Ppi = TempPtr->Ppi;
+ }
+
+
+ return EFI_SUCCESS;
+ }
+ Instance--;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ This function installs a notification service to be called back when a given
+ interface is installed or reinstalled. The purpose of the service is to publish
+ an interface that other parties can use to call additional PPIs that may materialize later.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+ @param Single TRUE if only single entry in the NotifyList.
+ FALSE if the NotifyList is ended with an entry which has the
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+InternalPeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
+ IN BOOLEAN Single
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+ INTN NotifyIndex;
+ INTN LastCallbackNotify;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyPtr;
+ UINTN NotifyDispatchCount;
+
+
+ NotifyDispatchCount = 0;
+
+ if (NotifyList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ Index = PrivateData->PpiData.NotifyListEnd;
+ LastCallbackNotify = Index;
+
+ //
+ // This is loop installs all Notify descriptors in the NotifyList. It is
+ // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
+ // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
+ //
+
+ for (;;) {
+ //
+ // Since PpiData is used for NotifyList and InstallList, max resource
+ // is reached if the Install reaches the PpiList
+ // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more Notify PPIs requirement.
+ //
+ if (Index == PrivateData->PpiData.PpiListEnd - 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // If some of the PPI data is invalid restore original Notify PPI database value
+ //
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
+ PrivateData->PpiData.NotifyListEnd = LastCallbackNotify;
+ DEBUG((EFI_D_ERROR, "ERROR -> InstallNotify: %g %p\n", NotifyList->Guid, NotifyList->Notify));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
+ NotifyDispatchCount ++;
+ }
+
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
+
+ PrivateData->PpiData.NotifyListEnd--;
+ DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
+ if (Single) {
+ //
+ // Only single entry in the NotifyList.
+ //
+ break;
+ } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the Notify List.
+ //
+ break;
+ }
+ //
+ // Go the next descriptor. Remember the NotifyList moves down.
+ //
+ NotifyList++;
+ Index--;
+ }
+
+ //
+ // If there is Dispatch Notify PPI installed put them on the bottom
+ //
+ if (NotifyDispatchCount > 0) {
+ for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) {
+ if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
+ NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify;
+
+ for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify;
+ }
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr;
+ PrivateData->PpiData.DispatchListEnd--;
+ }
+ }
+
+ LastCallbackNotify -= NotifyDispatchCount;
+ }
+
+ //
+ // Dispatch any callback level notifies for all previously installed PPIs.
+ //
+ DispatchNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ 0,
+ PrivateData->PpiData.PpiListEnd,
+ LastCallbackNotify,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function installs a notification service to be called back when a given
+ interface is installed or reinstalled. The purpose of the service is to publish
+ an interface that other parties can use to call additional PPIs that may materialize later.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+EFIAPI
+PeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
+ )
+{
+ return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
+}
+
+
+/**
+
+ Process the Notify List at dispatch level.
+
+ @param PrivateData PeiCore's private data structure.
+
+**/
+VOID
+ProcessNotifyList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ INTN TempValue;
+
+ while (TRUE) {
+ //
+ // Check if the PEIM that was just dispatched resulted in any
+ // Notifies getting installed. If so, go process any dispatch
+ // level Notifies that match the previouly installed PPIs.
+ // Use "while" instead of "if" since DispatchNotify can modify
+ // DispatchListEnd (with NotifyPpi) so we have to iterate until the same.
+ //
+ while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) {
+ TempValue = PrivateData->PpiData.DispatchListEnd;
+ DispatchNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ 0,
+ PrivateData->PpiData.LastDispatchedInstall,
+ PrivateData->PpiData.LastDispatchedNotify,
+ PrivateData->PpiData.DispatchListEnd
+ );
+ PrivateData->PpiData.LastDispatchedNotify = TempValue;
+ }
+
+
+ //
+ // Check if the PEIM that was just dispatched resulted in any
+ // PPIs getting installed. If so, go process any dispatch
+ // level Notifies that match the installed PPIs.
+ // Use "while" instead of "if" since DispatchNotify can modify
+ // PpiListEnd (with InstallPpi) so we have to iterate until the same.
+ //
+ while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) {
+ TempValue = PrivateData->PpiData.PpiListEnd;
+ DispatchNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ PrivateData->PpiData.LastDispatchedInstall,
+ PrivateData->PpiData.PpiListEnd,
+ PcdGet32 (PcdPeiCoreMaxPpiSupported)-1,
+ PrivateData->PpiData.DispatchListEnd
+ );
+ PrivateData->PpiData.LastDispatchedInstall = TempValue;
+ }
+
+ if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) {
+ break;
+ }
+ }
+ return;
+}
+
+/**
+
+ Dispatch notifications.
+
+ @param PrivateData PeiCore's private data structure
+ @param NotifyType Type of notify to fire.
+ @param InstallStartIndex Install Beginning index.
+ @param InstallStopIndex Install Ending index.
+ @param NotifyStartIndex Notify Beginning index.
+ @param NotifyStopIndex Notify Ending index.
+
+**/
+VOID
+DispatchNotify (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN NotifyType,
+ IN INTN InstallStartIndex,
+ IN INTN InstallStopIndex,
+ IN INTN NotifyStartIndex,
+ IN INTN NotifyStopIndex
+ )
+{
+ INTN Index1;
+ INTN Index2;
+ EFI_GUID *SearchGuid;
+ EFI_GUID *CheckGuid;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
+
+ //
+ // Remember that Installs moves up and Notifies moves down.
+ //
+ for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) {
+ NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify;
+
+ CheckGuid = NotifyDescriptor->Guid;
+
+ for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
+ SearchGuid = PrivateData->PpiData.PpiListPtrs[Index2].Ppi->Guid;
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID as INT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
+ (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
+ (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
+ (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3])) {
+ DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
+ SearchGuid,
+ NotifyDescriptor->Notify
+ ));
+ NotifyDescriptor->Notify (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ NotifyDescriptor,
+ (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi
+ );
+ }
+ }
+ }
+}
+
+/**
+ Process PpiList from SEC phase.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ These PPI's will be installed and/or immediately signaled if they are notification type.
+
+**/
+VOID
+ProcessPpiListFromSec (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ )
+{
+ EFI_STATUS Status;
+ EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
+ EFI_HOB_GENERIC_HEADER *SecHobList;
+
+ for (;;) {
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
+ //
+ // It is a notification PPI.
+ //
+ Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *) PpiList, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // It is a normal PPI.
+ //
+ Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the PPI List.
+ //
+ break;
+ }
+
+ PpiList++;
+ }
+
+ //
+ // If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
+ // the PEI Foundation will call the GetHobs() member function and install all HOBs
+ // returned into the HOB list. It does this after installing all PPIs passed from SEC
+ // into the PPI database and before dispatching any PEIMs.
+ //
+ Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **) &SecHobDataPpi);
+ if (!EFI_ERROR (Status)) {
+ Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
+ if (!EFI_ERROR (Status)) {
+ Status = PeiInstallSecHobData (PeiServices, SecHobList);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c
new file mode 100644
index 0000000000..e6d7899ef7
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c
@@ -0,0 +1,119 @@
+/** @file
+ Pei Core Reset System Support
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Core version of the Reset System
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+
+ @retval EFI_NOT_AVAILABLE_YET PPI not available yet.
+ @retval EFI_DEVICE_ERROR Did not reset system.
+ Otherwise, resets the system.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiResetSystem (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RESET_PPI *ResetPpi;
+
+ //
+ // Attempt to use newer ResetSystem2(). If this returns, then ResetSystem2()
+ // is not available.
+ //
+ PeiResetSystem2 (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ //
+ // Look for PEI Reset System PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiResetPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&ResetPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ return ResetPpi->ResetSystem (PeiServices);
+ }
+
+ //
+ // Report Status Code that Reset PPI is not available.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PS_EC_RESET_NOT_AVAILABLE)
+ );
+
+ //
+ // No reset PPIs are available yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset. ResetData is only valid if ResetStatus is something
+ other than EFI_SUCCESS unless the ResetType is EfiResetPlatformSpecific
+ where a minimum amount of ResetData is always required.
+
+**/
+VOID
+EFIAPI
+PeiResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RESET2_PPI *Reset2Ppi;
+
+ //
+ // Look for PEI Reset System 2 PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReset2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Reset2Ppi
+ );
+ if (!EFI_ERROR (Status)) {
+ Reset2Ppi->ResetSystem (ResetType, ResetStatus, DataSize, ResetData);
+ return;
+ }
+
+ //
+ // Report Status Code that Reset2 PPI is not available.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PS_EC_RESET_NOT_AVAILABLE)
+ );
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c
new file mode 100644
index 0000000000..763126057d
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c
@@ -0,0 +1,151 @@
+/** @file
+ EFI PEI Core Security services
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiSecurity2PpiGuid,
+ SecurityPpiNotifyCallback
+};
+
+/**
+ Initialize the security services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldCoreData Pointer to the old core data.
+ NULL if being run in non-permament memory mode.
+
+**/
+VOID
+InitializeSecurityServices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ PeiServicesNotifyPpi (&mNotifyList);
+ }
+ return;
+}
+
+/**
+
+ Provide a callback for when the security PPI is installed.
+ This routine will cache installed security PPI into PeiCore's private data.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor The descriptor for the notification event.
+ @param Ppi Pointer to the PPI in question.
+
+ @return Always success
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ //
+ // Get PEI Core private data
+ //
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ //
+ // If there isn't a security PPI installed, use the one from notification
+ //
+ if (PrivateData->PrivateSecurityPpi == NULL) {
+ PrivateData->PrivateSecurityPpi = (EFI_PEI_SECURITY2_PPI *)Ppi;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Provide a callout to the security verification service.
+
+ @param PrivateData PeiCore's private data structure
+ @param VolumeHandle Handle of FV
+ @param FileHandle Handle of PEIM's ffs
+ @param AuthenticationStatus Authentication status
+
+ @retval EFI_SUCCESS Image is OK
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval EFI_NOT_FOUND If security PPI is not installed.
+**/
+EFI_STATUS
+VerifyPeim (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT32 AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN DeferExection;
+
+ Status = EFI_NOT_FOUND;
+ if (PrivateData->PrivateSecurityPpi == NULL) {
+ //
+ // Check AuthenticationStatus first.
+ //
+ if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) {
+ if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ }
+ } else {
+ //
+ // Check to see if the image is OK
+ //
+ Status = PrivateData->PrivateSecurityPpi->AuthenticationState (
+ (CONST EFI_PEI_SERVICES **) &PrivateData->Ps,
+ PrivateData->PrivateSecurityPpi,
+ AuthenticationStatus,
+ VolumeHandle,
+ FileHandle,
+ &DeferExection
+ );
+ if (DeferExection) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Verify a Firmware volume.
+
+ @param CurrentFvAddress Pointer to the current Firmware Volume under consideration
+
+ @retval EFI_SUCCESS Firmware Volume is legal
+
+**/
+EFI_STATUS
+VerifyFv (
+ IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress
+ )
+{
+ //
+ // Right now just pass the test. Future can authenticate and/or check the
+ // FV-header or other metric for goodness of binary.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c
new file mode 100644
index 0000000000..a7fb524ff4
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c
@@ -0,0 +1,74 @@
+/** @file
+ Pei Core Status Code Support
+
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Core version of the Status Code reporter
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Type of Status Code.
+ @param Value Value to output for Status Code.
+ @param Instance Instance Number of this status code.
+ @param CallerId ID of the caller of this status code.
+ @param Data Optional data associated with this status code.
+
+ @retval EFI_SUCCESS if status code is successfully reported
+ @retval EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReportStatusCode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PROGRESS_CODE_PPI *StatusCodePpi;
+
+ //
+ // Locate StatusCode Ppi.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiStatusCodePpiGuid,
+ 0,
+ NULL,
+ (VOID **)&StatusCodePpi
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = StatusCodePpi->ReportStatusCode (
+ PeiServices,
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+
+ return Status;
+ }
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c
new file mode 100644
index 0000000000..8d9328b544
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c
@@ -0,0 +1,1678 @@
+/** @file
+ All Pcd Ppi services are implemented here.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Service.h"
+
+///
+/// Instance of PCD_PPI protocol is EDKII native implementation.
+/// This protocol instance support dynamic and dynamicEx type PCDs.
+///
+PCD_PPI mPcdPpiInstance = {
+ PeiPcdSetSku,
+
+ PeiPcdGet8,
+ PeiPcdGet16,
+ PeiPcdGet32,
+ PeiPcdGet64,
+ PeiPcdGetPtr,
+ PeiPcdGetBool,
+ PeiPcdGetSize,
+
+ PeiPcdGet8Ex,
+ PeiPcdGet16Ex,
+ PeiPcdGet32Ex,
+ PeiPcdGet64Ex,
+ PeiPcdGetPtrEx,
+ PeiPcdGetBoolEx,
+ PeiPcdGetSizeEx,
+
+ PeiPcdSet8,
+ PeiPcdSet16,
+ PeiPcdSet32,
+ PeiPcdSet64,
+ PeiPcdSetPtr,
+ PeiPcdSetBool,
+
+ PeiPcdSet8Ex,
+ PeiPcdSet16Ex,
+ PeiPcdSet32Ex,
+ PeiPcdSet64Ex,
+ PeiPcdSetPtrEx,
+ PeiPcdSetBoolEx,
+
+ PeiRegisterCallBackOnSet,
+ PcdUnRegisterCallBackOnSet,
+ PeiPcdGetNextToken,
+ PeiPcdGetNextTokenSpace
+};
+
+///
+/// Instance of EFI_PEI_PCD_PPI which is defined in PI 1.2 Vol 3.
+/// This PPI instance only support dyanmicEx type PCD.
+///
+EFI_PEI_PCD_PPI mEfiPcdPpiInstance = {
+ PeiPcdSetSku,
+
+ PeiPcdGet8Ex,
+ PeiPcdGet16Ex,
+ PeiPcdGet32Ex,
+ PeiPcdGet64Ex,
+ PeiPcdGetPtrEx,
+ PeiPcdGetBoolEx,
+ PeiPcdGetSizeEx,
+ PeiPcdSet8Ex,
+ PeiPcdSet16Ex,
+ PeiPcdSet32Ex,
+ PeiPcdSet64Ex,
+ PeiPcdSetPtrEx,
+ PeiPcdSetBoolEx,
+ (EFI_PEI_PCD_PPI_CALLBACK_ON_SET) PeiRegisterCallBackOnSet,
+ (EFI_PEI_PCD_PPI_CANCEL_CALLBACK) PcdUnRegisterCallBackOnSet,
+ PeiPcdGetNextToken,
+ PeiPcdGetNextTokenSpace
+};
+
+///
+/// Instance of GET_PCD_INFO_PPI protocol is EDKII native implementation.
+/// This protocol instance support dynamic and dynamicEx type PCDs.
+///
+GET_PCD_INFO_PPI mGetPcdInfoInstance = {
+ PeiGetPcdInfoGetInfo,
+ PeiGetPcdInfoGetInfoEx,
+ PeiGetPcdInfoGetSku
+};
+
+///
+/// Instance of EFI_GET_PCD_INFO_PPI which is defined in PI 1.2.1 Vol 3.
+/// This PPI instance only support dyanmicEx type PCD.
+///
+EFI_GET_PCD_INFO_PPI mEfiGetPcdInfoInstance = {
+ PeiGetPcdInfoGetInfoEx,
+ PeiGetPcdInfoGetSku
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gPcdPpiGuid,
+ &mPcdPpiInstance
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiPcdPpiGuid,
+ &mEfiPcdPpiInstance
+ }
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList2[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gGetPcdInfoPpiGuid,
+ &mGetPcdInfoInstance
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiGetPcdInfoPpiGuid,
+ &mEfiGetPcdInfoInstance
+ }
+};
+
+/**
+ Callback on SET PcdSetNvStoreDefaultId
+
+ Once PcdSetNvStoreDefaultId is set, the default NV storage will be found from
+ PcdNvStoreDefaultValueBuffer, and built into VariableHob.
+
+ @param[in] CallBackGuid The PCD token GUID being set.
+ @param[in] CallBackToken The PCD token number being set.
+ @param[in, out] TokenData A pointer to the token data being set.
+ @param[in] TokenDataSize The size, in bytes, of the data being set.
+
+**/
+VOID
+EFIAPI
+PcdSetNvStoreDefaultIdCallBack (
+ IN CONST EFI_GUID *CallBackGuid, OPTIONAL
+ IN UINTN CallBackToken,
+ IN OUT VOID *TokenData,
+ IN UINTN TokenDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 DefaultId;
+ SKU_ID SkuId;
+ UINTN FullSize;
+ UINTN Index;
+ UINT8 *DataBuffer;
+ UINT8 *VarStoreHobData;
+ UINT8 *BufferEnd;
+ BOOLEAN IsFound;
+ VARIABLE_STORE_HEADER *NvStoreBuffer;
+ PCD_DEFAULT_DATA *DataHeader;
+ PCD_DEFAULT_INFO *DefaultInfo;
+ PCD_DATA_DELTA *DeltaData;
+
+ DefaultId = *(UINT16 *) TokenData;
+ SkuId = GetPcdDatabase()->SystemSkuId;
+ IsFound = FALSE;
+
+ if (PeiPcdGetSizeEx (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdNvStoreDefaultValueBuffer)) > sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+ DataBuffer = (UINT8 *) PeiPcdGetPtrEx (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdNvStoreDefaultValueBuffer));
+ FullSize = ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) DataBuffer)->Length;
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER));
+ //
+ // The first section data includes NV storage default setting.
+ //
+ NvStoreBuffer = (VARIABLE_STORE_HEADER *) ((UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize);
+ VarStoreHobData = (UINT8 *) BuildGuidHob (&NvStoreBuffer->Signature, NvStoreBuffer->Size);
+ ASSERT (VarStoreHobData != NULL);
+ CopyMem (VarStoreHobData, NvStoreBuffer, NvStoreBuffer->Size);
+ //
+ // Find the matched SkuId and DefaultId in the first section
+ //
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == SkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ //
+ // Find the matched SkuId and DefaultId in the remaining section
+ //
+ Index = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + ((DataHeader->DataSize + 7) & (~7));
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ while (!IsFound && Index < FullSize && DataHeader->DataSize != 0xFFFFFFFF) {
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == SkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ if (IsFound) {
+ DeltaData = (PCD_DATA_DELTA *) BufferEnd;
+ BufferEnd = (UINT8 *) DataHeader + DataHeader->DataSize;
+ while ((UINT8 *) DeltaData < BufferEnd) {
+ *(VarStoreHobData + DeltaData->Offset) = (UINT8) DeltaData->Value;
+ DeltaData ++;
+ }
+ break;
+ }
+ Index = (Index + DataHeader->DataSize + 7) & (~7) ;
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ }
+ }
+
+ Status = PcdUnRegisterCallBackOnSet (
+ &gEfiMdeModulePkgTokenSpaceGuid,
+ PcdToken(PcdSetNvStoreDefaultId),
+ PcdSetNvStoreDefaultIdCallBack
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Report Pei PCD database of all SKUs as Guid HOB so that DxePcd can access it.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Successfully update the Boot records.
+**/
+EFI_STATUS
+EFIAPI
+EndOfPeiSignalPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_PCD_DATABASE *Database;
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *PcdDb;
+ UINT32 Length;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ Status = PeiServicesGetBootMode(&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Don't need to report it on S3 boot.
+ //
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ return EFI_SUCCESS;
+ }
+
+ PeiPcdDb = GetPcdDatabase();
+ if (PeiPcdDb->SystemSkuId != (SKU_ID) 0) {
+ //
+ // SkuId has been set. Don't need to report it to DXE phase.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get full PCD database from PcdPeim FileHandle
+ //
+ Instance = 0;
+ FileHandle = NULL;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances
+ //
+ Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+ //
+ // Error should not happen
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find PcdDb file from the beginning in this firmware volume.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindFileByName (&gEfiCallerIdGuid, VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find PcdPeim FileHandle in this volume
+ //
+ break;
+ }
+ //
+ // We cannot find PcdPeim in this firmware volume, then search the next volume.
+ //
+ Instance++;
+ }
+
+ //
+ // Find PEI PcdDb and Build second PcdDB GuidHob
+ //
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+ Length = PeiPcdDb->LengthForAllSkus;
+ Database = BuildGuidHob (&gPcdDataBaseHobGuid, Length);
+ CopyMem (Database, PcdDb, Length);
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mEndOfPeiSignalPpiNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndOfPeiSignalPpiNotifyCallback
+ }
+};
+
+/**
+ Main entry for PCD PEIM driver.
+
+ This routine initialize the PCD database for PEI phase and install PCD_PPI/EFI_PEI_PCD_PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return Status of install PCD_PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PcdPeimInit (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ BuildPcdDatabase (FileHandle);
+
+ //
+ // Install PCD_PPI and EFI_PEI_PCD_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList2[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiServicesNotifyPpi (&mEndOfPeiSignalPpiNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiRegisterCallBackOnSet (
+ &gEfiMdeModulePkgTokenSpaceGuid,
+ PcdToken(PcdSetNvStoreDefaultId),
+ PcdSetNvStoreDefaultIdCallBack
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return PeiGetPcdInfo (NULL, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return PeiGetPcdInfo (Guid, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+PeiGetPcdInfoGetSku (
+ VOID
+ )
+{
+ return (UINTN) GetPcdDatabase()->SystemSkuId;
+}
+
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+PeiPcdSetSku (
+ IN UINTN SkuId
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ SKU_ID *SkuIdTable;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *PcdDb;
+ UINT32 Length;
+ PCD_DATABASE_SKU_DELTA *SkuDelta;
+ PCD_DATA_DELTA *SkuDeltaData;
+
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId 0x%lx is to be set.\n", (SKU_ID) SkuId));
+
+ PeiPcdDb = GetPcdDatabase();
+
+ if (SkuId == PeiPcdDb->SystemSkuId) {
+ //
+ // The input SKU Id is equal to current SKU Id, return directly.
+ //
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId is same to current system Sku.\n"));
+ return;
+ }
+
+ if (PeiPcdDb->SystemSkuId != (SKU_ID) 0) {
+ DEBUG ((DEBUG_ERROR, "PcdPei - The SKU Id could be changed only once."));
+ DEBUG ((
+ DEBUG_ERROR,
+ "PcdPei - The SKU Id was set to 0x%lx already, it could not be set to 0x%lx any more.",
+ PeiPcdDb->SystemSkuId,
+ (SKU_ID) SkuId
+ ));
+ ASSERT (FALSE);
+ return;
+ }
+
+ SkuIdTable = (SKU_ID *) ((UINT8 *) PeiPcdDb + PeiPcdDb->SkuIdTableOffset);
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (SkuId == SkuIdTable[Index + 1]) {
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId is found in SkuId table.\n"));
+ break;
+ }
+ }
+
+ if (Index < SkuIdTable[0]) {
+ //
+ // Get full PCD database from PcdPeim FileHandle
+ //
+ Instance = 0;
+ FileHandle = NULL;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances
+ //
+ Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+ //
+ // Error should not happen
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find PcdDb file from the beginning in this firmware volume.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindFileByName (&gEfiCallerIdGuid, VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find PcdPeim FileHandle in this volume
+ //
+ break;
+ }
+ //
+ // We cannot find PcdPeim in this firmware volume, then search the next volume.
+ //
+ Instance++;
+ }
+
+ //
+ // Find the delta data between the different Skus
+ //
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+ Length = PeiPcdDb->LengthForAllSkus;
+ Index = (PeiPcdDb->Length + 7) & (~7);
+ SkuDelta = NULL;
+ while (Index < Length) {
+ SkuDelta = (PCD_DATABASE_SKU_DELTA *) ((UINT8 *) PcdDb + Index);
+ if (SkuDelta->SkuId == SkuId && SkuDelta->SkuIdCompared == 0) {
+ break;
+ }
+ Index = (Index + SkuDelta->Length + 7) & (~7);
+ }
+
+ //
+ // Patch the delta data into current PCD database
+ //
+ if (Index < Length && SkuDelta != NULL) {
+ SkuDeltaData = (PCD_DATA_DELTA *) (SkuDelta + 1);
+ while ((UINT8 *) SkuDeltaData < (UINT8 *) SkuDelta + SkuDelta->Length) {
+ *((UINT8 *) PeiPcdDb + SkuDeltaData->Offset) = (UINT8) SkuDeltaData->Value;
+ SkuDeltaData ++;
+ }
+ PeiPcdDb->SystemSkuId = (SKU_ID) SkuId;
+ DEBUG ((DEBUG_INFO, "PcdPei - Set current SKU Id to 0x%lx.\n", (SKU_ID) SkuId));
+ return;
+ }
+ }
+
+ //
+ // Invalid input SkuId, the default SKU Id will be still used for the system.
+ //
+ DEBUG ((DEBUG_ERROR, "PcdPei - Invalid input SkuId, the default SKU Id will be still used.\n"));
+
+ return;
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8 (
+ IN UINTN TokenNumber
+ )
+{
+ return *((UINT8 *) GetWorker (TokenNumber, sizeof (UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned16 (GetWorker (TokenNumber, sizeof (UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned32 (GetWorker (TokenNumber, sizeof (UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned64 (GetWorker (TokenNumber, sizeof (UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtr (
+ IN UINTN TokenNumber
+ )
+{
+ return GetWorker (TokenNumber, 0);
+}
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBool (
+ IN UINTN TokenNumber
+ )
+{
+ return *((BOOLEAN *) GetWorker (TokenNumber, sizeof (BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSize (
+ IN UINTN TokenNumber
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINTN Size;
+ UINTN MaxSize;
+ UINT32 LocalTokenCount;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ Size = (*((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber) & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
+
+ if (Size == 0) {
+ //
+ // For pointer type, we need to scan the SIZE_TABLE to get the current size.
+ //
+ return GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);
+ } else {
+ return Size;
+ }
+
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((UINT8 *) ExGetWorker (Guid, ExTokenNumber, sizeof (UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned16 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned32 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned64 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ExGetWorker (Guid, ExTokenNumber, 0);
+}
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((BOOLEAN *) ExGetWorker (Guid, ExTokenNumber, sizeof (BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return PeiPcdGetSize (GetExPcdTokenNumber (Guid, ExTokenNumber));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ )
+{
+ return SetWorker (TokenNumber, Buffer, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT8 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT16 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT32 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT64 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Value The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Value
+ )
+{
+ return ExSetWorker (ExTokenNumber, Guid, Value, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param [in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param [in] ExTokenNumber The PCD token number.
+ @param [in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN ExTokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ )
+{
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return PeiRegisterCallBackWorker (ExTokenNumber, Guid, CallBackFunction, TRUE);
+}
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PcdUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN ExTokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ )
+{
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return PeiRegisterCallBackWorker (ExTokenNumber, Guid, CallBackFunction, FALSE);
+}
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request
+ is being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service has retrieved the next valid token number.
+ @retval EFI_NOT_FOUND The PCD service could not find data from the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ )
+{
+ UINTN GuidTableIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ EFI_GUID *MatchGuid;
+ EFI_GUID *GuidTable;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ BOOLEAN Found;
+ BOOLEAN PeiExMapTableEmpty;
+ UINTN PeiNexTokenNumber;
+
+ if (!FeaturePcdGet (PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ PeiPcdDb = GetPcdDatabase ();
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+ if (Guid == NULL) {
+ if (*TokenNumber > PeiNexTokenNumber) {
+ return EFI_NOT_FOUND;
+ }
+ (*TokenNumber)++;
+ if (*TokenNumber > PeiNexTokenNumber) {
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+
+ Found = FALSE;
+ //
+ // Locate the GUID in ExMapTable first.
+ //
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ //
+ // If given token number is PCD_INVALID_TOKEN_NUMBER, then return the first
+ // token number in found token space.
+ //
+ if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+
+ for ( ; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if ((ExMapTable[Index].ExTokenNumber == *TokenNumber) && (ExMapTable[Index].ExGuidIndex == GuidTableIdx)) {
+ break;
+ }
+ }
+
+ while (Index < PeiPcdDb->ExTokenCount) {
+ Index++;
+ if (Index == PeiPcdDb->ExTokenCount) {
+ //
+ // Exceed the length of ExMap Table
+ //
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ } else if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ //
+ // Found the next match
+ //
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieves the next valid PCD token namespace for a given namespace.
+
+ Gets the next valid token namespace for a given namespace. This is useful to traverse the valid
+ token namespaces on a platform.
+
+ @param[in, out] Guid An indirect pointer to EFI_GUID. On input it designates a known token
+ namespace from which the search will start. On output, it designates the next valid
+ token namespace on the platform. If *Guid is NULL, then the GUID of the first token
+ space of the current platform is returned. If the search cannot locate the next valid
+ token namespace, an error is returned and the value of *Guid is undefined.
+
+ @retval EFI_SUCCESS The PCD service retrieved the value requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the next valid token namespace.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ )
+{
+ UINTN GuidTableIdx;
+ EFI_GUID *MatchGuid;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN Found;
+ BOOLEAN PeiExMapTableEmpty;
+ EFI_GUID *GuidTable;
+
+ if (!FeaturePcdGet (PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (Guid != NULL);
+
+ PeiPcdDb = GetPcdDatabase ();
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ if (*Guid == NULL) {
+ //
+ // return the first Token Space Guid.
+ //
+ *Guid = GuidTable + ExMapTable[0].ExGuidIndex;
+ return EFI_SUCCESS;
+ }
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(GuidTable[0]), *Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ Found = FALSE;
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ Index++;
+ for ( ; Index < PeiPcdDb->ExTokenCount; Index++ ) {
+ if (ExMapTable[Index].ExGuidIndex != GuidTableIdx) {
+ Found = FALSE;
+ for (Index2 = 0 ; Index2 < Index; Index2++) {
+ if (ExMapTable[Index2].ExGuidIndex == ExMapTable[Index].ExGuidIndex) {
+ //
+ // This token namespace should have been found and output at preceding getting.
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+ if (!Found) {
+ *Guid = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + ExMapTable[Index].ExGuidIndex;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ *Guid = NULL;
+ }
+
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Get PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specified size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param MaxSize Maximum size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @return PCD value's size for POINTER type PCD.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, Database);
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTable = (SIZE_INFO *)((UINT8 *)Database + Database->SizeTableOffset);
+
+ *MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // We consider current size is equal to MAX size.
+ //
+ return *MaxSize;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ return SizeTable[SizeTableIdx + 1];
+ }
+}
+
+/**
+ Set PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specified size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param CurrentSize Maximum size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @retval TRUE Success to set PCD's value size, which is not exceed maximum size
+ @retval FALSE Fail to set PCD's value size, which maybe exceed maximum size
+
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+ UINTN MaxSize;
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, Database);
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTable = (SIZE_INFO *)((UINT8 *)Database + Database->SizeTableOffset);
+
+ MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We shouldn't come here as we don't support SET for VPD
+ //
+ ASSERT (FALSE);
+ return FALSE;
+ } else {
+ if ((*CurrentSize > MaxSize) ||
+ (*CurrentSize == MAX_ADDRESS)) {
+ *CurrentSize = MaxSize;
+ return FALSE;
+ }
+
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
+ return TRUE;
+ }
+
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf
new file mode 100644
index 0000000000..3cba28944c
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf
@@ -0,0 +1,355 @@
+## @file
+# PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service.
+#
+# This version PCD PEIM depends on the external PCD database binary file, not built in PCD data base.
+# There are two PCD PPIs as follows:
+# 1) PCD_PPI
+# It is EDKII implementation which support Dynamic/DynamicEx Pcds.
+# 2) EFI_PEI_PCD_PPI
+# It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+# type Pcd.
+# For dynamicEx type PCD, it is compatible between PCD_PPI and EFI_PEI_PCD_PPI.
+# PCD PEIM driver will produce above two PPIs at same time.
+#
+# PCD database is generated as the separate binary image at build time. The binary image
+# will be intergrated into Firmware volume together with PCD driver.
+#
+# ////////////////////////////////////////////////////////////////////////////////
+# // //
+# // Introduction of PCD database //
+# // //
+# ////////////////////////////////////////////////////////////////////////////////
+#
+# 1, Introduction
+# PCD database hold all dynamic type PCD information. The structure of PEI PCD
+# database is generated by build tools according to dynamic PCD usage for
+# specified platform.
+#
+# 2, Dynamic Type PCD
+# Dynamic type PCD is used for the configuration/setting which value is determined
+# dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+# PatchablePcd) is fixed in final generated FD image in build time.
+#
+# 2.1 The "dynamic" determination means one of below cases:
+# a) The PCD setting value is produced by someone driver and consumed by
+# other driver in execution time.
+# b) The PCD setting value is set/get by user from FrontPage.
+# c) The PCD setting value is produced by platform OEM vendor in specified area.
+#
+# 2.2 According to module distribution way, dynamic PCD could be classfied as:
+# a) Dynamic:
+# If module is released in source code and will be built with platform
+# DSC, the dynamic PCD used by this module can be accessed as:
+# PcdGetxx(PcdSampleDynamicPcd);
+# In building platform, build tools will translate PcdSampleDynamicPcd to
+# pair of {Token Space Guid: Token Number} for this PCD.
+# b) DynamicEx:
+# If module is release as binary and will not pariticpate platform building,
+# the dynamic PCD used by this module need be accessed as:
+# PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+# Developer need explicity gives {Token Space Guid:Token Number} as parameter
+# in writting source code.
+#
+# 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+# a) Default Storage:
+# - The PCD value is stored in PCD database maintained by PCD driver in boot
+# time memory.
+# - This type is used for communication between PEIM/DXE driver, DXE/DXE
+# driver. But all set/get value will be losted after boot-time memory
+# is turn off.
+# - [PcdsDynamicDefault] is used as section name for this type PCD in
+# platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+#
+# b) Variable Storage:
+# - The PCD value is stored in variable area.
+# - As default storage type, this type PCD could be used for PEI/DXE driver
+# communication. But beside it, this type PCD could also be used to store
+# the value associate with a HII setting via variable interface.
+# - In PEI phase, the PCD value could only be got but can not be set due
+# to variable area is readonly.
+# - [PcdsDynamicHii] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+#
+# c) OEM specificed storage area:
+# - The PCD value is stored in OEM specified area which base address is
+# specified by a FixedAtBuild PCD setting - PcdVpdBaseAddress.
+# - The area is read only for PEI and DXE phase.
+# - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+#
+# 2.4 When and how to use dynamic PCD
+# Module developer do not care the used PCD is dynamic or static when writting
+# source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+# in platform DSC file. Please ref section 2.3 to get matching between dynamic
+# PCD type and section name in DSC file.
+#
+# 3, PCD database:
+# Although dynamic PCD could be in different storage type as above description,
+# but the basic information and default value for all dynamic PCD is hold
+# by PCD database maintained by PEI/DXE driver.
+#
+# As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+# also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+# To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+# PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+# database contains all PCDs used in PEI/DXE phase in memory.
+#
+# Build tool will generate PCD database into the separate binary file for
+# PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+#
+# 3.1 PcdPeim and PcdDxe
+# PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+# build guid hob in temporary memory and copy the binary data base from flash
+# to temporary memory for PEI PCD database.
+# DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+# a new PCD database is allocated in boot-time memory which including all
+# PEI PCD and DXE PCD entry.
+#
+# Pcd driver should run as early as possible before any other driver access
+# dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+# making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+#
+# 3.2 Token space Guid/Token number, Platform token, Local token number
+# Dynamic PCD
+# +-----------+ +---------+
+# |TokenSpace | |Platform |
+# | Guid | build tool | Token |
+# | + +-------------->| Number |
+# | Token | +---------+`._
+# | Number | `.
+# +-----------+ `. +------+
+# `-|Local |
+# |Token |
+# DynamicEx PCD ,-|Number|
+# +-----------+ ,-' +------+
+# |TokenSpace | ,-'
+# | Guid | _,-'
+# | + +.'
+# | Token |
+# | Number |
+# +-----------+
+#
+#
+# 3.2.1 Pair of Token space guid + Token number
+# Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+# is not easy maintained by PCD driver, and hashed token number will make
+# searching slowly.
+#
+# 3.2.2 Platform Token Number
+# "Platform token number" concept is introduced for mapping to a pair of
+# "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+# build tool in autogen.h and all of them are continual in a platform scope
+# started from 1.(0 meaning invalid internal token number)
+# With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+# in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+# in autogen.h.
+# Notes: The mapping between pair of "tokenspace guid + token number" and
+# "internal token number" need build tool establish, so "platform token number"
+# mechanism is not suitable for binary module which use DynamicEx type PCD.
+# To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+# to be specificed for PcdSet/PcdGet accessing macro.
+#
+# Platform Token Number is started from 1, and inceased continuous. From whole
+# platform scope, there are two zones: PEI Zone and DXE Zone
+# | Platform Token Number
+# ----------|----------------------------------------------------------------
+# PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+# DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+#
+# 3.2.3 Local Token Number
+# To fast searching a PCD entry in PCD database, PCD driver translate
+# platform token number to local token number via a mapping table.
+# For binary DynamicEx type PCD, there is a another mapping table to translate
+# "token space guid + token number" to local token number directly.
+# Local token number is identifier for all internal interface in PCD PEI/DXE
+# driver.
+#
+# A local token number is a 32-bit value in following meaning:
+# 32 ------------- 28 ---------- 24 -------- 0
+# | PCD type mask | Datum Type | Offset |
+# +-----------------------------------------+
+# where:
+# PCd type mask: indicate Pcd type from following macro:
+# PCD_TYPE_DATA
+# PCD_TYPE_HII
+# PCD_TYPE_VPD
+# PCD_TYPE_STRING
+# Datum Type : indicate PCD vaue type from following macro:
+# PCD_DATUM_TYPE_POINTER
+# PCD_DATUM_TYPE_UINT8
+# PCD_DATUM_TYPE_UINT16
+# PCD_DATUM_TYPE_UINT32
+# PCD_DATUM_TYPE_UINT64
+# Offset : indicate the related offset of PCD value in PCD database array.
+# Based on local token number, PCD driver could fast determine PCD type, value
+# type and get PCD entry from PCD database.
+#
+# 3.3 PCD Database binary file
+# PCD Database binary file will be created at build time as the standalone binary image.
+# To understand the binary image layout, PCD Database C structure is still generated
+# as comments by build tools in PCD driver's autogen.h/
+# autogen.c file. In generated C structure, following information is stored:
+# - ExMapTable: This table is used translate a binary dynamicex type PCD's
+# "tokenguid + token" to local token number.
+# - LocalTokenNumberTable:
+# This table stores all local token number in array, use "Internal
+# token number" as array index to get PCD entry's offset fastly.
+# - SizeTable: This table stores the size information for all PCD entry.
+# - GuidTable: This table stores guid value for DynamicEx's token space,
+# HII type PCD's variable GUID.
+# - SkuIdTable: TBD
+# - SystemSkuId: TBD
+# - PCD value structure:
+# Every PCD has a value record in PCD database. For different
+# datum type PCD has different record structure which will be
+# introduced in 3.3.1
+#
+# In a PCD database structure, there are two major area: Init and UnInit.
+# Init area is use stored above PCD internal structure such as ExMapTable,
+# LocalTokenNumberTable etc and the (default) value of PCD which has default
+# value specified in platform DSC file.
+# Unint area is used stored the value of PCD which has no default value in
+# platform DSC file, the value of NULL, 0 specified in platform DSC file can
+# be seemed as "no default value".
+#
+# 3.3.1 Simple Sample PCD Database C Structure
+# A general sample of PCD database structue is as follows:
+# typedef struct _PCD_DATABASE {
+# typedef struct _PCD_DATABASE_INIT {
+# //===== Following is PCD database internal maintain structures
+# DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+# UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+# GUID GuidTable[PEI_GUID_TABLE_SIZE];
+# SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+# UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+# SKU_ID SystemSkuId;
+#
+# //===== Following is value structure for PCD with default value
+# ....
+# ....
+# ....
+# } Init;
+# typedef struct _PCD_DATABSE_UNINIT {
+# //==== Following is value structure for PCD without default value
+# ....
+# ....
+# } UnInit;
+# }
+#
+# 3.3.2 PCD value structure in PCD database C structure
+# The value's structure is generated by build tool in PCD database C structure.
+# The PCDs in different datum type has different value structure.
+#
+# 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+# The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+# data member in PCD database, For example:
+# UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+# Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+# Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+# in DEC file.
+#
+# 3.3.2.2 VOID* datum type PCD
+# The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+#
+# 3.3.2.2.1 VOID* - string type
+# If the default value for VOID* datum type PCD like L"xxx", the PCD is
+# used for unicode string, and C structure of this datum type PCD is
+# UINT16 string array in PCD database, for example:
+# UINT16 StringTable[29];
+# The number of 29 in above sample is max size of a unicode string.
+#
+# If the default value for VOID* datum type PCD like "xxx", the PCD is
+# used for ascii string, and C structure of this datum type PCD is
+# UINT8 string array in PCD database, for example:
+# UINT8 StringTable[20];
+# The number of 20 in above sample is max size of a ascii string.
+#
+# 3.3.2.2.2 VOID* - byte array
+# If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+# the PCD is used for byte array. The generated structrue is same as
+# above ascii string table,
+# UINT8 StringTable[13];
+# The number of 13 in above sample is max size of byte array.
+#
+# 3.3.3 Some utility structures in PCD Database
+# 3.3.3.1 GuidTable
+# GuidTable array is used to store all related GUID value in PCD database:
+# - Variable GUID for HII type PCD
+# - Token space GUID for dynamicex type PCD
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PcdPeim
+ MODULE_UNI_FILE = PcdPeim.uni
+ FILE_GUID = 9B3ADA4F-AE56-4c24-8DEA-F03B7558AE50
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 4.0
+ PCD_IS_DRIVER = PEI_PCD_DRIVER
+ ENTRY_POINT = PcdPeimInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ Service.c
+ Service.h
+ Pcd.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ PeiServicesLib
+ HobLib
+ BaseLib
+ PeimEntryPoint
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gPcdDataBaseHobGuid
+ gPcdDataBaseSignatureGuid ## CONSUMES ## GUID # PCD database signature GUID.
+ gEfiMdeModulePkgTokenSpaceGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_CONSUMES
+ gPcdPpiGuid ## PRODUCES
+ gEfiPeiPcdPpiGuid ## PRODUCES
+ gGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiFullPcdDatabaseEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PcdPeimExtra.uni
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni
new file mode 100644
index 0000000000..3e7c5566f0
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni
@@ -0,0 +1,295 @@
+// /** @file
+// PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service.
+//
+// This version PCD PEIM depends on the external PCD database binary file, not built in PCD data base.
+// There are two PCD PPIs as follows:
+// 1) PCD_PPI
+// It is EDKII implementation which support Dynamic/DynamicEx Pcds.
+// 2) EFI_PEI_PCD_PPI
+// It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+// type Pcd.
+// For dynamicEx type PCD, it is compatible between PCD_PPI and EFI_PEI_PCD_PPI.
+// PCD PEIM driver will produce above two PPIs at same time.
+//
+// PCD database is generated as the separate binary image at build time. The binary image
+// will be intergrated into Firmware volume together with PCD driver.
+//
+// ////////////////////////////////////////////////////////////////////////////////
+// // //
+// // Introduction of PCD database //
+// // //
+// ////////////////////////////////////////////////////////////////////////////////
+//
+// 1, Introduction
+// PCD database hold all dynamic type PCD information. The structure of PEI PCD
+// database is generated by build tools according to dynamic PCD usage for
+// specified platform.
+//
+// 2, Dynamic Type PCD
+// Dynamic type PCD is used for the configuration/setting which value is determined
+// dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+// PatchablePcd) is fixed in final generated FD image in build time.
+//
+// 2.1 The "dynamic" determination means one of below cases:
+// a) The PCD setting value is produced by someone driver and consumed by
+// other driver in execution time.
+// b) The PCD setting value is set/get by user from FrontPage.
+// c) The PCD setting value is produced by platform OEM vendor in specified area.
+//
+// 2.2 According to module distribution way, dynamic PCD could be classfied as:
+// a) Dynamic:
+// If module is released in source code and will be built with platform
+// DSC, the dynamic PCD used by this module can be accessed as:
+// PcdGetxx(PcdSampleDynamicPcd);
+// In building platform, build tools will translate PcdSampleDynamicPcd to
+// pair of {Token Space Guid: Token Number} for this PCD.
+// b) DynamicEx:
+// If module is release as binary and will not pariticpate platform building,
+// the dynamic PCD used by this module need be accessed as:
+// PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+// Developer need explicity gives {Token Space Guid:Token Number} as parameter
+// in writting source code.
+//
+// 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+// a) Default Storage:
+// - The PCD value is stored in PCD database maintained by PCD driver in boot
+// time memory.
+// - This type is used for communication between PEIM/DXE driver, DXE/DXE
+// driver. But all set/get value will be losted after boot-time memory
+// is turn off.
+// - [PcdsDynamicDefault] is used as section name for this type PCD in
+// platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+//
+// b) Variable Storage:
+// - The PCD value is stored in variable area.
+// - As default storage type, this type PCD could be used for PEI/DXE driver
+// communication. But beside it, this type PCD could also be used to store
+// the value associate with a HII setting via variable interface.
+// - In PEI phase, the PCD value could only be got but can not be set due
+// to variable area is readonly.
+// - [PcdsDynamicHii] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+//
+// c) OEM specificed storage area:
+// - The PCD value is stored in OEM specified area which base address is
+// specified by a FixedAtBuild PCD setting - PcdVpdBaseAddress.
+// - The area is read only for PEI and DXE phase.
+// - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+//
+// 2.4 When and how to use dynamic PCD
+// Module developer do not care the used PCD is dynamic or static when writting
+// source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+// in platform DSC file. Please ref section 2.3 to get matching between dynamic
+// PCD type and section name in DSC file.
+//
+// 3, PCD database:
+// Although dynamic PCD could be in different storage type as above description,
+// but the basic information and default value for all dynamic PCD is hold
+// by PCD database maintained by PEI/DXE driver.
+//
+// As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+// also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+// To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+// PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+// database contains all PCDs used in PEI/DXE phase in memory.
+//
+// Build tool will generate PCD database into the separate binary file for
+// PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+//
+// 3.1 PcdPeim and PcdDxe
+// PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+// build guid hob in temporary memory and copy the binary data base from flash
+// to temporary memory for PEI PCD database.
+// DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+// a new PCD database is allocated in boot-time memory which including all
+// PEI PCD and DXE PCD entry.
+//
+// Pcd driver should run as early as possible before any other driver access
+// dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+// making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+//
+// 3.2 Token space Guid/Token number, Platform token, Local token number
+// Dynamic PCD
+// +-----------+ +---------+
+// |TokenSpace | |Platform |
+// | Guid | build tool | Token |
+// | + +-------------->| Number |
+// | Token | +---------+`._
+// | Number | `.
+// +-----------+ `. +------+
+// `-|Local |
+// |Token |
+// DynamicEx PCD ,-|Number|
+// +-----------+ ,-' +------+
+// |TokenSpace | ,-'
+// | Guid | _,-'
+// | + +.'
+// | Token |
+// | Number |
+// +-----------+
+//
+//
+// 3.2.1 Pair of Token space guid + Token number
+// Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+// is not easy maintained by PCD driver, and hashed token number will make
+// searching slowly.
+//
+// 3.2.2 Platform Token Number
+// "Platform token number" concept is introduced for mapping to a pair of
+// "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+// build tool in autogen.h and all of them are continual in a platform scope
+// started from 1.(0 meaning invalid internal token number)
+// With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+// in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+// in autogen.h.
+// Notes: The mapping between pair of "tokenspace guid + token number" and
+// "internal token number" need build tool establish, so "platform token number"
+// mechanism is not suitable for binary module which use DynamicEx type PCD.
+// To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+// to be specificed for PcdSet/PcdGet accessing macro.
+//
+// Platform Token Number is started from 1, and inceased continuous. From whole
+// platform scope, there are two zones: PEI Zone and DXE Zone
+// | Platform Token Number
+// ----------|----------------------------------------------------------------
+// PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+// DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+//
+// 3.2.3 Local Token Number
+// To fast searching a PCD entry in PCD database, PCD driver translate
+// platform token number to local token number via a mapping table.
+// For binary DynamicEx type PCD, there is a another mapping table to translate
+// "token space guid + token number" to local token number directly.
+// Local token number is identifier for all internal interface in PCD PEI/DXE
+// driver.
+//
+// A local token number is a 32-bit value in following meaning:
+// 32 ------------- 28 ---------- 24 -------- 0
+// | PCD type mask | Datum Type | Offset |
+// +-----------------------------------------+
+// where:
+// PCd type mask: indicate Pcd type from following macro:
+// PCD_TYPE_DATA
+// PCD_TYPE_HII
+// PCD_TYPE_VPD
+// PCD_TYPE_STRING
+// Datum Type : indicate PCD vaue type from following macro:
+// PCD_DATUM_TYPE_POINTER
+// PCD_DATUM_TYPE_UINT8
+// PCD_DATUM_TYPE_UINT16
+// PCD_DATUM_TYPE_UINT32
+// PCD_DATUM_TYPE_UINT64
+// Offset : indicate the related offset of PCD value in PCD database array.
+// Based on local token number, PCD driver could fast determine PCD type, value
+// type and get PCD entry from PCD database.
+//
+// 3.3 PCD Database binary file
+// PCD Database binary file will be created at build time as the standalone binary image.
+// To understand the binary image layout, PCD Database C structure is still generated
+// as comments by build tools in PCD driver's autogen.h/
+// autogen.c file. In generated C structure, following information is stored:
+// - ExMapTable: This table is used translate a binary dynamicex type PCD's
+// "tokenguid + token" to local token number.
+// - LocalTokenNumberTable:
+// This table stores all local token number in array, use "Internal
+// token number" as array index to get PCD entry's offset fastly.
+// - SizeTable: This table stores the size information for all PCD entry.
+// - GuidTable: This table stores guid value for DynamicEx's token space,
+// HII type PCD's variable GUID.
+// - SkuIdTable: TBD
+// - SystemSkuId: TBD
+// - PCD value structure:
+// Every PCD has a value record in PCD database. For different
+// datum type PCD has different record structure which will be
+// introduced in 3.3.1
+//
+// In a PCD database structure, there are two major area: Init and UnInit.
+// Init area is use stored above PCD internal structure such as ExMapTable,
+// LocalTokenNumberTable etc and the (default) value of PCD which has default
+// value specified in platform DSC file.
+// Unint area is used stored the value of PCD which has no default value in
+// platform DSC file, the value of NULL, 0 specified in platform DSC file can
+// be seemed as "no default value".
+//
+// 3.3.1 Simple Sample PCD Database C Structure
+// A general sample of PCD database structue is as follows:
+// typedef struct _PCD_DATABASE {
+// typedef struct _PCD_DATABASE_INIT {
+// //===== Following is PCD database internal maintain structures
+// DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+// UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+// GUID GuidTable[PEI_GUID_TABLE_SIZE];
+// SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+// UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+// SKU_ID SystemSkuId;
+//
+// //===== Following is value structure for PCD with default value
+// ....
+// ....
+// ....
+// } Init;
+// typedef struct _PCD_DATABSE_UNINIT {
+// //==== Following is value structure for PCD without default value
+// ....
+// ....
+// } UnInit;
+// }
+//
+// 3.3.2 PCD value structure in PCD database C structure
+// The value's structure is generated by build tool in PCD database C structure.
+// The PCDs in different datum type has different value structure.
+//
+// 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+// The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+// data member in PCD database, For example:
+// UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+// Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+// Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+// in DEC file.
+//
+// 3.3.2.2 VOID* datum type PCD
+// The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+//
+// 3.3.2.2.1 VOID* - string type
+// If the default value for VOID* datum type PCD like L"xxx", the PCD is
+// used for unicode string, and C structure of this datum type PCD is
+// UINT16 string array in PCD database, for example:
+// UINT16 StringTable[29];
+// The number of 29 in above sample is max size of a unicode string.
+//
+// If the default value for VOID* datum type PCD like "xxx", the PCD is
+// used for ascii string, and C structure of this datum type PCD is
+// UINT8 string array in PCD database, for example:
+// UINT8 StringTable[20];
+// The number of 20 in above sample is max size of a ascii string.
+//
+// 3.3.2.2.2 VOID* - byte array
+// If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+// the PCD is used for byte array. The generated structrue is same as
+// above ascii string table,
+// UINT8 StringTable[13];
+// The number of 13 in above sample is max size of byte array.
+//
+// 3.3.3 Some utility structures in PCD Database
+// 3.3.3.1 GuidTable
+// GuidTable array is used to store all related GUID value in PCD database:
+// - Variable GUID for HII type PCD
+// - Token space GUID for dynamicex type PCD
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service."
+
+#string STR_MODULE_DESCRIPTION #language en-US "PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service."
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni
new file mode 100644
index 0000000000..a618943612
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// PcdPeim Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform Configuration Database PEI Module"
+
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c
new file mode 100644
index 0000000000..e8a0b6ca10
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c
@@ -0,0 +1,1074 @@
+/** @file
+ The driver internal functions are implmented here.
+ They build Pei PCD database, and provide access service to PCD database.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Service.h"
+
+/**
+ Get Local Token Number by Token Number.
+
+ @param[in] Database PCD database.
+ @param[in] TokenNumber The PCD token number.
+
+ @return Local Token Number.
+**/
+UINT32
+GetLocalTokenNumber (
+ IN PEI_PCD_DATABASE *Database,
+ IN UINTN TokenNumber
+ )
+{
+ UINT32 LocalTokenNumber;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + TokenNumber);
+
+ return LocalTokenNumber;
+}
+
+/**
+ Get PCD type by Local Token Number.
+
+ @param[in] LocalTokenNumber The PCD local token number.
+
+ @return PCD type.
+**/
+EFI_PCD_TYPE
+GetPcdType (
+ IN UINT32 LocalTokenNumber
+ )
+{
+ switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
+ case PCD_DATUM_TYPE_POINTER:
+ return EFI_PCD_TYPE_PTR;
+ case PCD_DATUM_TYPE_UINT8:
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {
+ return EFI_PCD_TYPE_BOOL;
+ } else {
+ return EFI_PCD_TYPE_8;
+ }
+ case PCD_DATUM_TYPE_UINT16:
+ return EFI_PCD_TYPE_16;
+ case PCD_DATUM_TYPE_UINT32:
+ return EFI_PCD_TYPE_32;
+ case PCD_DATUM_TYPE_UINT64:
+ return EFI_PCD_TYPE_64;
+ default:
+ ASSERT (FALSE);
+ return EFI_PCD_TYPE_8;
+ }
+}
+
+/**
+ Get PCD name.
+
+ @param[in] OnlyTokenSpaceName If TRUE, only need to get the TokenSpaceCName.
+ If FALSE, need to get the full PCD name.
+ @param[in] Database PCD database.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The TokenSpaceCName or full PCD name.
+**/
+CHAR8 *
+GetPcdName (
+ IN BOOLEAN OnlyTokenSpaceName,
+ IN PEI_PCD_DATABASE *Database,
+ IN UINTN TokenNumber
+ )
+{
+ UINT8 *StringTable;
+ UINTN NameSize;
+ PCD_NAME_INDEX *PcdNameIndex;
+ CHAR8 *TokenSpaceName;
+ CHAR8 *PcdName;
+ CHAR8 *Name;
+
+ //
+ // Return NULL when PCD name table is absent.
+ //
+ if (Database->PcdNameTableOffset == 0) {
+ return NULL;
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ StringTable = (UINT8 *) Database + Database->StringTableOffset;
+
+ //
+ // Get the PCD name index.
+ //
+ PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
+ TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
+ PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
+
+ if (OnlyTokenSpaceName) {
+ //
+ // Only need to get the TokenSpaceCName.
+ //
+ Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
+ } else {
+ //
+ // Need to get the full PCD name.
+ //
+ NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ //
+ // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
+ //
+ AsciiStrCatS (Name, NameSize, TokenSpaceName);
+ Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
+ AsciiStrCatS (Name, NameSize, PcdName);
+ }
+
+ return Name;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Database PCD database.
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+ExGetPcdInfo (
+ IN PEI_PCD_DATABASE *Database,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ UINTN GuidTableIdx;
+ EFI_GUID *MatchGuid;
+ EFI_GUID *GuidTable;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ UINT32 LocalTokenNumber;
+
+ GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
+ MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
+
+ //
+ // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
+ //
+ for (Index = 0; Index < Database->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to the null-terminated ASCII string
+ // associated with the token's namespace Guid.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ //
+ // Here use one representative in the token space to get the TokenSpaceCName.
+ //
+ PcdInfo->PcdName = GetPcdName (TRUE, Database, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
+ PcdInfo->PcdSize = PeiPcdGetSize (ExMapTable[Index].TokenNumber);
+ LocalTokenNumber = GetLocalTokenNumber (Database, ExMapTable[Index].TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, Database, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+PeiGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ BOOLEAN PeiExMapTableEmpty;
+ UINTN PeiNexTokenNumber;
+ UINT32 LocalTokenNumber;
+
+ ASSERT (PcdInfo != NULL);
+
+ PeiPcdDb = GetPcdDatabase ();
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+
+ if (Guid == NULL) {
+ if (TokenNumber > PeiNexTokenNumber) {
+ return EFI_NOT_FOUND;
+ } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to NULL for default Token Space.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ PcdInfo->PcdName = NULL;
+ } else {
+ PcdInfo->PcdSize = PeiPcdGetSize (TokenNumber);
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, PeiPcdDb, TokenNumber);
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+ return ExGetPcdInfo (
+ PeiPcdDb,
+ Guid,
+ TokenNumber,
+ PcdInfo
+ );
+ }
+}
+
+/**
+ The function registers the CallBackOnSet fucntion
+ according to TokenNumber and EFI_GUID space.
+
+ @param ExTokenNumber The token number.
+ @param Guid The GUID space.
+ @param CallBackFunction The Callback function to be registered.
+ @param Register To register or unregister the callback function.
+
+ @retval EFI_SUCCESS If the Callback function is registered.
+ @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.
+ @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free
+ slot left in the CallbackFnTable.
+ @retval EFI_INVALID_PARAMETER If the callback function want to be de-registered can not be found.
+**/
+EFI_STATUS
+PeiRegisterCallBackWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PPI_CALLBACK CallBackFunction,
+ IN BOOLEAN Register
+)
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PCD_PPI_CALLBACK *CallbackTable;
+ PCD_PPI_CALLBACK Compare;
+ PCD_PPI_CALLBACK Assign;
+ UINT32 LocalTokenNumber;
+ UINT32 LocalTokenCount;
+ UINTN PeiNexTokenNumber;
+ UINTN TokenNumber;
+ UINTN Idx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ PeiPcdDb = GetPcdDatabase();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+
+ if (Guid == NULL) {
+ TokenNumber = ExTokenNumber;
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ ASSERT (TokenNumber + 1 < (PeiNexTokenNumber + 1));
+ } else {
+ TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT ((TokenNumber + 1) < (LocalTokenCount + 1));
+ }
+
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);
+
+ //
+ // We don't support SET for HII and VPD type PCD entry in PEI phase.
+ // So we will assert if any register callback for such PCD entry.
+ //
+ ASSERT ((LocalTokenNumber & PCD_TYPE_HII) == 0);
+ ASSERT ((LocalTokenNumber & PCD_TYPE_VPD) == 0);
+
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ ASSERT (GuidHob != NULL);
+
+ CallbackTable = GET_GUID_HOB_DATA (GuidHob);
+ CallbackTable = CallbackTable + (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
+
+ Compare = Register? NULL: CallBackFunction;
+ Assign = Register? CallBackFunction: NULL;
+
+
+ for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
+ if (CallbackTable[Idx] == Compare) {
+ CallbackTable[Idx] = Assign;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return Register? EFI_OUT_OF_RESOURCES : EFI_INVALID_PARAMETER;
+
+}
+
+
+/**
+ Find the Pcd database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @retval The base address of external PCD database binary.
+ @retval NULL Return NULL if not find.
+**/
+VOID *
+LocateExPcdBinary (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ EFI_STATUS Status;
+ VOID *PcdDb;
+
+ PcdDb = NULL;
+
+ ASSERT (FileHandle != NULL);
+
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check the first bytes (Header Signature Guid) and build version.
+ //
+ if (!CompareGuid (PcdDb, &gPcdDataBaseSignatureGuid) ||
+ (((PEI_PCD_DATABASE *) PcdDb)->BuildVersion != PCD_SERVICE_PEIM_VERSION)) {
+ ASSERT (FALSE);
+ }
+ return PcdDb;
+}
+
+
+/**
+ The function builds the PCD database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @return Pointer to PCD database.
+**/
+PEI_PCD_DATABASE *
+BuildPcdDatabase (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ PEI_PCD_DATABASE *Database;
+ PEI_PCD_DATABASE *PeiPcdDbBinary;
+ VOID *CallbackFnTable;
+ UINTN SizeOfCallbackFnTable;
+
+ //
+ // Locate the external PCD database binary for one section of current FFS
+ //
+ PeiPcdDbBinary = LocateExPcdBinary (FileHandle);
+
+ ASSERT(PeiPcdDbBinary != NULL);
+
+ Database = BuildGuidHob (&gPcdDataBaseHobGuid, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ ZeroMem (Database, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ //
+ // PeiPcdDbBinary is smaller than Database
+ //
+ CopyMem (Database, PeiPcdDbBinary, PeiPcdDbBinary->Length);
+
+ SizeOfCallbackFnTable = Database->LocalTokenCount * sizeof (PCD_PPI_CALLBACK) * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry);
+
+ CallbackFnTable = BuildGuidHob (&gEfiCallerIdGuid, SizeOfCallbackFnTable);
+
+ ZeroMem (CallbackFnTable, SizeOfCallbackFnTable);
+
+ return Database;
+}
+
+/**
+ The function is provided by PCD PEIM and PCD DXE driver to
+ do the work of reading a HII variable from variable service.
+
+ @param VariableGuid The Variable GUID.
+ @param VariableName The Variable Name.
+ @param VariableData The output data.
+ @param VariableSize The size of the variable.
+
+ @retval EFI_SUCCESS Operation successful.
+ @retval EFI_NOT_FOUND Variablel not found.
+**/
+EFI_STATUS
+GetHiiVariable (
+ IN CONST EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ OUT VOID **VariableData,
+ OUT UINTN *VariableSize
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+ VOID *Buffer;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = 0;
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ VariableName,
+ (EFI_GUID *) VariableGuid,
+ NULL,
+ &Size,
+ NULL
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = PeiServicesAllocatePool (Size, &Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ (UINT16 *) VariableName,
+ (EFI_GUID *) VariableGuid,
+ NULL,
+ &Size,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ *VariableSize = Size;
+ *VariableData = Buffer;
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Invoke the callback function when dynamic PCD entry was set, if this PCD entry
+ has registered callback function.
+
+ @param ExTokenNumber DynamicEx PCD's token number, if this PCD entry is dyanmicEx
+ type PCD.
+ @param Guid DynamicEx PCD's guid, if this PCD entry is dynamicEx type
+ PCD.
+ @param TokenNumber PCD token number generated by build tools.
+ @param Data Value want to be set for this PCD entry
+ @param Size The size of value
+
+**/
+VOID
+InvokeCallbackOnSet (
+ UINTN ExTokenNumber,
+ CONST EFI_GUID *Guid, OPTIONAL
+ UINTN TokenNumber,
+ VOID *Data,
+ UINTN Size
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PCD_PPI_CALLBACK *CallbackTable;
+ UINTN Idx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINT32 LocalTokenCount;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ if (Guid == NULL) {
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+ }
+
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ ASSERT (GuidHob != NULL);
+
+ CallbackTable = GET_GUID_HOB_DATA (GuidHob);
+
+ CallbackTable += (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
+
+ for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
+ if (CallbackTable[Idx] != NULL) {
+ CallbackTable[Idx] (Guid,
+ (Guid == NULL) ? (TokenNumber + 1) : ExTokenNumber,
+ Data,
+ Size
+ );
+ }
+ }
+}
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ return SetWorker (TokenNumber, Data, &Size, FALSE);
+}
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ )
+{
+ UINT32 LocalTokenNumber;
+ UINTN PeiNexTokenNumber;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ STRING_HEAD StringTableIdx;
+ UINTN Offset;
+ VOID *InternalData;
+ UINTN MaxSize;
+ UINT32 LocalTokenCount;
+
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ if (PtrType) {
+ //
+ // Get MaxSize first, then check new size with max buffer size.
+ //
+ GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);
+ if (*Size > MaxSize) {
+ *Size = MaxSize;
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (*Size != PeiPcdGetSize (TokenNumber + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // We only invoke the callback function for Dynamic Type PCD Entry.
+ // For Dynamic EX PCD entry, we have invoked the callback function for Dynamic EX
+ // type PCD entry in ExSetWorker.
+ //
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+ if (TokenNumber + 1 < PeiNexTokenNumber + 1) {
+ InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
+ }
+
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ InternalData = (VOID *) ((UINT8 *) PeiPcdDb + Offset);
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ case PCD_TYPE_HII:
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ case PCD_TYPE_STRING:
+ if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
+ StringTableIdx = *((STRING_HEAD *)InternalData);
+ CopyMem ((UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset + StringTableIdx, Data, *Size);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ case PCD_TYPE_DATA:
+ {
+ if (PtrType) {
+ if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
+ CopyMem (InternalData, Data, *Size);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ switch (*Size) {
+ case sizeof(UINT8):
+ *((UINT8 *) InternalData) = *((UINT8 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT16):
+ *((UINT16 *) InternalData) = *((UINT16 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT32):
+ *((UINT32 *) InternalData) = *((UINT32 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT64):
+ *((UINT64 *) InternalData) = *((UINT64 *) Data);
+ return EFI_SUCCESS;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ }
+
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ return ExSetWorker (ExTokenNumber, Guid, Data, &Size, FALSE);
+}
+
+/**
+ Set value for a dynamic-ex PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ )
+{
+ UINTN TokenNumber;
+
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ return EFI_NOT_FOUND;
+ }
+
+ InvokeCallbackOnSet (ExTokenNumber, Guid, TokenNumber, Data, *Size);
+
+ return SetWorker (TokenNumber, Data, Size, PtrType);
+
+}
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dyanmic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ )
+{
+ return GetWorker (GetExPcdTokenNumber (Guid, ExTokenNumber), GetSize);
+}
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ )
+{
+ UINT32 Offset;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+ VARIABLE_HEAD *VariableHead;
+ EFI_STATUS Status;
+ UINTN DataSize;
+ VOID *Data;
+ UINT8 *StringTable;
+ STRING_HEAD StringTableIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINT32 LocalTokenNumber;
+ UINT32 LocalTokenCount;
+ UINT8 *VaraiableDefaultBuffer;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ ASSERT ((GetSize == PeiPcdGetSize(TokenNumber + 1)) || (GetSize == 0));
+
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ StringTable = (UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset;
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ {
+ VPD_HEAD *VpdHead;
+ VpdHead = (VPD_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
+ return (VOID *) ((UINTN) PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);
+ }
+
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ case PCD_TYPE_HII:
+ {
+ VariableHead = (VARIABLE_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
+
+ Guid = (EFI_GUID *) ((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + VariableHead->GuidTableIndex;
+ Name = (UINT16*)&StringTable[VariableHead->StringIndex];
+
+ if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
+ //
+ // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
+ // string array in string table.
+ //
+ VaraiableDefaultBuffer = (UINT8 *) &StringTable[*(STRING_HEAD*)((UINT8*) PeiPcdDb + VariableHead->DefaultValueOffset)];
+ } else {
+ VaraiableDefaultBuffer = (UINT8 *) PeiPcdDb + VariableHead->DefaultValueOffset;
+ }
+ Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
+ if ((Status == EFI_SUCCESS) && (DataSize >= (VariableHead->Offset + GetSize))) {
+ if (GetSize == 0) {
+ //
+ // It is a pointer type. So get the MaxSize reserved for
+ // this PCD entry.
+ //
+ GetPtrTypeSize (TokenNumber, &GetSize, PeiPcdDb);
+ if (GetSize > (DataSize - VariableHead->Offset)) {
+ //
+ // Use actual valid size.
+ //
+ GetSize = DataSize - VariableHead->Offset;
+ }
+ }
+ //
+ // If the operation is successful, we copy the data
+ // to the default value buffer in the PCD Database.
+ //
+ CopyMem (VaraiableDefaultBuffer, (UINT8 *) Data + VariableHead->Offset, GetSize);
+ }
+ return (VOID *) VaraiableDefaultBuffer;
+ }
+
+ case PCD_TYPE_DATA:
+ return (VOID *) ((UINT8 *)PeiPcdDb + Offset);
+
+ case PCD_TYPE_STRING:
+ StringTableIdx = * (STRING_HEAD*) ((UINT8 *) PeiPcdDb + Offset);
+ return (VOID *) (&StringTable[StringTableIdx]);
+
+ default:
+ ASSERT (FALSE);
+ break;
+
+ }
+
+ ASSERT (FALSE);
+
+ return NULL;
+
+}
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Dynamic-ex PCD token number.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ UINT32 Index;
+ DYNAMICEX_MAPPING *ExMap;
+ EFI_GUID *GuidTable;
+ EFI_GUID *MatchGuid;
+ UINTN MatchGuidIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ PeiPcdDb = GetPcdDatabase();
+
+ ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);
+ //
+ // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
+ // error in the BUILD system.
+ //
+ ASSERT (MatchGuid != NULL);
+
+ MatchGuidIdx = MatchGuid - GuidTable;
+
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
+ (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
+ return ExMap[Index].TokenNumber;
+ }
+ }
+
+ return PCD_INVALID_TOKEN_NUMBER;
+}
+
+/**
+ Get PCD database from GUID HOB in PEI phase.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+GetPcdDatabase (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
+ ASSERT (GuidHob != NULL);
+
+ return (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
+}
+
+/**
+ Get index of PCD entry in size table.
+
+ @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
+ @param Database Pointer to PCD database in PEI phase.
+
+ @return index of PCD entry in size table.
+
+**/
+UINTN
+GetSizeTableIndex (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ UINTN Index;
+ UINTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+
+ SizeTableIdx = 0;
+
+ for (Index = 0; Index < LocalTokenNumberTableIdx; Index++) {
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + Index);
+
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // Current size is equal to MAX size.
+ //
+ SizeTableIdx += 2;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTableIdx += 2;
+ }
+ }
+
+ }
+
+ return SizeTableIdx;
+}
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h
new file mode 100644
index 0000000000..3a7910a900
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h
@@ -0,0 +1,1088 @@
+/** @file
+ The internal header file declares the private functions used by PeiPcd driver.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_PCD_SERVICE_H_
+#define _PEI_PCD_SERVICE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/Pcd.h>
+#include <Ppi/PiPcd.h>
+#include <Ppi/PcdInfo.h>
+#include <Ppi/PiPcdInfo.h>
+#include <Guid/PcdDataBaseHobGuid.h>
+#include <Guid/PcdDataBaseSignatureGuid.h>
+#include <Guid/VariableFormat.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Please make sure the PCD Serivce PEIM Version is consistent with
+// the version of the generated PEIM PCD Database by build tool.
+//
+#define PCD_SERVICE_PEIM_VERSION 7
+
+//
+// PCD_PEI_SERVICE_DRIVER_VERSION is defined in Autogen.h.
+//
+#if (PCD_SERVICE_PEIM_VERSION != PCD_PEI_SERVICE_DRIVER_VERSION)
+ #error "Please make sure the version of PCD PEIM Service and the generated PCD PEI Database match."
+#endif
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+PeiGetPcdInfoGetSku (
+ VOID
+ );
+
+//
+// PPI Interface Implementation Declaration.
+//
+
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default. The valid SkuId range is 1 to 255.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+PeiPcdSetSku (
+ IN UINTN SkuId
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtr (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBool (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSize (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ );
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param [in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param [in] TokenNumber The PCD token number.
+ @param [in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PcdUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ );
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request
+ is being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service has retrieved the next valid token number.
+ Or the input token number is already the last valid token number in the PCD database.
+ In the later case, *TokenNumber is updated with the value of 0.
+ @retval EFI_NOT_FOUND If this input token number and token namespace does not exist on the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ );
+
+/**
+ Retrieves the next valid PCD token namespace for a given namespace.
+
+ @param[in, out] Guid An indirect pointer to EFI_GUID. On input it designates
+ a known token namespace from which the search will start. On output,
+ it designates the next valid token namespace on the platform. If the input
+ token namespace does not exist on the platform, an error is returned and
+ the value of *Guid is undefined. If *Guid is NULL, then the GUID of the
+ first token space of the current platform is assigned to *Guid the function
+ return EFI_SUCCESS. If *Guid is NULL and there is no namespace exist in
+ the platform other than the default (NULL) tokennamespace, *Guid is unchanged
+ and the function return EFI_SUCCESS. If this input token namespace is the last
+ namespace on the platform, *Guid will be assigned to NULL and the function return
+ EFI_SUCCESS.
+
+ @retval EFI_SUCCESS The PCD service retrieved the next valid token space Guid.
+ Or the input token space Guid is already the last valid token space Guid
+ in the PCD database. In the later case, *Guid is updated with the value of NULL.
+ @retval EFI_NOT_FOUND If the input token namespace does not exist on the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ );
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+PeiGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/* Internal Function definitions */
+/**
+ Get PCD database from GUID HOB in PEI phase.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+GetPcdDatabase (
+ VOID
+ );
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ );
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN Size
+ );
+
+/**
+ Set value for a dynamic PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ );
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dyanmic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ );
+
+typedef struct {
+ UINTN TokenNumber;
+ UINTN Size;
+ UINT32 LocalTokenNumberAlias;
+} EX_PCD_ENTRY_ATTRIBUTE;
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ );
+
+/**
+ The function registers the CallBackOnSet fucntion
+ according to TokenNumber and EFI_GUID space.
+
+ @param TokenNumber The token number.
+ @param Guid The GUID space.
+ @param CallBackFunction The Callback function to be registered.
+ @param Register To register or unregister the callback function.
+
+ @retval EFI_SUCCESS If the Callback function is registered.
+ @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.
+ @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free
+ slot left in the CallbackFnTable.
+**/
+EFI_STATUS
+PeiRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PPI_CALLBACK CallBackFunction,
+ IN BOOLEAN Register
+ );
+
+/**
+ The function builds the PCD database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+BuildPcdDatabase (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ );
+
+/**
+ Get index of PCD entry in size table.
+
+ @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
+ @param Database Pointer to PCD database.
+
+ @return index of PCD entry in size table.
+
+**/
+UINTN
+GetSizeTableIndex (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+/**
+ Get PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specificed size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param MaxSize Maxmium size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @return PCD value's size for POINTER type PCD.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+/**
+ Set PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specificed size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param CurrentSize Maxmium size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @retval TRUE Success to set PCD's value size, which is not exceed maxmium size
+ @retval FALSE Fail to set PCD's value size, which maybe exceed maxmium size
+
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+#endif
+