summaryrefslogtreecommitdiff
path: root/Platform
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-23 14:34:36 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:15:26 +0800
commitee3c51a87edd88adcce0899b2fc1c4e8596c5194 (patch)
tree0b7c882151ee90cd52218398aac2f17aa95bf29e /Platform
parentb7d3a1c6e9df0b25d55d2855ffb989d5c164e60c (diff)
downloadedk2-platforms-ee3c51a87edd88adcce0899b2fc1c4e8596c5194.tar.xz
BroxtonPlatformPkg: Add MdeModulePkg
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Platform')
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c84
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c554
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c251
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h33
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c1304
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c2345
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h384
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c167
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c878
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c266
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c132
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.unibin0 -> 2822 bytes
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.unibin0 -> 1346 bytes
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h1707
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf120
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c456
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c634
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c59
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c152
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c73
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c80
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c239
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c1706
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h1359
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c1562
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c871
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf101
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c330
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c436
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h138
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf63
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.unibin0 -> 2194 bytes
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.unibin0 -> 1372 bytes
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c1424
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf353
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c1221
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h1120
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c1185
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h151
-rw-r--r--Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf77
40 files changed, 22015 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..4d88da02ee
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/BootMode/BootMode.c
@@ -0,0 +1,84 @@
+/** @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 - 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.
+
+**/
+
+#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..c096590760
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c
@@ -0,0 +1,554 @@
+/** @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 - 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.
+
+**/
+
+#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[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Width The width of the access. Enumerated in bytes.
+ @param[in] Address The physical address of the access.
+ @param[in] Count The number of accesses to perform.
+ @param[in, out] 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[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Width The width of the access. Enumerated in bytes.
+ @param[in] Address The physical address of the access.
+ @param[in] Count The number of accesses to perform.
+ @param[in, out] 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[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Width The width of the access. Enumerated in bytes.
+ @param[in] Address The physical address of the access.
+ @param[in] Count The number of accesses to perform.
+ @param[in, out] 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[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Width The width of the access. Enumerated in bytes.
+ @param[in] Address The physical address of the access.
+ @param[in] Count The number of accesses to perform.
+ @param[in, out] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param[in] This Pointer to local data for the interface.
+ @param[in] Address The physical address of the access.
+ @param[in] 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..277e5eed4a
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.c
@@ -0,0 +1,251 @@
+/** @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 - 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.
+
+**/
+
+#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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] 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..d9a4bcf02c
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dependency/Dependency.h
@@ -0,0 +1,33 @@
+/** @file
+ This module contains data specific to dependency expressions
+ and local function prototypes.
+
+ 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_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..7b2de6aad2
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -0,0 +1,1304 @@
+/** @file
+ EFI PEI Core dispatch services.
+
+ 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.
+
+**/
+
+#include "PeiMain.h"
+
+///
+/// temporary memory is filled with this initial value during SEC phase
+///
+#define INIT_CAR_VALUE 0x5AA55AA5
+
+typedef struct {
+ EFI_STATUS_CODE_DATA DataHeader;
+ EFI_HANDLE Handle;
+} PEIM_FILE_HANDLE_EXTENDED_DATA;
+
+/**
+ Discover all Peims and optional Apriori file in one FV. There is at most one
+ Apriori file in one FV.
+
+ @param[in] Private Pointer to the private data passed in from caller
+ @param[in] 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[in] PrivateData Pointer to the private data passed in from caller
+ @param[in] 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[in] 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[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 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);
+}
+
+/**
+ Conduct PEIM dispatch.
+
+ @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
+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;
+ PEIM_FILE_HANDLE_EXTENDED_DATA ExtendedData;
+ EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
+ UINT64 NewStackSize;
+ UINTN HeapTemporaryRamSize;
+ EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
+ EFI_PHYSICAL_ADDRESS TopOfNewStack;
+ EFI_PHYSICAL_ADDRESS TopOfOldStack;
+ EFI_PHYSICAL_ADDRESS TemporaryRamBase;
+ UINTN TemporaryRamSize;
+ UINTN TemporaryStackSize;
+ VOID *TemporaryStackBase;
+ UINTN PeiTemporaryRamSize;
+ VOID *PeiTemporaryRamBase;
+ UINTN StackOffset;
+ BOOLEAN StackOffsetPositive;
+ EFI_PHYSICAL_ADDRESS HoleMemBase;
+ UINTN HoleMemSize;
+ EFI_FV_FILE_INFO FvFileInfo;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+ VOID *LoadFixPeiCodeBegin;
+ EFI_PHYSICAL_ADDRESS TempBase1;
+ UINTN TempSize1;
+ EFI_PHYSICAL_ADDRESS TempBase2;
+ UINTN TempSize2;
+ UINTN Index;
+
+ 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];
+ 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]++;
+ Private->CurrentFileHandle = PeimFileHandle;
+ Private->CurrentPeimFvCount = Index1;
+ Private->CurrentPeimCount = 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 FV 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 {
+ //
+ // 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);
+
+ ExtendedData.Handle = (EFI_HANDLE) PeimFileHandle;
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
+ (VOID *) (&ExtendedData),
+ sizeof (ExtendedData)
+ );
+
+ 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;
+ }
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
+ (VOID *) (&ExtendedData),
+ sizeof (ExtendedData)
+ );
+ PERF_END (PeimFileHandle, "PEIM", NULL, 0);
+
+ }
+ }
+
+ if (Private->SwitchStackSignal) {
+ //
+ // Before switch stack from temporary memory to permenent memory, caculate the heap and stack
+ // usage in temporary memory for debuging.
+ //
+ DEBUG_CODE_BEGIN ();
+ UINT32 *StackPointer;
+ for (StackPointer = (UINT32 *) SecCoreData->StackBase;
+ (StackPointer < (UINT32 *) ((UINTN) SecCoreData->StackBase + SecCoreData->StackSize)) \
+ && (*StackPointer == INIT_CAR_VALUE);
+ StackPointer ++);
+
+ DEBUG ((EFI_D_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32) SecCoreData->StackSize));
+ DEBUG ((EFI_D_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", Private->HobList.Raw, (UINT32) ((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN) Private->HobList.Raw)));
+ DEBUG ((EFI_D_INFO, "Total temporary memory: %d bytes.\n", (UINT32) SecCoreData->TemporaryRamSize));
+ DEBUG ((EFI_D_INFO, " temporary memory stack ever used: %d bytes.\n",
+ (UINT32) (SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN) SecCoreData->StackBase))
+ ));
+ DEBUG ((EFI_D_INFO, " temporary memory heap used: %d bytes.\n",
+ (UINT32) ((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
+ ));
+ 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 permenent 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 permenent 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);
+
+ //
+ // Caculate 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));
+
+ //
+ // Caculate 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 permenent 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
+ );
+ //
+ // Entry PEI Phase 2
+ //
+ PeiCore (SecCoreData, NULL, Private);
+ } else {
+ //
+ // 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, (UINT8 *) PeiTemporaryRamBase, HeapTemporaryRamSize);
+
+ //
+ // Migrate Stack
+ //
+ CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
+
+ //
+ // Copy Hole Range Data
+ // Convert PPI from Hole.
+ //
+ 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);
+ }
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessNotifyList (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 availble 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);
+ 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 that did not get
+ // dispatched. So we need to make another pass
+ //
+ // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM on this
+ // pass. If we did not dispatch a PEIM 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[in] PrivateData PeiCore's private data structure
+ @param[in] OldCoreData Old data from SecCore
+ NULL if being run in non-permament memory mode.
+ @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.
+
+ @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[in] Private PeiCore's private data structure
+ @param[in] FileHandle PEIM's file handle
+ @param[in] 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[in] 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..c52df00f36
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.c
@@ -0,0 +1,2345 @@
+/** @file
+ Pei Core Firmware File System service routines.
+
+ 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.
+
+**/
+
+#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 Alignment Value in
+ (bytes) Attributes Field Firmware Volume Interfaces
+ 1 0 0
+ 16 1 4
+ 128 2 7
+ 512 3 9
+ 1 KB 4 10
+ 4 KB 5 12
+ 32 KB 6 15
+ 64 KB 7 16
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+
+/**
+ Convert the FFS File Attributes to FV File Attributes
+
+ @param[in] 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);
+
+ 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[in] ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
+ in the Attributes field.
+ @param[in] 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[in] 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[in] 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;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ 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))) {
+ return &PrivateData->Fv[Index];
+ }
+ }
+ 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[in] FvHandle Pointer to the FV header of the volume to search
+ @param[in] FileName File name
+ @param[in] SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param[in, out] FileHandle This parameter must point to a valid FFS volume.
+ @param[in, out] 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[in] PrivateData Pointer to PEI_CORE_INSTANCE.
+ @param[in] 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,
+ BfvHeader->FvLength,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //Override: Start
+ //
+ // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
+ // additional Fvs to PeiCore.
+ //
+ //Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
+ //ASSERT_EFI_ERROR (Status);
+//Override: End
+}
+
+/**
+ 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
+ @retval Other 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;
+ EFI_FV_INFO FvInfo;
+ EFI_FV_INFO TempFvInfo;
+ BOOLEAN CheckFvName;
+ UINTN Index;
+ EFI_PEI_FV_HANDLE OrgFvHandle;
+
+ Status = EFI_SUCCESS;
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei\n", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
+ DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC \n"));
+ ASSERT (FALSE);
+ }
+
+ 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;
+ }
+
+ //
+ // 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.
+ //
+ CheckFvName = TRUE;
+ FvPpi->GetVolumeInfo (FvPpi, FvHandle, &FvInfo);
+ if (CompareGuid (&FvInfo.FvName, &gZeroGuid)) {
+ CheckFvName = FALSE;
+ }
+
+ 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 (CheckFvName) {
+ PrivateData->Fv[FvIndex].FvPpi->GetVolumeInfo (PrivateData->Fv[FvIndex].FvPpi, PrivateData->Fv[FvIndex].FvHandle, &TempFvInfo);
+ if (CompareGuid (&FvInfo.FvName, &TempFvInfo.FvName)) {
+ //
+ // They are same. Switch its data from original Handle to new Handle.
+ //
+ OrgFvHandle = PrivateData->Fv[FvIndex].FvHandle;
+ PrivateData->Fv[FvIndex].FvHandle = FvHandle;
+ PrivateData->Fv[FvIndex].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvInfo2Ppi.FvInfo;
+ PrivateData->Fv[FvIndex].FvPpi = FvPpi;
+ if (PrivateData->Fv[FvIndex].ScanFv) {
+ for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv) && (PrivateData->Fv[FvIndex].FvFileHandles[Index] != NULL); Index ++) {
+ PrivateData->Fv[FvIndex].FvFileHandles[Index] = (EFI_PEI_FILE_HANDLE *) (VOID *) ((UINTN) (VOID *) PrivateData->Fv[FvIndex].FvFileHandles[Index] - (UINTN) (VOID *) OrgFvHandle + (UINTN) (VOID *) FvHandle);
+ }
+ if (PrivateData->CurrentPeimFvCount == FvIndex) {
+ PrivateData->CurrentFileHandle =(EFI_PEI_FILE_HANDLE *) (VOID *) ((UINTN) (VOID *) PrivateData->CurrentFileHandle - (UINTN) (VOID *) OrgFvHandle + (UINTN) (VOID *) FvHandle);
+ for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv) && (PrivateData->CurrentFvFileHandles[Index] != NULL); Index ++) {
+ PrivateData->CurrentFvFileHandles[Index] = (EFI_PEI_FILE_HANDLE *) (VOID *) ((UINTN) (VOID *) PrivateData->CurrentFvFileHandles[Index] - (UINTN) (VOID *) OrgFvHandle + (UINTN) (VOID *) FvHandle);
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "The Fv has been migrated from %p to %p!\n", OrgFvHandle, FvHandle));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // 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;
+ 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 *) 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, PrivateData->FvCount - 1, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[PrivateData->FvCount - 1], 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[in] GuidedSectionGuid The Guided Section GUID.
+ @param[in] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] SectionType Filter to find only section of this type.
+ @param[in, out] SectionInstance Pointer to the filter to find the specific instance of section.
+ @param[in] Section From where to search.
+ @param[in] SectionSize The file size to search.
+ @param[out] OutputBuffer A pointer to the discovered section, if successful.
+ NULL if section not found
+ @param[out] AuthenticationStatus Updated upon return to point to the authentication status for this section.
+ @param[in] IsFfs3Fv Indicates the FV format.
+
+ @retval EFI_NOT_FOUND The match section is not found.
+ @retval 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)) {
+ //
+ // 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] SectionType Filter to find only sections of this type.
+ @param[in] FileHandle Pointer to the current file to search.
+ @param[out] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] SectionType The value of the section type to find.
+ @param[in] SectionInstance Section instance to find.
+ @param[in] FileHandle Handle of the firmware file to search.
+ @param[out] SectionData A pointer to the discovered section, if successful.
+ @param[out] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param[in] FvHandle Handle of firmware volume in which to search.
+ @param[in, out] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
+ Volume (BFV).
+ @param[in, out] 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[in] FileName A pointer to the name of the file to find within the firmware volume.
+ @param[in] VolumeHandle The firmware volume to search
+ @param[out] 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[in] FileHandle Handle of the file.
+ @param[out] 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[in] FileHandle Handle of the file.
+ @param[out] 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[in] VolumeHandle Handle of the volume.
+ @param[out] 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);
+}
+
+/**
+ Get Fv image from the FV type file, then install FV INFO(2) ppi, Build FV hob.
+
+ @param[in] PrivateData PeiCore's private data structure
+ @param[in] ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
+ @param[in] 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;
+
+ //
+ // 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;
+ }
+
+ //
+ // Check FvImage
+ //
+ 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;
+ }
+ 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
+ //
+ PeiServicesInstallFvInfoPpi (
+ &FvHeader->FileSystemGuid,
+ (VOID**) FvHeader,
+ (UINT32) FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ PeiServicesInstallFvInfo2Ppi (
+ &FvHeader->FileSystemGuid,
+ (VOID**) FvHeader,
+ (UINT32) FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName,
+ AuthenticationStatus
+ );
+
+ //
+ // 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
+ );
+
+ 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] Buffer Points to the start of the buffer.
+ @param[in] BufferSize Size of the buffer.
+ @param[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] SearchType A filter to find only files of this type. Type
+ EFI_FV_FILETYPE_ALL causes no filtering to be
+ done.
+ @param[in] FvHandle Handle of firmware volume in which to
+ search.
+ @param[in, out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] FileName A pointer to the name of the file to find
+ within the firmware volume.
+ @param[in] 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[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] FileHandle Handle of the file.
+ @param[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] FileHandle Handle of the file.
+ @param[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] FvHandle Handle to the firmware handle.
+ @param[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] SearchType A filter to find only sections of this
+ type.
+ @param[in] FileHandle Handle of firmware file in which to
+ search.
+ @param[out] 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[in] This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param[in] SearchType A filter to find only sections of this
+ type.
+ @param[in] SearchInstance A filter to find the specific instance
+ of sections.
+ @param[in] FileHandle Handle of firmware file in which to
+ search.
+ @param[out] SectionData Updated upon return to point to the
+ section found.
+ @param[out] 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[in] 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[in] Private Pointer of PEI_CORE_INSTANCE
+ @param[in] 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 <= FixedPcdGet32 (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 permenant
+ memory.
+
+ @param[in] 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;
+
+ //
+ // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
+ // additional Fvs to PeiCore.
+ //
+ Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
+ ASSERT_EFI_ERROR (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 < FixedPcdGet32 (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 < FixedPcdGet32 (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[in] PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param[in] 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 >= FixedPcdGet32 (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[in] PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param[in] Format Point to given FV format guid
+ @param[out] FvInfo On return, the pointer of FV information buffer
+ @param[out] FvInfoSize On return, the size of FV information buffer.
+ @param[out] 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[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] 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;
+
+ 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 >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (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;
+ 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 *) 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, PrivateData->FvCount - 1, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[PrivateData->FvCount - 1], 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..aec46da283
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/FwVol/FwVol.h
@@ -0,0 +1,384 @@
+/** @file
+ The internal header file for firmware volume related definitions.
+
+ Copyright (c) 2009 - 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 _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..e731a7ec0f
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Hob/Hob.c
@@ -0,0 +1,167 @@
+/** @file
+ This module provide Hand-Off Block manupulation.
+
+ 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.
+
+**/
+
+#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;
+}
+
+/**
+
+ 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..08c05fe765
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Image/Image.c
@@ -0,0 +1,878 @@
+/** @file
+ Pei Core Load Image Support.
+
+ 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.
+
+**/
+
+#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
+ )
+{
+ PEI_CORE_INSTANCE *Private;
+ VOID* MemoryBuffer;
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ if (Private->PeiMemoryInstalled && ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) || PcdGetBool (PcdShadowPeimOnS3Boot)) &&
+ (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) || EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_IA32))) {
+ //
+ // 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) {
+ MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);
+ ASSERT (MemoryBuffer != NULL);
+ CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400);
+ Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;
+ }
+
+ ImageContext->ImageRead = Private->ShadowedImageRead;
+ } else {
+ ImageContext->ImageRead = PeiImageRead;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is avaliable, the function will mark the correponding 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 addres 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 loadding 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 loadding 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 FixLoaddingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoaddingAddress = 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 loadding 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 = (UINTN) (
+ 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 fileds 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 runing in memory
+ //
+ FixLoaddingAddress = 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.
+ //
+ FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
+ }
+ //
+ // Check if the memory range is avaliable.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loadding address
+ //
+ ImageContext->ImageAddress = FixLoaddingAddress;
+ }
+ }
+ 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)FixLoaddingAddress, 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 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 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;
+
+ 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;
+ }
+
+ //
+ // XIP image that ImageAddress is same to Image handle.
+ //
+ if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ IsXipImage = TRUE;
+ }
+
+ //
+ // When Image has no reloc section, it can't be relocated into memory.
+ //
+ if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || 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, boot mode is not S3, and image is relocatable.
+ //
+ if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || 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.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
+ }
+ } else {
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
+ }
+ if (ImageContext.ImageAddress != 0) {
+ //
+ // 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 (
+ 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..689e8e17b4
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
@@ -0,0 +1,266 @@
+/** @file
+ EFI PEI Core memory services.
+
+ 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.
+
+**/
+
+#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 (PrivateData->PeiMemoryInstalled);
+ return EFI_SUCCESS;
+ }
+
+ PrivateData->PhysicalMemoryBegin = MemoryBegin;
+ PrivateData->PhysicalMemoryLength = MemoryLength;
+ PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
+
+ PrivateData->SwitchStackSignal = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The purpose of the service is to publish an interface that allows
+ PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+ @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
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;
+ UINTN RemainingPages;
+
+ if ((MemoryType != EfiLoaderCode) &&
+ (MemoryType != EfiLoaderData) &&
+ (MemoryType != EfiRuntimeServicesCode) &&
+ (MemoryType != EfiRuntimeServicesData) &&
+ (MemoryType != EfiBootServicesCode) &&
+ (MemoryType != EfiBootServicesData) &&
+ (MemoryType != EfiACPIReclaimMemory) &&
+ (MemoryType != EfiReservedMemoryType) &&
+ (MemoryType != EfiACPIMemoryNVS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ //
+ // Check if Hob already available
+ //
+ if (!PrivateData->PeiMemoryInstalled) {
+ //
+ // When PeiInstallMemory is called but temporary memory has *not* been moved to temporary memory,
+ // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
+ //
+ if (!PrivateData->SwitchStackSignal) {
+ return EFI_NOT_AVAILABLE_YET;
+ } else {
+ FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
+ FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);
+ }
+ } else {
+ FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
+ FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
+ }
+
+ //
+ // Check to see if on 4k boundary, If not aligned, make the allocation aligned.
+ //
+ *(FreeMemoryTop) -= *(FreeMemoryTop) & 0xFFF;
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation
+ //
+ RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;
+ //
+ // For page allocation, the overhead sizeof (EFI_HOB_MEMORY_ALLOCATION) needs one extra page.
+ // So the number of remaining pages needs to be greater than that of the request pages.
+ //
+ if (RemainingPages <= Pages) {
+ 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.
+ //
+ BuildMemoryAllocationHob (
+ *(FreeMemoryTop),
+ Pages * EFI_PAGE_SIZE,
+ MemoryType
+ );
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Pool allocation service. Before permenent 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..8da6034ceb
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c
@@ -0,0 +1,132 @@
+/** @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 - 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.
+
+**/
+
+#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..fdb8bf0604
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCore.uni
Binary files differ
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..4d81c3ea1e
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiCoreExtra.uni
Binary files differ
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..3a34b06a2d
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.h
@@ -0,0 +1,1707 @@
+/** @file
+ Definition of Pei Core Structures and Services.
+
+ 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_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/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 <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>
+#include <Guid/ZeroGuid.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;
+ 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 phisical 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 stack 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
+ );
+
+//
+// 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
+ );
+
+
+//
+// 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
+ );
+
+/**
+ Memory allocation service on permanent memory,
+ not usable prior to the memory installation.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryType Type of memory to allocate.
+ @param Pages Number of pages to allocate.
+ @param Memory Pointer of memory allocated.
+
+ @retval EFI_SUCCESS The allocation was successful
+ @retval EFI_INVALID_PARAMETER Only AllocateAnyAddress is supported.
+ @retval EFI_NOT_AVAILABLE_YET Called with permanent memory not available
+ @retval EFI_OUT_OF_RESOURCES There is not enough HOB heap to satisfy the requirement
+ to allocate the number of pages.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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 permenent 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 permenant
+ 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..aa5b7e07d0
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -0,0 +1,120 @@
+## @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 - 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.
+#
+##
+
+[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
+ gZeroGuid
+
+[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
+
+[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
+
+[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..3a697128e6
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
@@ -0,0 +1,456 @@
+/** @file
+ Platform Info driver to public platform related HOB data.
+
+ 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.
+
+**/
+
+#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
+};
+
+/**
+ 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);
+ }
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Fixup for PeiService's address
+ //
+ SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Update HandOffHob for new installed permenent 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 the PPI descriptor's pointer
+ //
+ ConvertPpiPointers (SecCoreData, OldCoreData);
+
+ //
+ // After the whole temporary memory is migrated, then we can allocate page in
+ // permenent 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 = 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();
+ }
+
+ //
+ // 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;
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
+
+ //
+ // Save PeiServicePointer so that it can be retrieved anywhere.
+ //
+ SetPeiServicesTablePointer ((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 any PPI services to PEI, install them.
+ //
+ if (PpiList != NULL) {
+ Status = PeiServicesInstallPpi (PpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } 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);
+
+ //
+ // Check if InstallPeiMemory service was called.
+ //
+ 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);
+
+ //
+ // 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();
+}
+
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..a932d26125
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Ppi/Ppi.c
@@ -0,0 +1,634 @@
+/** @file
+ EFI PEI Core PPI services.
+
+ 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.
+
+**/
+
+#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
+ConverSinglePpiPointer (
+ 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 stack 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) {
+ //
+ // Convert PPI pointer in old Heap
+ //
+ ConverSinglePpiPointer (
+ &PrivateData->PpiData.PpiListPtrs[Index],
+ (UINTN)SecCoreData->PeiTemporaryRamBase,
+ (UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
+ PrivateData->HeapOffset,
+ PrivateData->HeapOffsetPositive
+ );
+
+ //
+ // Convert PPI pointer in old Stack
+ //
+ ConverSinglePpiPointer (
+ &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;
+ }
+
+ ConverSinglePpiPointer (
+ &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.
+
+ @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
+ )
+{
+ 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++;
+
+ //
+ // Continue until the end of the PPI List.
+ //
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_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 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.
+
+ @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
+ )
+{
+ 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 ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_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;
+}
+
+/**
+ 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
+ );
+ }
+ }
+ }
+}
+
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..112fad6560
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Reset/Reset.c
@@ -0,0 +1,59 @@
+/** @file
+ Pei Core Reset System Support.
+
+ 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.
+
+**/
+
+#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;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiResetPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &ResetPpi
+ );
+
+ //
+ // LocatePpi returns EFI_NOT_FOUND on error
+ //
+ 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)
+ );
+ return EFI_NOT_AVAILABLE_YET;
+}
+
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..c0c664d3a3
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/Security/Security.c
@@ -0,0 +1,152 @@
+/** @file
+ EFI PEI Core Security services.
+
+ 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.
+
+**/
+
+#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..64e11eacc7
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c
@@ -0,0 +1,73 @@
+/** @file
+ Pei Core Status Code Support.
+
+ 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.
+
+**/
+
+#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/Console/TerminalDxe/Ansi.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c
new file mode 100644
index 0000000000..72d52a20d6
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c
@@ -0,0 +1,80 @@
+/** @file
+ Implementation of translation upon PC ANSI.
+
+ 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.
+
+**/
+
+#include "Terminal.h"
+
+/**
+ Translate all raw data in the Raw FIFO into unicode, and insert
+ them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+AnsiRawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 RawData;
+
+ //
+ // pop the raw data out from the raw fifo,
+ // and translate it into unicode, then push
+ // the unicode into unicode fifo, until the raw fifo is empty.
+ //
+ while (!IsRawFiFoEmpty (TerminalDevice) && !IsUnicodeFiFoFull (TerminalDevice)) {
+
+ RawFiFoRemoveOneKey (TerminalDevice, &RawData);
+
+ UnicodeFiFoInsertOneKey (TerminalDevice, (UINT16) RawData);
+ }
+}
+
+/**
+ Check if input string is valid Ascii string, valid EFI control characters
+ or valid text graphics.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_UNSUPPORTED If not all input characters are valid.
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+AnsiTestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ )
+{
+ CHAR8 GraphicChar;
+
+ //
+ // support three kind of character:
+ // valid ascii, valid efi control char, valid text graphics.
+ //
+ for (; *WString != CHAR_NULL; WString++) {
+
+ if ( !(TerminalIsValidAscii (*WString) ||
+ TerminalIsValidEfiCntlChar (*WString) ||
+ TerminalIsValidTextGraphics (*WString, &GraphicChar, NULL) )) {
+
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c
new file mode 100644
index 0000000000..8b6eda5499
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c
@@ -0,0 +1,239 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Terminal 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.
+
+**/
+
+#include "Terminal.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName = {
+ TerminalComponentNameGetDriverName,
+ TerminalComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gTerminalComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) TerminalComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) TerminalComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mTerminalDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Serial Terminal Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mTerminalDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gTerminalComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ TERMINAL_DEV *TerminalDevice;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gTerminalDriverBinding.DriverBindingHandle,
+ &gEfiSerialIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // This is a bus driver, so ChildHandle can not be NULL.
+ //
+ if (ChildHandle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiSerialIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our context back
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ gTerminalDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ TerminalDevice->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gTerminalComponentName)
+ );
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
new file mode 100644
index 0000000000..2470ad08d4
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -0,0 +1,1706 @@
+/** @file
+ Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
+ Simple Text Output Protocol upon Serial IO Protocol.
+
+ 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.
+
+**/
+
+#include "Terminal.h"
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
+ TerminalDriverBindingSupported,
+ TerminalDriverBindingStart,
+ TerminalDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+EFI_GUID *gTerminalType[] = {
+ &gEfiPcAnsiGuid,
+ &gEfiVT100Guid,
+ &gEfiVT100PlusGuid,
+ &gEfiVTUTF8Guid
+};
+
+
+TERMINAL_DEV mTerminalDevTemplate = {
+ TERMINAL_DEV_SIGNATURE,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ { // SimpleTextInput
+ TerminalConInReset,
+ TerminalConInReadKeyStroke,
+ NULL
+ },
+ { // SimpleTextOutput
+ TerminalConOutReset,
+ TerminalConOutOutputString,
+ TerminalConOutTestString,
+ TerminalConOutQueryMode,
+ TerminalConOutSetMode,
+ TerminalConOutSetAttribute,
+ TerminalConOutClearScreen,
+ TerminalConOutSetCursorPosition,
+ TerminalConOutEnableCursor,
+ NULL
+ },
+ { // SimpleTextOutputMode
+ 1, // MaxMode
+ 0, // Mode
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
+ 0, // CursorColumn
+ 0, // CursorRow
+ TRUE // CursorVisible
+ },
+ NULL, // TerminalConsoleModeData
+ 0, // SerialInTimeOut
+
+ NULL, // RawFifo
+ NULL, // UnicodeFiFo
+ NULL, // EfiKeyFiFo
+
+ NULL, // ControllerNameTable
+ NULL, // TimerEvent
+ NULL, // TwoSecondTimeOut
+ INPUT_STATE_DEFAULT,
+ RESET_STATE_DEFAULT,
+ FALSE,
+ { // SimpleTextInputEx
+ TerminalConInResetEx,
+ TerminalConInReadKeyStrokeEx,
+ NULL,
+ TerminalConInSetState,
+ TerminalConInRegisterKeyNotify,
+ TerminalConInUnregisterKeyNotify,
+ },
+ { // NotifyList
+ NULL,
+ NULL,
+ }
+};
+
+TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
+ {100, 31},
+ //
+ // New modes can be added here.
+ //
+};
+
+/**
+ Test to see if this driver supports Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ VENDOR_DEVICE_PATH *Node;
+
+ //
+ // If remaining device path is not NULL, then make sure it is a
+ // device path that describes a terminal communications protocol.
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
+
+ if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
+ Node->Header.SubType != MSG_VENDOR_DP ||
+ DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
+
+ return EFI_UNSUPPORTED;
+
+ }
+ //
+ // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
+ //
+ if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
+ !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
+ !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
+ !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
+
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ // The Controller must support the Serial I/O Protocol.
+ // This driver is a bus driver with at most 1 child device, so it is
+ // ok for it to be already started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Build the terminal device path for the child device according to the
+ terminal type.
+
+ @param ParentDevicePath Parent device path.
+ @param RemainingDevicePath A specific child device.
+
+ @return The child device path built.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL*
+EFIAPI
+BuildTerminalDevpath (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
+ UINT8 TerminalType;
+ VENDOR_DEVICE_PATH *Node;
+ EFI_STATUS Status;
+
+ TerminalDevicePath = NULL;
+ TerminalType = PCANSITYPE;
+
+ //
+ // Use the RemainingDevicePath to determine the terminal type
+ //
+ Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
+ if (Node == NULL) {
+ TerminalType = PCANSITYPE;
+
+ } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
+
+ TerminalType = PCANSITYPE;
+
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
+
+ TerminalType = VT100TYPE;
+
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
+
+ TerminalType = VT100PLUSTYPE;
+
+ } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
+
+ TerminalType = VTUTF8TYPE;
+
+ } else {
+ return NULL;
+ }
+
+ //
+ // Build the device path for the child device
+ //
+ Status = SetTerminalDevicePath (
+ TerminalType,
+ ParentDevicePath,
+ &TerminalDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return TerminalDevicePath;
+}
+
+/**
+ Compare a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data structure.
+ @param Single A pointer to a single-instance device path data structure.
+
+ @retval TRUE If the Single is contained within Multi.
+ @retval FALSE The Single is not match within Multi.
+
+**/
+BOOLEAN
+MatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ //
+ // If the single device path is found in multiple device paths,
+ // return success
+ //
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ FreePool (DevicePathInst);
+ return TRUE;
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether the terminal device path is in the global variable.
+
+ @param VariableName Pointer to one global variable.
+ @param TerminalDevicePath Pointer to the terminal device's device path.
+
+ @retval TRUE The devcie is in the global variable.
+ @retval FALSE The devcie is not in the global variable.
+
+**/
+BOOLEAN
+IsTerminalInConsoleVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ BOOLEAN ReturnFlag;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Check whether the terminal device path is one of the variable instances.
+ //
+ ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
+
+ FreePool (Variable);
+
+ return ReturnFlag;
+}
+
+/**
+ Free notify functions list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.
+
+**/
+EFI_STATUS
+TerminalFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize all the text modes which the terminal console supports.
+
+ It returns information for available text modes that the terminal can support.
+
+ @param[out] TextModeCount The total number of text modes that terminal console supports.
+ @param[out] TextModeData The buffer to the text modes column and row information.
+ Caller is responsible to free it when it's non-NULL.
+
+ @retval EFI_SUCCESS The supporting mode information is returned.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+InitializeTerminalConsoleTextMode (
+ OUT UINTN *TextModeCount,
+ OUT TERMINAL_CONSOLE_MODE_DATA **TextModeData
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ TERMINAL_CONSOLE_MODE_DATA *ModeBuffer;
+ TERMINAL_CONSOLE_MODE_DATA *NewModeBuffer;
+ UINTN ValidCount;
+ UINTN ValidIndex;
+
+ if ((TextModeCount == NULL) || (TextModeData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);
+
+ //
+ // Get defined mode buffer pointer.
+ //
+ ModeBuffer = mTerminalConsoleModeData;
+
+ //
+ // Here we make sure that the final mode exposed does not include the duplicated modes,
+ // and does not include the invalid modes which exceed the max column and row.
+ // Reserve 2 modes for 80x25, 80x50 of terminal console.
+ //
+ NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));
+ ASSERT (NewModeBuffer != NULL);
+
+ //
+ // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
+ //
+ ValidCount = 0;
+
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 25;
+ ValidCount++;
+
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 50;
+ ValidCount++;
+
+ //
+ // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
+ //
+ for (Index = 0; Index < Count; Index++) {
+ if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {
+ //
+ // Skip the pre-defined mode which is invalid.
+ //
+ continue;
+ }
+ for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
+ if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
+ (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
+ //
+ // Skip the duplicated mode.
+ //
+ break;
+ }
+ }
+ if (ValidIndex == ValidCount) {
+ NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
+ NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;
+ ValidCount++;
+ }
+ }
+
+ DEBUG_CODE (
+ for (Index = 0; Index < ValidCount; Index++) {
+ DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
+ Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
+ }
+ );
+
+ //
+ // Return valid mode count and mode information buffer.
+ //
+ *TextModeCount = ValidCount;
+ *TextModeData = NewModeBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on Controller by opening a Serial IO protocol,
+ reading Device Path, and creating a child handle with a Simple Text In,
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.
+ And store Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ VENDOR_DEVICE_PATH *Node;
+ VENDOR_DEVICE_PATH *DefaultNode;
+ TERMINAL_DEV *TerminalDevice;
+ UINT8 TerminalType;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
+ BOOLEAN ConInSelected;
+ BOOLEAN ConOutSelected;
+ BOOLEAN NullRemaining;
+ BOOLEAN SimTxtInInstalled;
+ BOOLEAN SimTxtOutInstalled;
+ BOOLEAN FirstEnter;
+ UINTN ModeCount;
+
+ TerminalDevice = NULL;
+ DefaultNode = NULL;
+ ConInSelected = FALSE;
+ ConOutSelected = FALSE;
+ NullRemaining = TRUE;
+ SimTxtInInstalled = FALSE;
+ SimTxtOutInstalled = FALSE;
+ FirstEnter = FALSE;
+ //
+ // Get the Device Path Protocol to build the device path of the child device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ //
+ // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ //
+ // the serial I/O protocol never be opened before, it is the first
+ // time to start the serial Io controller
+ //
+ FirstEnter = TRUE;
+ }
+
+ //
+ // Serial I/O is not already open by this driver, then tag the handle
+ // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
+ // StdErrDev variables with the list of possible terminal types on this
+ // serial port.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiCallerIdGuid,
+ DuplicateDevicePath (ParentDevicePath),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (!IsHotPlugDevice (ParentDevicePath)) {
+ //
+ // if the serial device is a hot plug device, do not update the
+ // ConInDev, ConOutDev, and StdErrDev variables.
+ //
+ TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
+ }
+ }
+
+ //
+ // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
+ //
+ // Simple In/Out Protocol will not be installed onto the handle if the
+ // device path to the handle is not present in the ConIn/ConOut
+ // environment variable. But If RemainingDevicePath is NULL, then always
+ // produce both Simple In and Simple Text Output Protocols. This is required
+ // for the connect all sequences to make sure all possible consoles are
+ // produced no matter what the current values of ConIn, ConOut, or StdErr are.
+ //
+ if (RemainingDevicePath == NULL) {
+ NullRemaining = TRUE;
+ }
+
+ DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
+ if (DevicePath != NULL) {
+ ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
+ ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
+ FreePool (DevicePath);
+ } else {
+ goto Error;
+ }
+ //
+ // Not create the child terminal handle if both Simple In/In Ex and
+ // Simple text Out protocols are not required to be published
+ //
+ if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
+ goto Error;
+ }
+
+ //
+ // create the child terminal handle during first entry
+ //
+ if (FirstEnter) {
+ //
+ // First enther the start funciton
+ //
+ FirstEnter = FALSE;
+ //
+ // Make sure a child handle does not already exist. This driver can only
+ // produce one child per serial port.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = EFI_ALREADY_STARTED;
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ //
+ // If RemainingDevicePath is NULL, then create default device path node
+ //
+ if (RemainingDevicePath == NULL) {
+ DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));
+ if (DefaultNode == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ TerminalType = PcdGet8 (PcdDefaultTerminalType);
+ //
+ // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)
+ //
+ ASSERT (TerminalType <= VTUTF8TYPE);
+
+ CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));
+ RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // Use the RemainingDevicePath to determine the terminal type
+ //
+ Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
+ if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
+ TerminalType = PCANSITYPE;
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
+ TerminalType = VT100TYPE;
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
+ TerminalType = VT100PLUSTYPE;
+ } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
+ TerminalType = VTUTF8TYPE;
+ } else {
+ goto Error;
+ }
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCESSS
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Initialize the Terminal Dev
+ //
+ TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
+ if (TerminalDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ TerminalDevice->TerminalType = TerminalType;
+ TerminalDevice->SerialIo = SerialIo;
+
+ InitializeListHead (&TerminalDevice->NotifyList);
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKeyEx,
+ TerminalDevice,
+ &TerminalDevice->SimpleInputEx.WaitForKeyEx
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKey,
+ TerminalDevice,
+ &TerminalDevice->SimpleInput.WaitForKey
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Allocates and initializes the FIFO buffer to be zero, used for accommodating
+ // the pre-read pending characters.
+ //
+ TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
+ if (TerminalDevice->RawFiFo == NULL) {
+ goto Error;
+ }
+ TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
+ if (TerminalDevice->UnicodeFiFo == NULL) {
+ goto Error;
+ }
+ TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
+ if (TerminalDevice->EfiKeyFiFo == NULL) {
+ goto Error;
+ }
+
+ //
+ // Set Simple Text Output Protocol from template.
+ //
+ SimpleTextOutput = CopyMem (
+ &TerminalDevice->SimpleTextOutput,
+ &mTerminalDevTemplate.SimpleTextOutput,
+ sizeof (mTerminalDevTemplate.SimpleTextOutput)
+ );
+ SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
+
+ Status = InitializeTerminalConsoleTextMode (&ModeCount, &TerminalDevice->TerminalConsoleModeData);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+ TerminalDevice->SimpleTextOutputMode.MaxMode = (INT32) ModeCount;
+
+ //
+ // For terminal devices, cursor is always visible
+ //
+ TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
+ Status = TerminalConOutSetAttribute (
+ SimpleTextOutput,
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ //
+ // Build the component name for the child device
+ //
+ TerminalDevice->ControllerNameTable = NULL;
+ switch (TerminalDevice->TerminalType) {
+ case PCANSITYPE:
+ AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"PC-ANSI Serial Console",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"PC-ANSI Serial Console",
+ FALSE
+ );
+
+ break;
+
+ case VT100TYPE:
+ AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-100 Serial Console",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-100 Serial Console",
+ FALSE
+ );
+
+ break;
+
+ case VT100PLUSTYPE:
+ AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-100+ Serial Console",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-100+ Serial Console",
+ FALSE
+ );
+
+ break;
+
+ case VTUTF8TYPE:
+ AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-UTF8 Serial Console",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &TerminalDevice->ControllerNameTable,
+ (CHAR16 *)L"VT-UTF8 Serial Console",
+ FALSE
+ );
+
+ break;
+ }
+
+ //
+ // Build the device path for the child device
+ //
+ Status = SetTerminalDevicePath (
+ TerminalDevice->TerminalType,
+ ParentDevicePath,
+ &TerminalDevice->DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = TerminalConOutReset (SimpleTextOutput, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = TerminalConOutSetMode (SimpleTextOutput, 0);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TerminalConInTimerHandler,
+ TerminalDevice,
+ &TerminalDevice->TimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer (
+ TerminalDevice->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TerminalDevice->TwoSecondTimeOut
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallProtocolInterface (
+ &TerminalDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ TerminalDevice->DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Register the Parent-Child relationship via
+ // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &TerminalDevice->SerialIo,
+ This->DriverBindingHandle,
+ TerminalDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ //
+ // Find the child handle, and get its TerminalDevice private data
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ ASSERT (OpenInfoBuffer != NULL);
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ //
+ // Find the child terminal handle.
+ // Test whether the SimpleTxtIn and SimpleTxtOut have been published
+ //
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTextInput,
+ This->DriverBindingHandle,
+ OpenInfoBuffer[Index].ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ SimTxtInInstalled = TRUE;
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
+ }
+
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ OpenInfoBuffer[Index].ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ SimTxtOutInstalled = TRUE;
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+ }
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+ } else {
+ goto ReportError;
+ }
+
+ ASSERT (TerminalDevice != NULL);
+ //
+ // Only do the reset if the device path is in the Conout variable
+ //
+ if (ConInSelected && !SimTxtInInstalled) {
+ Status = TerminalDevice->SimpleInput.Reset (
+ &TerminalDevice->SimpleInput,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Need to report Error Code first
+ //
+ goto ReportError;
+ }
+ }
+
+ //
+ // Only output the configure string to remote terminal if the device path
+ // is in the Conout variable
+ //
+ if (ConOutSelected && !SimTxtOutInstalled) {
+ Status = TerminalDevice->SimpleTextOutput.SetAttribute (
+ &TerminalDevice->SimpleTextOutput,
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = TerminalDevice->SimpleTextOutput.Reset (
+ &TerminalDevice->SimpleTextOutput,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = TerminalDevice->SimpleTextOutput.SetMode (
+ &TerminalDevice->SimpleTextOutput,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = TerminalDevice->SimpleTextOutput.EnableCursor (
+ &TerminalDevice->SimpleTextOutput,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+ }
+
+ //
+ // Simple In/Out Protocol will not be installed onto the handle if the
+ // device path to the handle is not present in the ConIn/ConOut
+ // environment variable. But If RemainingDevicePath is NULL, then always
+ // produce both Simple In and Simple Text Output Protocols. This is required
+ // for the connect all sequences to make sure all possible consoles are
+ // produced no matter what the current values of ConIn, ConOut, or StdErr are.
+ //
+ if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &TerminalDevice->Handle,
+ &gEfiSimpleTextInProtocolGuid,
+ &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &TerminalDevice->SimpleInputEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
+ Status = gBS->InstallProtocolInterface (
+ &TerminalDevice->Handle,
+ &gEfiSimpleTextOutProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &TerminalDevice->SimpleTextOutput
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+ if (DefaultNode != NULL) {
+ FreePool (DefaultNode);
+ }
+
+ return EFI_SUCCESS;
+
+ReportError:
+ //
+ // Report error code before exiting
+ //
+ DevicePath = ParentDevicePath;
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
+ DevicePath
+ );
+
+Error:
+ //
+ // Use the Stop() function to free all resources allocated in Start()
+ //
+ if (TerminalDevice != NULL) {
+
+ if (TerminalDevice->Handle != NULL) {
+ This->Stop (This, Controller, 1, &TerminalDevice->Handle);
+ } else {
+
+ if (TerminalDevice->TwoSecondTimeOut != NULL) {
+ gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
+ }
+
+ if (TerminalDevice->TimerEvent != NULL) {
+ gBS->CloseEvent (TerminalDevice->TimerEvent);
+ }
+
+ if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ }
+
+ if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ }
+
+ TerminalFreeNotifyList (&TerminalDevice->NotifyList);
+
+ if (TerminalDevice->RawFiFo != NULL) {
+ FreePool (TerminalDevice->RawFiFo);
+ }
+ if (TerminalDevice->UnicodeFiFo != NULL) {
+ FreePool (TerminalDevice->UnicodeFiFo);
+ }
+ if (TerminalDevice->EfiKeyFiFo != NULL) {
+ FreePool (TerminalDevice->EfiKeyFiFo);
+ }
+
+ if (TerminalDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ }
+
+ if (TerminalDevice->DevicePath != NULL) {
+ FreePool (TerminalDevice->DevicePath);
+ }
+
+ if (TerminalDevice->TerminalConsoleModeData != NULL) {
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ }
+
+ FreePool (TerminalDevice);
+ }
+ }
+
+ if (DefaultNode != NULL) {
+ FreePool (DefaultNode);
+ }
+
+ This->Stop (This, Controller, 0, NULL);
+
+ return Status;
+}
+
+/**
+ Stop this driver on Controller by closing Simple Text In, Simple Text
+ In Ex, Simple Text Out protocol, and removing parent device path from
+ Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ TERMINAL_DEV *TerminalDevice;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Remove Parent Device Path from
+ // the Console Device Environment Variables
+ //
+ TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
+
+ //
+ // Uninstall the Terminal Driver's GUID Tag from the Serial controller
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ ParentDevicePath,
+ NULL
+ );
+
+ //
+ // Free the ParentDevicePath that was duplicated in Start()
+ //
+ if (!EFI_ERROR (Status)) {
+ FreePool (ParentDevicePath);
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextInProtocolGuid,
+ &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &TerminalDevice->SimpleInputEx,
+ &gEfiSimpleTextOutProtocolGuid,
+ &TerminalDevice->SimpleTextOutput,
+ &gEfiDevicePathProtocolGuid,
+ TerminalDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+
+ if (TerminalDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ }
+
+ gBS->CloseEvent (TerminalDevice->TimerEvent);
+ gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ TerminalFreeNotifyList (&TerminalDevice->NotifyList);
+ FreePool (TerminalDevice->DevicePath);
+ if (TerminalDevice->TerminalConsoleModeData != NULL) {
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ }
+ FreePool (TerminalDevice);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update terminal device path in Console Device Environment Variables.
+
+ @param VariableName The Console Device Environment Variable.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalUpdateConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableSize;
+ UINT8 TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Variable == NULL) {
+ return;
+ }
+
+ //
+ // Append terminal device path onto the variable.
+ //
+ for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+ NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
+ if (Variable != NULL) {
+ FreePool (Variable);
+ }
+
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ Variable = NewVariable;
+ }
+
+ VariableSize = GetDevicePathSize (Variable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ Variable
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Variable);
+
+ return ;
+}
+
+
+/**
+ Remove terminal device path from Console Device Environment Variables.
+
+ @param VariableName Console Device Environment Variables.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalRemoveConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN FoundOne;
+ BOOLEAN Match;
+ UINTN VariableSize;
+ UINTN InstanceSize;
+ UINT8 TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ Instance = NULL;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Variable == NULL) {
+ return ;
+ }
+
+ FoundOne = FALSE;
+ OriginalVariable = Variable;
+ NewVariable = NULL;
+
+ //
+ // Get first device path instance from Variable
+ //
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ if (Instance == NULL) {
+ FreePool (OriginalVariable);
+ return ;
+ }
+ //
+ // Loop through all the device path instances of Variable
+ //
+ do {
+ //
+ // Loop through all the terminal types that this driver supports
+ //
+ Match = FALSE;
+ for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
+
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+
+ //
+ // Compare the generated device path to the current device path instance
+ //
+ if (TempDevicePath != NULL) {
+ if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
+ Match = TRUE;
+ FoundOne = TRUE;
+ }
+
+ FreePool (TempDevicePath);
+ }
+ }
+ //
+ // If a match was not found, then keep the current device path instance
+ //
+ if (!Match) {
+ SavedNewVariable = NewVariable;
+ NewVariable = AppendDevicePathInstance (NewVariable, Instance);
+ if (SavedNewVariable != NULL) {
+ FreePool (SavedNewVariable);
+ }
+ }
+ //
+ // Get next device path instance from Variable
+ //
+ FreePool (Instance);
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ } while (Instance != NULL);
+
+ FreePool (OriginalVariable);
+
+ if (FoundOne) {
+ VariableSize = GetDevicePathSize (NewVariable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ NewVariable
+ );
+ //
+ // Shrinking variable with existing variable driver implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (NewVariable != NULL) {
+ FreePool (NewVariable);
+ }
+
+ return ;
+}
+
+/**
+ Build terminal device path according to terminal type.
+
+ @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
+ @param ParentDevicePath Parent device path.
+ @param TerminalDevicePath Returned terminal device path, if building successfully.
+
+ @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
+ @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
+ @retval EFI_SUCCESS Build terminal device path successfully.
+
+**/
+EFI_STATUS
+SetTerminalDevicePath (
+ IN UINT8 TerminalType,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
+ )
+{
+ VENDOR_DEVICE_PATH Node;
+
+ *TerminalDevicePath = NULL;
+ Node.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Header.SubType = MSG_VENDOR_DP;
+
+ //
+ // Generate terminal device path node according to terminal type.
+ //
+ switch (TerminalType) {
+
+ case PCANSITYPE:
+ CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);
+ break;
+
+ case VT100TYPE:
+ CopyGuid (&Node.Guid, &gEfiVT100Guid);
+ break;
+
+ case VT100PLUSTYPE:
+ CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);
+ break;
+
+ case VTUTF8TYPE:
+ CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get VENDOR_DEVCIE_PATH size and put into Node.Header
+ //
+ SetDevicePathNodeLength (
+ &Node.Header,
+ sizeof (VENDOR_DEVICE_PATH)
+ );
+
+ //
+ // Append the terminal node onto parent device path
+ // to generate a complete terminal device path.
+ //
+ *TerminalDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Node
+ );
+ if (*TerminalDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module Terminal. The user code starts with this function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeTerminal(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gTerminalDriverBinding,
+ ImageHandle,
+ &gTerminalComponentName,
+ &gTerminalComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Check if the device supports hot-plug through its device path.
+
+ This function could be updated to check more types of Hot Plug devices.
+ Currently, it checks USB and PCCard device.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a hot-plug device
+ @retval FALSE The devcie is not a hot-plug device.
+
+**/
+BOOLEAN
+IsHotPlugDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
+
+ CheckDevicePath = DevicePath;
+ while (!IsDevicePathEnd (CheckDevicePath)) {
+ //
+ // Check device whether is hot plug device or not throught Device Path
+ //
+ if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
+ //
+ // If Device is USB device
+ //
+ return TRUE;
+ }
+ if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
+ //
+ // If Device is PCCard
+ //
+ return TRUE;
+ }
+
+ CheckDevicePath = NextDevicePathNode (CheckDevicePath);
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
new file mode 100644
index 0000000000..384b7ba45c
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
@@ -0,0 +1,1359 @@
+/** @file
+ Header file for Terminal 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 _TERMINAL_H_
+#define _TERMINAL_H_
+
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/PcAnsi.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+
+
+#define RAW_FIFO_MAX_NUMBER 256
+#define FIFO_MAX_NUMBER 128
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ UINT8 Data[RAW_FIFO_MAX_NUMBER + 1];
+} RAW_DATA_FIFO;
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ UINT16 Data[FIFO_MAX_NUMBER + 1];
+} UNICODE_FIFO;
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ EFI_INPUT_KEY Data[FIFO_MAX_NUMBER + 1];
+} EFI_KEY_FIFO;
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+} TERMINAL_CONSOLE_MODE_DATA;
+
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+
+#define TERMINAL_DEV_SIGNATURE SIGNATURE_32 ('t', 'm', 'n', 'l')
+
+#define TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('t', 'm', 'e', 'n')
+
+typedef struct _TERMINAL_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} TERMINAL_CONSOLE_IN_EX_NOTIFY;
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ UINT8 TerminalType;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleInput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode;
+ TERMINAL_CONSOLE_MODE_DATA *TerminalConsoleModeData;
+ UINTN SerialInTimeOut;
+ RAW_DATA_FIFO *RawFiFo;
+ UNICODE_FIFO *UnicodeFiFo;
+ EFI_KEY_FIFO *EfiKeyFiFo;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT TwoSecondTimeOut;
+ UINT32 InputState;
+ UINT32 ResetState;
+
+ //
+ // Esc could not be output to the screen by user,
+ // but the terminal driver need to output it to
+ // the terminal emulation software to send control sequence.
+ // This boolean is used by the terminal driver only
+ // to indicate whether the Esc could be sent or not.
+ //
+ BOOLEAN OutputEscChar;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleInputEx;
+ LIST_ENTRY NotifyList;
+} TERMINAL_DEV;
+
+#define INPUT_STATE_DEFAULT 0x00
+#define INPUT_STATE_ESC 0x01
+#define INPUT_STATE_CSI 0x02
+#define INPUT_STATE_LEFTOPENBRACKET 0x04
+#define INPUT_STATE_O 0x08
+#define INPUT_STATE_2 0x10
+#define INPUT_STATE_1 0x20
+#define INPUT_STATE_1N 0x40
+#define RESET_STATE_DEFAULT 0x00
+#define RESET_STATE_ESC_R 0x01
+#define RESET_STATE_ESC_R_ESC_R 0x02
+
+#define TERMINAL_CON_IN_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInput, TERMINAL_DEV_SIGNATURE)
+#define TERMINAL_CON_OUT_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleTextOutput, TERMINAL_DEV_SIGNATURE)
+#define TERMINAL_CON_IN_EX_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInputEx, TERMINAL_DEV_SIGNATURE)
+
+typedef union {
+ UINT8 Utf8_1;
+ UINT8 Utf8_2[2];
+ UINT8 Utf8_3[3];
+} UTF8_CHAR;
+
+#define PCANSITYPE 0
+#define VT100TYPE 1
+#define VT100PLUSTYPE 2
+#define VTUTF8TYPE 3
+
+#define LEFTOPENBRACKET 0x5b // '['
+#define ACAP 0x41
+#define BCAP 0x42
+#define CCAP 0x43
+#define DCAP 0x44
+
+#define BACKSPACE 8
+#define ESC 27
+#define CSI 0x9B
+#define DEL 127
+#define BRIGHT_CONTROL_OFFSET 2
+#define FOREGROUND_CONTROL_OFFSET 6
+#define BACKGROUND_CONTROL_OFFSET 11
+#define ROW_OFFSET 2
+#define COLUMN_OFFSET 5
+
+typedef struct {
+ UINT16 Unicode;
+ CHAR8 PcAnsi;
+ CHAR8 Ascii;
+} UNICODE_TO_CHAR;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gTerminalComponentName2;
+
+/**
+ The user Entry Point for module Terminal. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeTerminal (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
+ This driver only perform dependent serial device reset regardless of
+ the value of ExtendeVerification
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Skip by this driver.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
+
+ @param This Indicates the calling context.
+ @param Key A pointer to a buffer that is filled in with the
+ keystroke information for the key that was sent
+ from terminal.
+
+ @retval EFI_SUCCESS The keystroke information is returned successfully.
+ @retval EFI_NOT_READY There is no keystroke data available.
+ @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Check if the key already has been registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ registered.
+ @param InputData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Simple Text Input Ex protocol prototypes
+//
+
+/**
+ Reset the input device and optionally run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due
+ to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and
+ could not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its
+ state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke information data for the key that was
+ pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification.
+
+ @retval EFI_SUCCESS The notification function was registered
+ successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data
+ structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ );
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being
+ unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered
+ successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+ @retval EFI_NOT_FOUND Can not find the matching entry in database.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+ If ExtendeVerification is TRUE, then perform dependent serial device reset,
+ and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+ The Unicode string will be converted to terminal expressible data stream
+ and send to terminal via serial port.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be displayed
+ on the terminal screen.
+
+ @retval EFI_SUCCESS The string is output successfully.
+ @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
+ @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
+ be rendered and are skipped.
+ @retval EFI_UNSUPPORTED If current display mode is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+ If one of the characters in the *Wstring is
+ neither valid Unicode drawing characters,
+ not ASCII code, then this function will return
+ EFI_UNSUPPORTED.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be tested.
+
+ @retval EFI_SUCCESS The terminal is capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It returns information for an available text mode
+ that the terminal supports.
+ In this driver, we support text mode 80x25 (mode 0),
+ 80x50 (mode 1), 100x31 (mode 2).
+
+ @param This Indicates the calling context.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUT.SetMode().
+ Set the terminal to a specified display mode.
+ In this driver, we only support mode 0.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set
+ because of serial device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+
+ @param This Indicates the calling context.
+ @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
+ are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ It clears the ANSI terminal's display to the
+ currently selected background color.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+
+ @param This Indicates the calling context.
+ @param Column The row to set cursor to.
+ @param Row The column to set cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The request fails due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
+ is invalid for current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+/**
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+ In this driver, the cursor cannot be hidden.
+
+ @param This Indicates the calling context.
+ @param Visible If TRUE, the cursor is set to be visible,
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The request is valid.
+ @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Test to see if this driver supports Controller.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on Controller by opening a Serial IO protocol,
+ reading Device Path, and creating a child handle with a Simple Text In,
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.
+ And store Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Stop this driver on Controller by closing Simple Text In, Simple Text
+ In Ex, Simple Text Out protocol, and removing parent device path from
+ Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Free notify functions list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.
+
+**/
+EFI_STATUS
+TerminalFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// internal functions
+//
+
+/**
+ Check for a pending key in the Efi Key FIFO or Serial device buffer.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS There is key pending.
+ @retval EFI_NOT_READY There is no key pending.
+ @retval EFI_DEVICE_ERROR If Serial IO is not attached to serial device.
+
+**/
+EFI_STATUS
+TerminalConInCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ );
+
+/**
+ Update terminal device path in Console Device Environment Variables.
+
+ @param VariableName The Console Device Environment Variable.
+ @param ParentDevicePath The terminal device path to be updated.
+
+ @return None.
+
+**/
+VOID
+TerminalUpdateConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ );
+
+/**
+ Remove console device variable.
+
+ @param VariableName A pointer to the variable name.
+ @param ParentDevicePath A pointer to the parent device path.
+
+**/
+VOID
+TerminalRemoveConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ );
+
+/**
+ Build termial device path according to terminal type.
+
+ @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
+ @param ParentDevicePath Parent device path.
+ @param TerminalDevicePath Returned terminal device path, if building successfully.
+
+ @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
+ @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
+ @retval EFI_SUCCESS Build terminal device path successfully.
+
+**/
+EFI_STATUS
+SetTerminalDevicePath (
+ IN UINT8 TerminalType,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
+ );
+
+/**
+ Get one key out of serial buffer.
+
+ @param SerialIo Serial I/O protocl attached to the serial device.
+ @param Input The fetched key.
+
+ @retval EFI_NOT_READY If serial buffer is empty.
+ @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
+ @retval EFI_SUCCESS If reading serial buffer successfully, put
+ the fetched key to the parameter output.
+
+**/
+EFI_STATUS
+GetOneKeyFromSerial (
+ EFI_SERIAL_IO_PROTOCOL *SerialIo,
+ UINT8 *Input
+ );
+
+/**
+ Insert one byte raw data into the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+RawFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 Input
+ );
+
+/**
+ Remove one pre-fetched key out of the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+RawFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 *Output
+ );
+
+/**
+ Clarify whether Raw Data FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is empty.
+ @retval FALSE If Raw Data FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsRawFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether Raw Data FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is full.
+ @retval FALSE If Raw Data FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsRawFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Key The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Key
+ );
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Output
+ );
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Insert one pre-fetched key into the Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Unicode FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+UnicodeFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 Input
+ );
+
+/**
+ Remove one pre-fetched key out of the Unicode FIFO buffer.
+ The caller should guarantee that Unicode FIFO buffer is not empty
+ by IsUnicodeFiFoEmpty ().
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+**/
+VOID
+UnicodeFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 *Output
+ );
+
+/**
+ Clarify whether Unicode FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is empty.
+ @retval FALSE If Unicode FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsUnicodeFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether Unicode FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is full.
+ @retval FALSE If Unicode FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsUnicodeFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Count Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @return The count in bytes of Unicode FIFO.
+
+**/
+UINT8
+UnicodeFiFoGetKeyCount (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Translate raw data into Unicode (according to different encode), and
+ translate Unicode into key information. (according to different standard).
+
+ @param TerminalDevice Terminal driver private structure.
+
+**/
+VOID
+TranslateRawDataToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+//
+// internal functions for PC ANSI
+//
+
+/**
+ Translate all raw data in the Raw FIFI into unicode, and insert
+ them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+AnsiRawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Converts a stream of Unicode characters from a terminal input device into EFI Keys that
+ can be read through the Simple Input Protocol.
+
+ The table below shows the keyboard input mappings that this function supports.
+ If the ESC sequence listed in one of the columns is presented, then it is translated
+ into the coorespoding EFI Scan Code. If a matching sequence is not found, then the raw
+ key strokes are converted into EFI Keys.
+
+ 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
+ completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
+ converted into EFI Keys.
+ There is one special input sequence that will force the system to reset.
+ This is ESC R ESC r ESC R.
+
+ Symbols used in table below
+ ===========================
+ ESC = 0x1B
+ CSI = 0x9B
+ DEL = 0x7f
+ ^ = CTRL
+ +=========+======+===========+==========+==========+
+ | | EFI | UEFI 2.0 | | |
+ | | Scan | | VT100+ | |
+ | KEY | Code | PC ANSI | VTUTF8 | VT100 |
+ +=========+======+===========+==========+==========+
+ | NULL | 0x00 | | | |
+ | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
+ | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
+ | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
+ | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
+ | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
+ | END | 0x06 | ESC [ F | ESC k | ESC [ K |
+ | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
+ | | | ESC [ L | | ESC [ L |
+ | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
+ | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
+ | | | | | ESC [ ? |
+ | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
+ | | | | | ESC [ / |
+ | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
+ | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
+ | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
+ | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
+ | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
+ | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
+ | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
+ | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
+ | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
+ | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
+ | Escape | 0x17 | ESC | ESC | ESC |
+ | F11 | 0x15 | | ESC ! | |
+ | F12 | 0x16 | | ESC @ | |
+ +=========+======+===========+==========+==========+
+
+ Special Mappings
+ ================
+ ESC R ESC r ESC R = Reset System
+
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Check if input string is valid Ascii string, valid EFI control characters
+ or valid text graphics.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_UNSUPPORTED If not all input characters are valid.
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+AnsiTestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ );
+
+//
+// internal functions for VTUTF8
+//
+
+/**
+ Translate all VT-UTF8 characters in the Raw FIFI into unicode characters,
+ and insert them into Unicode FIFO.
+
+ @param VtUtf8Device The terminal device.
+
+**/
+VOID
+VTUTF8RawDataToUnicode (
+ IN TERMINAL_DEV *VtUtf8Device
+ );
+
+/**
+ Check if input string is valid VT-UTF8 string.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+VTUTF8TestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ );
+
+/**
+ Translate one Unicode character into VT-UTF8 characters.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Unicode Unicode character need translating.
+ @param Utf8Char Return VT-UTF8 character set.
+ @param ValidBytes The count of valid VT-UTF8 characters. If
+ ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+UnicodeToUtf8 (
+ IN CHAR16 Unicode,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ );
+
+/**
+ Get one valid VT-UTF8 characters set from Raw Data FIFO.
+
+ @param Utf8Device The terminal device.
+ @param Utf8Char Returned valid VT-UTF8 characters set.
+ @param ValidBytes The count of returned VT-VTF8 characters.
+ If ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+GetOneValidUtf8Char (
+ IN TERMINAL_DEV *Utf8Device,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ );
+
+/**
+ Translate VT-UTF8 characters into one Unicode character.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Utf8Char VT-UTF8 character set needs translating.
+ @param ValidBytes The count of valid VT-UTF8 characters.
+ @param UnicodeChar Returned unicode character.
+
+**/
+VOID
+Utf8ToUnicode (
+ IN UTF8_CHAR Utf8Char,
+ IN UINT8 ValidBytes,
+ OUT CHAR16 *UnicodeChar
+ );
+
+//
+// functions for boxdraw unicode
+//
+
+/**
+ Detects if a Unicode char is for Box Drawing text graphics.
+
+ @param Graphic Unicode char to test.
+ @param PcAnsi Optional pointer to return PCANSI equivalent of
+ Graphic.
+ @param Ascii Optional pointer to return ASCII equivalent of
+ Graphic.
+
+ @retval TRUE If Graphic is a supported Unicode Box Drawing character.
+
+**/
+BOOLEAN
+TerminalIsValidTextGraphics (
+ IN CHAR16 Graphic,
+ OUT CHAR8 *PcAnsi, OPTIONAL
+ OUT CHAR8 *Ascii OPTIONAL
+ );
+
+/**
+ Detects if a valid ASCII char.
+
+ @param Ascii An ASCII character.
+
+ @retval TRUE If it is a valid ASCII character.
+ @retval FALSE If it is not a valid ASCII character.
+
+**/
+BOOLEAN
+TerminalIsValidAscii (
+ IN CHAR16 Ascii
+ );
+
+/**
+ Detects if a valid EFI control character.
+
+ @param CharC An input EFI Control character.
+
+ @retval TRUE If it is a valid EFI control character.
+ @retval FALSE If it is not a valid EFI control character.
+
+**/
+BOOLEAN
+TerminalIsValidEfiCntlChar (
+ IN CHAR16 CharC
+ );
+
+/**
+ Check if the device supports hot-plug through its device path.
+
+ This function could be updated to check more types of Hot Plug devices.
+ Currently, it checks USB and PCCard device.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a hot-plug device
+ @retval FALSE The devcie is not a hot-plug device.
+
+**/
+BOOLEAN
+IsHotPlugDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Timer handler to poll the key from serial.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+TerminalConInTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+#endif
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
new file mode 100644
index 0000000000..715dae7afd
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -0,0 +1,1562 @@
+/** @file
+ Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
+
+ 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.
+
+**/
+
+#include "Terminal.h"
+
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param TerminalDevice Terminal driver private structure
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+ReadKeyStrokeWorker (
+ IN TERMINAL_DEV *TerminalDevice,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
+ return EFI_NOT_READY;
+ }
+
+ KeyData->KeyState.KeyShiftState = 0;
+ KeyData->KeyState.KeyToggleState = 0;
+
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
+ This driver only perform dependent serial device reset regardless of
+ the value of ExtendeVerification
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Skip by this driver.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
+
+ @param This Indicates the calling context.
+ @param Key A pointer to a buffer that is filled in with the
+ keystroke information for the key that was sent
+ from terminal.
+
+ @retval EFI_SUCCESS The keystroke information is returned successfully.
+ @retval EFI_NOT_READY There is no keystroke data available.
+ @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ //
+ // get TERMINAL_DEV from "This" parameter.
+ //
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
+
+ Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Check if the key already has been registered.
+
+ If both RegsiteredData and InputData is NULL, then ASSERT().
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ registered.
+ @param InputData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ TerminalConInWaitForKey (Event, Context);
+}
+
+//
+// Simple Text Input Ex protocol functions
+//
+
+/**
+ Reset the input device and optionally run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due
+ to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ return ReadKeyStrokeWorker (TerminalDevice, KeyData);
+
+}
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and
+ could not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its
+ state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke information data for the key that was
+ pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification.
+
+ @retval EFI_SUCCESS The notification function was registered
+ successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data
+ structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+ NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being
+ unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered
+ successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ LIST_ENTRY *Link;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ LIST_ENTRY *NotifyList;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ gBS->FreePool (CurrentNotify);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Can not find the matching entry in database.
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Translate raw data into Unicode (according to different encode), and
+ translate Unicode into key information. (according to different standard).
+
+ @param TerminalDevice Terminal driver private structure.
+
+**/
+VOID
+TranslateRawDataToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ switch (TerminalDevice->TerminalType) {
+
+ case PCANSITYPE:
+ case VT100TYPE:
+ case VT100PLUSTYPE:
+ AnsiRawDataToUnicode (TerminalDevice);
+ UnicodeToEfiKey (TerminalDevice);
+ break;
+
+ case VTUTF8TYPE:
+ //
+ // Process all the raw data in the RawFIFO,
+ // put the processed key into UnicodeFIFO.
+ //
+ VTUTF8RawDataToUnicode (TerminalDevice);
+
+ //
+ // Translate all the Unicode data in the UnicodeFIFO to Efi key,
+ // then put into EfiKeyFIFO.
+ //
+ UnicodeToEfiKey (TerminalDevice);
+
+ break;
+ }
+}
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Someone is waiting on the keystroke event, if there's
+ // a key pending, signal the event
+ //
+
+ if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {
+
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Timer handler to poll the key from serial.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+ UINT8 Input = 0;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+
+ TerminalDevice = (TERMINAL_DEV *) Context;
+
+ SerialIo = TerminalDevice->SerialIo;
+ if (SerialIo == NULL) {
+ return ;
+ }
+
+
+ //
+ // Fetch all the keys in the serial buffer,
+ // and insert the byte stream into RawFIFO.
+ //
+ while (!IsRawFiFoFull (TerminalDevice)) {
+
+ Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
+ TerminalDevice->DevicePath
+ );
+ }
+ break;
+ }
+
+ RawFiFoInsertOneKey (TerminalDevice, Input);
+ }
+
+
+ //
+ // Translate all the raw data in RawFIFO into EFI Key,
+ // according to different terminal type supported.
+ //
+ TranslateRawDataToEfiKey (TerminalDevice);
+}
+
+/**
+ Get one key out of serial buffer.
+
+ @param SerialIo Serial I/O protocol attached to the serial device.
+ @param Output The fetched key.
+
+ @retval EFI_NOT_READY If serial buffer is empty.
+ @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
+ @retval EFI_SUCCESS If reading serial buffer successfully, put
+ the fetched key to the parameter output.
+
+**/
+EFI_STATUS
+GetOneKeyFromSerial (
+ EFI_SERIAL_IO_PROTOCOL *SerialIo,
+ UINT8 *Output
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Size = 1;
+ *Output = 0;
+
+ //
+ // Read one key from serial I/O device.
+ //
+ Status = SerialIo->Read (SerialIo, &Size, Output);
+
+ if (EFI_ERROR (Status)) {
+
+ if (Status == EFI_TIMEOUT) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ }
+
+ if (*Output == 0) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert one byte raw data into the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+RawFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 Input
+ )
+{
+ UINT8 Tail;
+
+ Tail = TerminalDevice->RawFiFo->Tail;
+
+ if (IsRawFiFoFull (TerminalDevice)) {
+ //
+ // Raw FIFO is full
+ //
+ return FALSE;
+ }
+
+ TerminalDevice->RawFiFo->Data[Tail] = Input;
+
+ TerminalDevice->RawFiFo->Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+RawFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->RawFiFo->Head;
+
+ if (IsRawFiFoEmpty (TerminalDevice)) {
+ //
+ // FIFO is empty
+ //
+ *Output = 0;
+ return FALSE;
+ }
+
+ *Output = TerminalDevice->RawFiFo->Data[Head];
+
+ TerminalDevice->RawFiFo->Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Clarify whether Raw Data FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is empty.
+ @retval FALSE If Raw Data FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsRawFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether Raw Data FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is full.
+ @retval FALSE If Raw Data FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsRawFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->RawFiFo->Tail;
+ Head = TerminalDevice->RawFiFo->Head;
+
+ if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Key The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Key
+ )
+{
+ UINT8 Tail;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_KEY_DATA KeyData;
+
+ Tail = TerminalDevice->EfiKeyFiFo->Tail;
+
+ CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
+ KeyData.KeyState.KeyShiftState = 0;
+ KeyData.KeyState.KeyToggleState = 0;
+
+ //
+ // Invoke notification functions if exist
+ //
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+ if (IsEfiKeyFiFoFull (TerminalDevice)) {
+ //
+ // Efi Key FIFO is full
+ //
+ return FALSE;
+ }
+
+ CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
+
+ TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->EfiKeyFiFo->Head;
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);
+
+ if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
+ //
+ // FIFO is empty
+ //
+ Output->ScanCode = SCAN_NULL;
+ Output->UnicodeChar = 0;
+ return FALSE;
+ }
+
+ *Output = TerminalDevice->EfiKeyFiFo->Data[Head];
+
+ TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->EfiKeyFiFo->Tail;
+ Head = TerminalDevice->EfiKeyFiFo->Head;
+
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Insert one pre-fetched key into the Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Unicode FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+UnicodeFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 Input
+ )
+{
+ UINT8 Tail;
+
+ Tail = TerminalDevice->UnicodeFiFo->Tail;
+ ASSERT (Tail < FIFO_MAX_NUMBER + 1);
+
+
+ if (IsUnicodeFiFoFull (TerminalDevice)) {
+ //
+ // Unicode FIFO is full
+ //
+ return FALSE;
+ }
+
+ TerminalDevice->UnicodeFiFo->Data[Tail] = Input;
+
+ TerminalDevice->UnicodeFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the Unicode FIFO buffer.
+ The caller should guarantee that Unicode FIFO buffer is not empty
+ by IsUnicodeFiFoEmpty ().
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+**/
+VOID
+UnicodeFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->UnicodeFiFo->Head;
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);
+
+ *Output = TerminalDevice->UnicodeFiFo->Data[Head];
+
+ TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
+}
+
+/**
+ Clarify whether Unicode FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is empty.
+ @retval FALSE If Unicode FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsUnicodeFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether Unicode FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is full.
+ @retval FALSE If Unicode FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsUnicodeFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->UnicodeFiFo->Tail;
+ Head = TerminalDevice->UnicodeFiFo->Head;
+
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Count Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @return The count in bytes of Unicode FIFO.
+
+**/
+UINT8
+UnicodeFiFoGetKeyCount (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->UnicodeFiFo->Tail;
+ Head = TerminalDevice->UnicodeFiFo->Head;
+
+ if (Tail >= Head) {
+ return (UINT8) (Tail - Head);
+ } else {
+ return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
+ }
+}
+
+/**
+ Update the Unicode characters from a terminal input device into EFI Keys FIFO.
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKeyFlushState (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_INPUT_KEY Key;
+ UINT32 InputState;
+
+ InputState = TerminalDevice->InputState;
+
+ if (IsEfiKeyFiFoFull (TerminalDevice)) {
+ return;
+ }
+
+ if ((InputState & INPUT_STATE_ESC) != 0) {
+ Key.ScanCode = SCAN_ESC;
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_CSI) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = CSI;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = LEFTOPENBRACKET;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_O) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = 'O';
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_2) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = '2';
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ //
+ // Cancel the timer.
+ //
+ gBS->SetTimer (
+ TerminalDevice->TwoSecondTimeOut,
+ TimerCancel,
+ 0
+ );
+
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+}
+
+
+/**
+ Converts a stream of Unicode characters from a terminal input device into EFI Keys that
+ can be read through the Simple Input Protocol.
+
+ The table below shows the keyboard input mappings that this function supports.
+ If the ESC sequence listed in one of the columns is presented, then it is translated
+ into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
+ key strokes are converted into EFI Keys.
+
+ 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
+ completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
+ converted into EFI Keys.
+ There is one special input sequence that will force the system to reset.
+ This is ESC R ESC r ESC R.
+
+ Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
+ The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
+ DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
+
+ Symbols used in table below
+ ===========================
+ ESC = 0x1B
+ CSI = 0x9B
+ DEL = 0x7f
+ ^ = CTRL
+ +=========+======+===========+==========+==========+
+ | | EFI | UEFI 2.0 | | |
+ | | Scan | | VT100+ | |
+ | KEY | Code | PC ANSI | VTUTF8 | VT100 |
+ +=========+======+===========+==========+==========+
+ | NULL | 0x00 | | | |
+ | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
+ | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
+ | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
+ | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
+ | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
+ | END | 0x06 | ESC [ F | ESC k | ESC [ K |
+ | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
+ | | | ESC [ L | | ESC [ L |
+ | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
+ | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
+ | | | | | ESC [ ? |
+ | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
+ | | | | | ESC [ / |
+ | F1 | 0x0B | ESC[11~ | ESC 1 | ESC O P |
+ | F2 | 0x0C | ESC[12~ | ESC 2 | ESC O Q |
+ | F3 | 0x0D | ESC[13~ | ESC 3 | ESC O w |
+ | F4 | 0x0E | ESC[14~ | ESC 4 | ESC O x |
+ | F5 | 0x0F | ESC[15~ | ESC 5 | ESC O t |
+ | F6 | 0x10 | ESC[16~ | ESC 6 | ESC O u |
+ | F7 | 0x11 | ESC[17~ | ESC 7 | ESC O q |
+ | F8 | 0x12 | ESC[18~ | ESC 8 | ESC O r |
+ | F9 | 0x13 | ESC[19~ | ESC 9 | ESC O p |
+ | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
+ | Escape | 0x17 | ESC | ESC | ESC |
+ | F11 | 0x15 | | ESC ! | |
+ | F12 | 0x16 | | ESC @ | |
+ +=========+======+===========+==========+==========+
+ Special Mappings
+ ================
+ ESC R ESC r ESC R = Reset System
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS TimerStatus;
+ UINT16 UnicodeChar;
+ EFI_INPUT_KEY Key;
+ BOOLEAN SetDefaultResetState;
+ UINT16 CandidtateScanCode = SCAN_NULL; //OVERRIDE
+
+ TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
+
+ if (!EFI_ERROR (TimerStatus)) {
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
+
+ if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
+ //
+ // Check to see if the 2 seconds timer has expired
+ //
+ TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
+ if (!EFI_ERROR (TimerStatus)) {
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+ }
+
+ //
+ // Fetch one Unicode character from the Unicode FIFO
+ //
+ UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
+
+ SetDefaultResetState = TRUE;
+
+ switch (TerminalDevice->InputState) {
+ case INPUT_STATE_DEFAULT:
+
+ break;
+
+ case INPUT_STATE_ESC:
+
+ if (UnicodeChar == LEFTOPENBRACKET) {
+ TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ continue;
+ }
+
+ if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
+ TerminalDevice->InputState |= INPUT_STATE_O;
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ continue;
+ }
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
+ TerminalDevice->TerminalType == VTUTF8TYPE) {
+ switch (UnicodeChar) {
+ case '1':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case '2':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case '3':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case '4':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case '5':
+ Key.ScanCode = SCAN_F5;
+ break;
+ case '6':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case '7':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case '8':
+ Key.ScanCode = SCAN_F8;
+ break;
+ case '9':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case '0':
+ Key.ScanCode = SCAN_F10;
+ break;
+ case '!':
+ Key.ScanCode = SCAN_F11;
+ break;
+ case '@':
+ Key.ScanCode = SCAN_F12;
+ break;
+ case 'h':
+ Key.ScanCode = SCAN_HOME;
+ break;
+ case 'k':
+ Key.ScanCode = SCAN_END;
+ break;
+ case '+':
+ Key.ScanCode = SCAN_INSERT;
+ break;
+ case '-':
+ Key.ScanCode = SCAN_DELETE;
+ break;
+ case '/':
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ break;
+ case '?':
+ Key.ScanCode = SCAN_PAGE_UP;
+ break;
+ default :
+ break;
+ }
+ }
+
+ switch (UnicodeChar) {
+ case 'R':
+ if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
+ TerminalDevice->ResetState = RESET_STATE_ESC_R;
+ SetDefaultResetState = FALSE;
+ } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ Key.ScanCode = SCAN_NULL;
+ break;
+ case 'r':
+ if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
+ TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
+ SetDefaultResetState = FALSE;
+ }
+ Key.ScanCode = SCAN_NULL;
+ break;
+ default :
+ break;
+ }
+
+ if (SetDefaultResetState) {
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_O:
+
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == VT100TYPE) {
+ switch (UnicodeChar) {
+ case 'P':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'Q':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'w':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'x':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case 't':
+ Key.ScanCode = SCAN_F5;
+ break;
+ case 'u':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case 'q':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case 'r':
+ Key.ScanCode = SCAN_F8;
+ break;
+ case 'p':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case 'M':
+ Key.ScanCode = SCAN_F10;
+ break;
+ default :
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
+
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ if (UnicodeChar == '1') {
+ TerminalDevice->InputState |= INPUT_STATE_1;
+ continue;
+ }
+
+ if (UnicodeChar == '2') {
+ TerminalDevice->InputState |= INPUT_STATE_2;
+ continue;
+ }
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == PCANSITYPE ||
+ TerminalDevice->TerminalType == VT100TYPE ||
+ TerminalDevice->TerminalType == VT100PLUSTYPE ||
+ TerminalDevice->TerminalType == VTUTF8TYPE) {
+ switch (UnicodeChar) {
+ case 'A':
+ Key.ScanCode = SCAN_UP;
+ break;
+ case 'B':
+ Key.ScanCode = SCAN_DOWN;
+ break;
+ case 'C':
+ Key.ScanCode = SCAN_RIGHT;
+ break;
+ case 'D':
+ Key.ScanCode = SCAN_LEFT;
+ break;
+ case 'H':
+ if (TerminalDevice->TerminalType == PCANSITYPE ||
+ TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_HOME;
+ }
+ break;
+ case 'F':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_END;
+ }
+ break;
+ case 'K':
+ if (TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_END;
+ }
+ break;
+ case 'L':
+ case '@':
+ if (TerminalDevice->TerminalType == PCANSITYPE ||
+ TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_INSERT;
+ }
+ break;
+ case 'X':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_DELETE;
+ }
+ break;
+ case 'P':
+ if (TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_DELETE;
+ } else if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F4;
+ }
+ break;
+ case 'I':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_PAGE_UP;
+ }
+ break;
+ case 'V':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F10;
+ }
+ break;
+ case '?':
+ if (TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_PAGE_UP;
+ }
+ break;
+ case 'G':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ }
+ break;
+ case 'U':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F9;
+ }
+ break;
+ case '/':
+ if (TerminalDevice->TerminalType == VT100TYPE) {
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ }
+ break;
+ case 'M':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F1;
+ }
+ break;
+ case 'N':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F2;
+ }
+ break;
+ case 'O':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F3;
+ }
+ break;
+ case 'Q':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F5;
+ }
+ break;
+ case 'R':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F6;
+ }
+ break;
+ case 'S':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F7;
+ }
+ break;
+ case 'T':
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ Key.ScanCode = SCAN_F8;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_1:
+
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ switch (UnicodeChar) {
+ case '1':
+ CandidtateScanCode = SCAN_F1;
+ break;
+ case '2':
+ CandidtateScanCode = SCAN_F2;
+ break;
+ case '3':
+ CandidtateScanCode = SCAN_F3;
+ break;
+ case '4':
+ CandidtateScanCode = SCAN_F4;
+ break;
+ case '5':
+ CandidtateScanCode = SCAN_F5;
+ break;
+ case '6':
+ CandidtateScanCode = SCAN_F6;
+ break;
+ case '7':
+ CandidtateScanCode = SCAN_F7;
+ break;
+ case '8':
+ CandidtateScanCode = SCAN_F8;
+ break;
+ case '9':
+ CandidtateScanCode = SCAN_F9;
+ break;
+ }
+ if ( CandidtateScanCode != SCAN_NULL) {
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ TerminalDevice->InputState |= INPUT_STATE_1N;
+ continue;
+ }
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_1 | INPUT_STATE_1N:
+ if (TerminalDevice->TerminalType == PCANSITYPE) {
+ if (UnicodeChar == '~') {
+ Key.ScanCode = CandidtateScanCode;
+ CandidtateScanCode = SCAN_NULL;
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ break;
+ default:
+ //
+ // Invalid state. This should never happen.
+ //
+ ASSERT (FALSE);
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+ }
+
+ if (UnicodeChar == ESC) {
+ TerminalDevice->InputState = INPUT_STATE_ESC;
+ }
+
+ if (UnicodeChar == CSI) {
+ TerminalDevice->InputState = INPUT_STATE_CSI;
+ }
+
+ if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
+ Status = gBS->SetTimer(
+ TerminalDevice->TwoSecondTimeOut,
+ TimerRelative,
+ (UINT64)20000000
+ );
+ ASSERT_EFI_ERROR (Status);
+ continue;
+ }
+
+ if (SetDefaultResetState) {
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ if (UnicodeChar == DEL) {
+ Key.ScanCode = SCAN_DELETE;
+ Key.UnicodeChar = 0;
+ } else {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = UnicodeChar;
+ }
+
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
new file mode 100644
index 0000000000..221b9883e7
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
@@ -0,0 +1,871 @@
+/** @file
+ Implementation for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol.
+
+ 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.
+
+**/
+
+#include "Terminal.h"
+
+//
+// This list is used to define the valid extend chars.
+// It also provides a mapping from Unicode to PCANSI or
+// ASCII. The ASCII mapping we just made up.
+//
+//
+UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = {
+ { BOXDRAW_HORIZONTAL, 0xc4, L'-' },
+ { BOXDRAW_VERTICAL, 0xb3, L'|' },
+ { BOXDRAW_DOWN_RIGHT, 0xda, L'/' },
+ { BOXDRAW_DOWN_LEFT, 0xbf, L'\\' },
+ { BOXDRAW_UP_RIGHT, 0xc0, L'\\' },
+ { BOXDRAW_UP_LEFT, 0xd9, L'/' },
+ { BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' },
+ { BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' },
+ { BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' },
+ { BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' },
+ { BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' },
+ { BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' },
+ { BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' },
+ { BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' },
+ { BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' },
+ { BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' },
+ { BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' },
+ { BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' },
+ { BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' },
+ { BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' },
+ { BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' },
+ { BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' },
+ { BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' },
+ { BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' },
+ { BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' },
+ { BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' },
+ { BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' },
+ { BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' },
+ { BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' },
+ { BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' },
+ { BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' },
+ { BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' },
+ { BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' },
+ { BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' },
+ { BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' },
+ { BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' },
+ { BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' },
+ { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' },
+ { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' },
+ { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' },
+
+ { BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' },
+ { BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' },
+
+ { GEOMETRICSHAPE_UP_TRIANGLE, 0x1e, L'^' },
+ { GEOMETRICSHAPE_RIGHT_TRIANGLE, 0x10, L'>' },
+ { GEOMETRICSHAPE_DOWN_TRIANGLE, 0x1f, L'v' },
+ { GEOMETRICSHAPE_LEFT_TRIANGLE, 0x11, L'<' },
+
+ { ARROW_LEFT, 0x3c, L'<' },
+ { ARROW_UP, 0x18, L'^' },
+ { ARROW_RIGHT, 0x3e, L'>' },
+ { ARROW_DOWN, 0x19, L'v' },
+
+ { 0x0000, 0x00, L'\0' }
+};
+
+CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 };
+CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 };
+CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 };
+CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 };
+
+//
+// Body of the ConOut functions
+//
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+
+ If ExtendeVerification is TRUE, then perform dependent serial device reset,
+ and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+
+ The Unicode string will be converted to terminal expressible data stream
+ and send to terminal via serial port.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be displayed
+ on the terminal screen.
+
+ @retval EFI_SUCCESS The string is output successfully.
+ @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
+ @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
+ be rendered and are skipped.
+ @retval EFI_UNSUPPORTED If current display mode is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ UINTN Length;
+ UTF8_CHAR Utf8Char;
+ CHAR8 GraphicChar;
+ CHAR8 AsciiChar;
+ EFI_STATUS Status;
+ UINT8 ValidBytes;
+ //
+ // flag used to indicate whether condition happens which will cause
+ // return EFI_WARN_UNKNOWN_GLYPH
+ //
+ BOOLEAN Warning;
+
+ ValidBytes = 0;
+ Warning = FALSE;
+ AsciiChar = 0;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // Get current display mode
+ //
+ Mode = This->Mode;
+
+ if (Mode->Mode >= Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ This->QueryMode (
+ This,
+ Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+
+ for (; *WString != CHAR_NULL; WString++) {
+
+ switch (TerminalDevice->TerminalType) {
+
+ case PCANSITYPE:
+ case VT100TYPE:
+ case VT100PLUSTYPE:
+
+ if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) {
+ //
+ // If it's not a graphic character convert Unicode to ASCII.
+ //
+ GraphicChar = (CHAR8) *WString;
+
+ if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) {
+ //
+ // when this driver use the OutputString to output control string,
+ // TerminalDevice->OutputEscChar is set to let the Esc char
+ // to be output to the terminal emulation software.
+ //
+ if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) {
+ GraphicChar = 27;
+ } else {
+ GraphicChar = '?';
+ Warning = TRUE;
+ }
+ }
+
+ AsciiChar = GraphicChar;
+
+ }
+
+ if (TerminalDevice->TerminalType != PCANSITYPE) {
+ GraphicChar = AsciiChar;
+ }
+
+ Length = 1;
+
+ Status = TerminalDevice->SerialIo->Write (
+ TerminalDevice->SerialIo,
+ &Length,
+ &GraphicChar
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto OutputError;
+ }
+
+ break;
+
+ case VTUTF8TYPE:
+ UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
+ Length = ValidBytes;
+ Status = TerminalDevice->SerialIo->Write (
+ TerminalDevice->SerialIo,
+ &Length,
+ (UINT8 *) &Utf8Char
+ );
+ if (EFI_ERROR (Status)) {
+ goto OutputError;
+ }
+ break;
+ }
+ //
+ // Update cursor position.
+ //
+ switch (*WString) {
+
+ case CHAR_BACKSPACE:
+ if (Mode->CursorColumn > 0) {
+ Mode->CursorColumn--;
+ }
+ break;
+
+ case CHAR_LINEFEED:
+ if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
+ Mode->CursorRow++;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ Mode->CursorColumn = 0;
+ break;
+
+ default:
+ if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) {
+
+ Mode->CursorColumn++;
+
+ } else {
+
+ Mode->CursorColumn = 0;
+ if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
+ Mode->CursorRow++;
+ }
+
+ }
+ break;
+
+ };
+
+ }
+
+ if (Warning) {
+ return EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ return EFI_SUCCESS;
+
+OutputError:
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_OUTPUT_ERROR),
+ TerminalDevice->DevicePath
+ );
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+
+ If one of the characters in the *Wstring is
+ neither valid Unicode drawing characters,
+ not ASCII code, then this function will return
+ EFI_UNSUPPORTED.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be tested.
+
+ @retval EFI_SUCCESS The terminal is capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_STATUS Status;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ switch (TerminalDevice->TerminalType) {
+
+ case PCANSITYPE:
+ case VT100TYPE:
+ case VT100PLUSTYPE:
+ Status = AnsiTestString (TerminalDevice, WString);
+ break;
+
+ case VTUTF8TYPE:
+ Status = VTUTF8TestString (TerminalDevice, WString);
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+
+ It returns information for an available text mode
+ that the terminal supports.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+ *Columns = TerminalDevice->TerminalConsoleModeData[ModeNumber].Columns;
+ *Rows = TerminalDevice->TerminalConsoleModeData[ModeNumber].Rows;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUT.SetMode().
+
+ Set the terminal to a specified display mode.
+ In this driver, we only support mode 0.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set
+ because of serial device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set the current mode
+ //
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ This->ClearScreen (This);
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mSetModeString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ Status = This->ClearScreen (This);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+
+ @param This Indicates the calling context.
+ @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
+ are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ UINT8 ForegroundControl;
+ UINT8 BackgroundControl;
+ UINT8 BrightControl;
+ INT32 SavedColumn;
+ INT32 SavedRow;
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ SavedColumn = 0;
+ SavedRow = 0;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // only the bit0..6 of the Attribute is valid
+ //
+ if ((Attribute | 0x7f) != 0x7f) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Skip outputting the command string for the same attribute
+ // It improves the terminal performance significantly
+ //
+ if (This->Mode->Attribute == (INT32) Attribute) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // convert Attribute value to terminal emulator
+ // understandable foreground color
+ //
+ switch (Attribute & 0x07) {
+
+ case EFI_BLACK:
+ ForegroundControl = 30;
+ break;
+
+ case EFI_BLUE:
+ ForegroundControl = 34;
+ break;
+
+ case EFI_GREEN:
+ ForegroundControl = 32;
+ break;
+
+ case EFI_CYAN:
+ ForegroundControl = 36;
+ break;
+
+ case EFI_RED:
+ ForegroundControl = 31;
+ break;
+
+ case EFI_MAGENTA:
+ ForegroundControl = 35;
+ break;
+
+ case EFI_BROWN:
+ ForegroundControl = 33;
+ break;
+
+ default:
+
+ case EFI_LIGHTGRAY:
+ ForegroundControl = 37;
+ break;
+
+ }
+ //
+ // bit4 of the Attribute indicates bright control
+ // of terminal emulator.
+ //
+ BrightControl = (UINT8) ((Attribute >> 3) & 1);
+
+ //
+ // convert Attribute value to terminal emulator
+ // understandable background color.
+ //
+ switch ((Attribute >> 4) & 0x07) {
+
+ case EFI_BLACK:
+ BackgroundControl = 40;
+ break;
+
+ case EFI_BLUE:
+ BackgroundControl = 44;
+ break;
+
+ case EFI_GREEN:
+ BackgroundControl = 42;
+ break;
+
+ case EFI_CYAN:
+ BackgroundControl = 46;
+ break;
+
+ case EFI_RED:
+ BackgroundControl = 41;
+ break;
+
+ case EFI_MAGENTA:
+ BackgroundControl = 45;
+ break;
+
+ case EFI_BROWN:
+ BackgroundControl = 43;
+ break;
+
+ default:
+
+ case EFI_LIGHTGRAY:
+ BackgroundControl = 47;
+ break;
+ }
+ //
+ // terminal emulator's control sequence to set attributes
+ //
+ mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16) ('0' + BrightControl);
+ mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (ForegroundControl / 10));
+ mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (ForegroundControl % 10));
+ mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (BackgroundControl / 10));
+ mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (BackgroundControl % 10));
+
+ //
+ // save current column and row
+ // for future scrolling back use.
+ //
+ SavedColumn = This->Mode->CursorColumn;
+ SavedRow = This->Mode->CursorRow;
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mSetAttributeString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // scroll back to saved cursor position.
+ //
+ This->Mode->CursorColumn = SavedColumn;
+ This->Mode->CursorRow = SavedRow;
+
+ This->Mode->Attribute = (INT32) Attribute;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ It clears the ANSI terminal's display to the
+ currently selected background color.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // control sequence for clear screen request
+ //
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mClearScreenString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = This->SetCursorPosition (This, 0, 0);
+
+ return Status;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+
+ @param This Indicates the calling context.
+ @param Column The row to set cursor to.
+ @param Row The column to set cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The request fails due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
+ is invalid for current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // get current mode
+ //
+ Mode = This->Mode;
+
+ //
+ // get geometry of current mode
+ //
+ Status = This->QueryMode (
+ This,
+ Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Column >= MaxColumn || Row >= MaxRow) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // control sequence to move the cursor
+ //
+ mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16) ('0' + ((Row + 1) / 10));
+ mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16) ('0' + ((Row + 1) % 10));
+ mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16) ('0' + ((Column + 1) / 10));
+ mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16) ('0' + ((Column + 1) % 10));
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mSetCursorPositionString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // update current cursor position
+ // in the Mode data structure.
+ //
+ Mode->CursorColumn = (INT32) Column;
+ Mode->CursorRow = (INT32) Row;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ In this driver, the cursor cannot be hidden.
+
+ @param This Indicates the calling context.
+ @param Visible If TRUE, the cursor is set to be visible,
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The request is valid.
+ @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ if (!Visible) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Detects if a Unicode char is for Box Drawing text graphics.
+
+ @param Graphic Unicode char to test.
+ @param PcAnsi Optional pointer to return PCANSI equivalent of
+ Graphic.
+ @param Ascii Optional pointer to return ASCII equivalent of
+ Graphic.
+
+ @retval TRUE If Graphic is a supported Unicode Box Drawing character.
+
+**/
+BOOLEAN
+TerminalIsValidTextGraphics (
+ IN CHAR16 Graphic,
+ OUT CHAR8 *PcAnsi, OPTIONAL
+ OUT CHAR8 *Ascii OPTIONAL
+ )
+{
+ UNICODE_TO_CHAR *Table;
+
+ if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
+ //
+ // Unicode drawing code charts are all in the 0x25xx range,
+ // arrows are 0x21xx
+ //
+ return FALSE;
+ }
+
+ for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) {
+ if (Graphic == Table->Unicode) {
+ if (PcAnsi != NULL) {
+ *PcAnsi = Table->PcAnsi;
+ }
+
+ if (Ascii != NULL) {
+ *Ascii = Table->Ascii;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Detects if a valid ASCII char.
+
+ @param Ascii An ASCII character.
+
+ @retval TRUE If it is a valid ASCII character.
+ @retval FALSE If it is not a valid ASCII character.
+
+**/
+BOOLEAN
+TerminalIsValidAscii (
+ IN CHAR16 Ascii
+ )
+{
+ //
+ // valid ascii code lies in the extent of 0x20 ~ 0x7f
+ //
+ if ((Ascii >= 0x20) && (Ascii <= 0x7f)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Detects if a valid EFI control character.
+
+ @param CharC An input EFI Control character.
+
+ @retval TRUE If it is a valid EFI control character.
+ @retval FALSE If it is not a valid EFI control character.
+
+**/
+BOOLEAN
+TerminalIsValidEfiCntlChar (
+ IN CHAR16 CharC
+ )
+{
+ //
+ // only support four control characters.
+ //
+ if (CharC == CHAR_NULL ||
+ CharC == CHAR_BACKSPACE ||
+ CharC == CHAR_LINEFEED ||
+ CharC == CHAR_CARRIAGE_RETURN ||
+ CharC == CHAR_TAB
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
new file mode 100644
index 0000000000..d6cd3def65
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
@@ -0,0 +1,101 @@
+## @file
+# Terminal module installs Simple Text Input(ex)/Out protocols for serial devices.
+#
+# This module will install Simple Text Input (Ex) protocol and Simple Test Output
+# protocols based on Serial I/O protocol for serial devices including hotplug serial
+# devices.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TerminalDxe
+ MODULE_UNI_FILE = TerminalDxe.uni
+ FILE_GUID = 9E863906-A40F-4875-977F-5B93FF237FC6
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeTerminal
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gTerminalDriverBinding
+# COMPONENT_NAME = gTerminalComponentName
+# COMPONENT_NAME2 = gTerminalComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Vtutf8.c
+ Ansi.c
+ TerminalConOut.c
+ TerminalConIn.c
+ Terminal.c
+ Terminal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ ReportStatusCodeLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ BaseLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"ConInDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConInDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOutDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOutDev"
+ gEfiGlobalVariableGuid
+ gEfiVTUTF8Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiVT100Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiVT100PlusGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiPcAnsiGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiSerialIoProtocolGuid ## TO_START
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ gEfiSimpleTextOutProtocolGuid ## BY_START
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## CONSUMES
+
+# [Event]
+# # Relative timer event set by UnicodeToEfiKey(), used to be one 2 seconds input timeout.
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+# # Period timer event to invoke TerminalConInTimerHandler(), period value is KEYBOARD_TIMER_INTERVAL and used to poll the key from serial
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TerminalDxeExtra.uni
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c
new file mode 100644
index 0000000000..2f6bb54c8a
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c
@@ -0,0 +1,330 @@
+/** @file
+ Implementation of translation upon VT-UTF8.
+
+ 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.
+
+**/
+
+#include "Terminal.h"
+
+/**
+ Translate all VT-UTF8 characters in the Raw FIFI into unicode characters,
+ and insert them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+VTUTF8RawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ UTF8_CHAR Utf8Char;
+ UINT8 ValidBytes;
+ UINT16 UnicodeChar;
+
+ ValidBytes = 0;
+ //
+ // pop the raw data out from the raw fifo,
+ // and translate it into unicode, then push
+ // the unicode into unicode fifo, until the raw fifo is empty.
+ //
+ while (!IsRawFiFoEmpty (TerminalDevice) && !IsUnicodeFiFoFull (TerminalDevice)) {
+
+ GetOneValidUtf8Char (TerminalDevice, &Utf8Char, &ValidBytes);
+
+ if (ValidBytes < 1 || ValidBytes > 3) {
+ continue;
+ }
+
+ Utf8ToUnicode (Utf8Char, ValidBytes, (CHAR16 *) &UnicodeChar);
+
+ UnicodeFiFoInsertOneKey (TerminalDevice, UnicodeChar);
+ }
+}
+
+/**
+ Get one valid VT-UTF8 characters set from Raw Data FIFO.
+
+ @param Utf8Device The terminal device.
+ @param Utf8Char Returned valid VT-UTF8 characters set.
+ @param ValidBytes The count of returned VT-VTF8 characters.
+ If ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+GetOneValidUtf8Char (
+ IN TERMINAL_DEV *Utf8Device,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ )
+{
+ UINT8 Temp;
+ UINT8 Index;
+ BOOLEAN FetchFlag;
+
+ Temp = 0;
+ Index = 0;
+ FetchFlag = TRUE;
+
+ //
+ // if no valid Utf8 char is found in the RawFiFo,
+ // then *ValidBytes will be zero.
+ //
+ *ValidBytes = 0;
+
+ while (!IsRawFiFoEmpty (Utf8Device)) {
+
+ RawFiFoRemoveOneKey (Utf8Device, &Temp);
+
+ switch (*ValidBytes) {
+
+ case 0:
+ if ((Temp & 0x80) == 0) {
+ //
+ // one-byte utf8 char
+ //
+ *ValidBytes = 1;
+
+ Utf8Char->Utf8_1 = Temp;
+
+ FetchFlag = FALSE;
+
+ } else if ((Temp & 0xe0) == 0xc0) {
+ //
+ // two-byte utf8 char
+ //
+ *ValidBytes = 2;
+
+ Utf8Char->Utf8_2[1] = Temp;
+
+ } else if ((Temp & 0xf0) == 0xe0) {
+ //
+ // three-byte utf8 char
+ //
+ *ValidBytes = 3;
+
+ Utf8Char->Utf8_3[2] = Temp;
+
+ Index++;
+
+ } else {
+ //
+ // reset *ValidBytes to zero, let valid utf8 char search restart
+ //
+ *ValidBytes = 0;
+ }
+
+ break;
+
+ case 2:
+ //
+ // two-byte utf8 char go on
+ //
+ if ((Temp & 0xc0) == 0x80) {
+
+ Utf8Char->Utf8_2[0] = Temp;
+
+ FetchFlag = FALSE;
+
+ } else {
+
+ *ValidBytes = 0;
+ }
+ break;
+
+ case 3:
+ //
+ // three-byte utf8 char go on
+ //
+ if ((Temp & 0xc0) == 0x80) {
+ if (Index == 1) {
+ Utf8Char->Utf8_3[1] = Temp;
+ Index++;
+ } else {
+ Utf8Char->Utf8_3[0] = Temp;
+ FetchFlag = FALSE;
+ }
+ } else {
+ //
+ // reset *ValidBytes and Index to zero, let valid utf8 char search restart
+ //
+ *ValidBytes = 0;
+ Index = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!FetchFlag) {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Translate VT-UTF8 characters into one Unicode character.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Utf8Char VT-UTF8 character set needs translating.
+ @param ValidBytes The count of valid VT-UTF8 characters.
+ @param UnicodeChar Returned unicode character.
+
+**/
+VOID
+Utf8ToUnicode (
+ IN UTF8_CHAR Utf8Char,
+ IN UINT8 ValidBytes,
+ OUT CHAR16 *UnicodeChar
+ )
+{
+ UINT8 UnicodeByte0;
+ UINT8 UnicodeByte1;
+ UINT8 Byte0;
+ UINT8 Byte1;
+ UINT8 Byte2;
+
+ *UnicodeChar = 0;
+
+ //
+ // translate utf8 code to unicode, in terminal standard,
+ // up to 3 bytes utf8 code is supported.
+ //
+ switch (ValidBytes) {
+ case 1:
+ //
+ // one-byte utf8 code
+ //
+ *UnicodeChar = (UINT16) Utf8Char.Utf8_1;
+ break;
+
+ case 2:
+ //
+ // two-byte utf8 code
+ //
+ Byte0 = Utf8Char.Utf8_2[0];
+ Byte1 = Utf8Char.Utf8_2[1];
+
+ UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f));
+ UnicodeByte1 = (UINT8) ((Byte1 >> 2) & 0x07);
+ *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8));
+ break;
+
+ case 3:
+ //
+ // three-byte utf8 code
+ //
+ Byte0 = Utf8Char.Utf8_3[0];
+ Byte1 = Utf8Char.Utf8_3[1];
+ Byte2 = Utf8Char.Utf8_3[2];
+
+ UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f));
+ UnicodeByte1 = (UINT8) ((Byte2 << 4) | ((Byte1 >> 2) & 0x0f));
+ *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8));
+
+ default:
+ break;
+ }
+
+ return ;
+}
+
+/**
+ Translate one Unicode character into VT-UTF8 characters.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Unicode Unicode character need translating.
+ @param Utf8Char Return VT-UTF8 character set.
+ @param ValidBytes The count of valid VT-UTF8 characters. If
+ ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+UnicodeToUtf8 (
+ IN CHAR16 Unicode,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ )
+{
+ UINT8 UnicodeByte0;
+ UINT8 UnicodeByte1;
+ //
+ // translate unicode to utf8 code
+ //
+ UnicodeByte0 = (UINT8) Unicode;
+ UnicodeByte1 = (UINT8) (Unicode >> 8);
+
+ if (Unicode < 0x0080) {
+
+ Utf8Char->Utf8_1 = (UINT8) (UnicodeByte0 & 0x7f);
+ *ValidBytes = 1;
+
+ } else if (Unicode < 0x0800) {
+ //
+ // byte sequence: high -> low
+ // Utf8_2[0], Utf8_2[1]
+ //
+ Utf8Char->Utf8_2[1] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80);
+ Utf8Char->Utf8_2[0] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x1f) + 0xc0);
+
+ *ValidBytes = 2;
+
+ } else {
+ //
+ // byte sequence: high -> low
+ // Utf8_3[0], Utf8_3[1], Utf8_3[2]
+ //
+ Utf8Char->Utf8_3[2] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80);
+ Utf8Char->Utf8_3[1] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x3f) + 0x80);
+ Utf8Char->Utf8_3[0] = (UINT8) (((UnicodeByte1 >> 4) & 0x0f) + 0xe0);
+
+ *ValidBytes = 3;
+ }
+}
+
+
+/**
+ Check if input string is valid VT-UTF8 string.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+VTUTF8TestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ )
+{
+ //
+ // to utf8, all kind of characters are supported.
+ //
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c
new file mode 100644
index 0000000000..a3f5971b2b
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c
@@ -0,0 +1,436 @@
+/** @file
+ Implementation of Generic Memory Test Protocol which does not perform real memory test.
+ Also clears memory when the MemoryOverwriteRequest bit is set.
+
+ 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.
+
+**/
+
+#include "NullMemoryTest.h"
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/IoLib.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <CMOSMap.h>
+
+UINT64 mTestedSystemMemory = 0;
+UINT64 mTotalSystemMemory = 0;
+EFI_HANDLE mGenericMemoryTestHandle;
+
+EFI_GENERIC_MEMORY_TEST_PROTOCOL mGenericMemoryTest = {
+ InitializeMemoryTest,
+ GenPerformMemoryTest,
+ GenMemoryTestFinished,
+ GenCompatibleRangeTest
+};
+
+EFI_STATUS
+GetMemoryMap (
+ OUT EFI_MEMORY_DESCRIPTOR **EfiMemoryMap,
+ OUT UINTN *EfiMemoryMapSize,
+ UINTN *EfiDescriptorSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN EfiMapKey;
+ UINT32 EfiDescriptorVersion;
+ UINT8 TmpMemoryMap[1];
+
+ //
+ // Get System MemoryMapSize
+ //
+ *EfiMemoryMapSize = 1;
+ Status = gBS->GetMemoryMap (
+ EfiMemoryMapSize,
+ (EFI_MEMORY_DESCRIPTOR *) TmpMemoryMap,
+ &EfiMapKey,
+ EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // This error is expected in first call to GetMemoryMap().
+ // After the first call, GetMemoryMap() will populate EfiMemoryMapSize
+ // with the correct size.
+ //
+ DEBUG ((EFI_D_INFO, "Buffer too small\n"));
+ }
+
+ //
+ // Now that we have the size of the memory map data, allocate some memory to store it in.
+ //
+ (*EfiMemoryMapSize) += EFI_PAGE_SIZE;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ *EfiMemoryMapSize,
+ EfiMemoryMap
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "Can not Allocate Memory\n"));
+ return Status;
+ }
+
+ //
+ // Get System MemoryMap
+ //
+ Status = gBS->GetMemoryMap (
+ EfiMemoryMapSize,
+ *EfiMemoryMap,
+ &EfiMapKey,
+ EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ return Status;
+}
+
+BOOLEAN
+AddresInRange (
+ EFI_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ if (sizeof (UINTN) == sizeof (UINT64)){
+ return TRUE;
+ } else {
+ if (RShiftU64(PhysicalAddress, 32) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+}
+
+EFI_STATUS
+ClearAvailableSystemMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_DESCRIPTOR *EfiEntry;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
+ UINTN EfiMemoryMapSize;
+ UINTN EfiDescriptorSize;
+
+ Status = GetMemoryMap (&EfiMemoryMap, &EfiMemoryMapSize, &EfiDescriptorSize);
+ if (EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ EfiEntry = EfiMemoryMap;
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ while (EfiEntry < EfiMemoryMapEnd) {
+ if (AddresInRange (EfiEntry->PhysicalStart)) {
+ if (EfiEntry->Type == EfiConventionalMemory) {
+ DEBUG((EFI_D_INFO, "CLEAR Memory at 0x%08p; ", EfiEntry->PhysicalStart));
+ DEBUG((EFI_D_INFO, "Length: 0x%08x; Type: 0x%x\n", EFI_PAGES_TO_SIZE (EfiEntry->NumberOfPages), EfiEntry->Type));
+ gBS->SetMem ((VOID *) (UINTN) EfiEntry->PhysicalStart, (UINTN )EFI_PAGES_TO_SIZE (EfiEntry->NumberOfPages), 0);
+ } else {
+ //
+ // Skip this region if it is not "EfiConventionalMemory"
+ //
+ DEBUG ((EFI_D_INFO, "SKIP Memory at 0x%08p; ", EfiEntry->PhysicalStart));
+ DEBUG ((EFI_D_INFO, "Length: 0x%08x; Type: 0x%x\n", EFI_PAGES_TO_SIZE(EfiEntry->NumberOfPages), EfiEntry->Type));
+ }
+ }
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ gBS->FreePool(EfiMemoryMap);
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsMemoryOverwriteRequested (
+ )
+{
+ BOOLEAN bRetValue = 0;
+ EFI_STATUS Status;
+ UINT64 MemoryOverwriteReq = 0;
+ UINTN VariableSize;
+ UINT8 CmosRegValue;
+
+ DEBUG((EFI_D_INFO, "+IsMemoryOverwriteRequested\n"));
+
+ //
+ // Read the CMOS Register EFI_CMOS_CLEAN_RESET
+ //
+ IoWrite8(CmosIo_72, EFI_CMOS_CLEAN_RESET);
+ CmosRegValue = IoRead8(CmosIo_73);
+
+ //
+ // Get the MOR variable
+ //
+ VariableSize = sizeof (MemoryOverwriteReq);
+ Status = gRT->GetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &VariableSize,
+ &MemoryOverwriteReq
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ VariableSize = sizeof (UINT8);
+ Status = gRT->SetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ &MemoryOverwriteReq
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "IsMemoryOverwriteRequested: Failed to Get MOR Variable - Status = %r\n", Status));
+ }
+ goto Exit;
+ }
+
+ DEBUG ((EFI_D_INFO, "IsMemoryOverwriteRequested: MOR Control Value = %02x, CmosRegValue = %02x\n", MemoryOverwriteReq, CmosRegValue));
+
+ if ((MOR_CLEAR_MEMORY_VALUE(MemoryOverwriteReq)) &&
+ (((CmosRegValue != B_MAGIC_CLEAN_RESET_VALUE) && (MOR_DISABLE_AUTO_DETECT_VALUE(MemoryOverwriteReq) == 0)) ||
+ (MOR_DISABLE_AUTO_DETECT_VALUE(MemoryOverwriteReq) == 1))
+ )
+ {
+ DEBUG((EFI_D_INFO, "IsMemoryOverwriteRequested: Un-controlled Reset detected and hence requesting the Memory Clear\n"));
+ bRetValue = 1;
+ }
+
+Exit:
+ IoWrite8(CmosIo_73, B_MAGIC_INIT_VALUE); // Initialize to a known value
+ DEBUG((EFI_D_INFO, "-IsMemoryOverwriteRequested: bRetValue = %d\n", bRetValue));
+ return bRetValue;
+}
+
+VOID
+HandleMorRequest (
+ VOID
+ )
+{
+ BOOLEAN bCleanMemory = 0;
+
+ //
+ // Check if there is a need for memory overwrite.
+ //
+ bCleanMemory = IsMemoryOverwriteRequested();
+
+ //
+ // Clear memory if OS requested a memory overwrite operation.
+ // This is being done for the memory used by OS => Stolen memory is not cleared as OS cannot store keys in UEFI Stolen memory
+ //
+ if (bCleanMemory)
+ {
+ DEBUG((EFI_D_INFO, "Clearing the memory per MOR request.\n"));
+ ClearAvailableSystemMemory();
+ }
+
+ return;
+}
+
+
+/**
+ Entry point of the NULL memory test driver.
+
+ This function is the entry point of the NULL memory test driver.
+ It simply installs the Generic Memory Test Protocol.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Generic Memory Test Protocol is successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericMemoryTestEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallProtocolInterface (
+ &mGenericMemoryTestHandle,
+ &gEfiGenericMemTestProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mGenericMemoryTest
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HandleMorRequest();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the generic memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.MemoryTestInit.
+ It simply promotes untested reserved memory to system memory without real test.
+
+ @param This Protocol instance pointer.
+ @param Level The coverage level of the memory test.
+ @param RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test initialized correctly.
+ @retval EFI_NO_MEDIA There is not any non-tested memory found, in this
+ function if not any non-tesed memory found means
+ that the memory test driver have not detect any
+ non-tested extended memory of current system.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ )
+{
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ (MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
+ ) {
+ //
+ // For those reserved memory that have not been tested, simply promote to system memory.
+ //
+ gDS->RemoveMemorySpace (
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].Length
+ );
+
+ gDS->AddMemorySpace (
+ EfiGcdMemoryTypeSystemMemory,
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].Length,
+ MemorySpaceMap[Index].Capabilities &~
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+
+ mTestedSystemMemory += MemorySpaceMap[Index].Length;
+ mTotalSystemMemory += MemorySpaceMap[Index].Length;
+ } else if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
+ mTotalSystemMemory += MemorySpaceMap[Index].Length;
+ }
+ }
+
+ FreePool (MemorySpaceMap);
+
+ *RequireSoftECCInit = FALSE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform the memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.PerformMemoryTest.
+ It simply returns EFI_NOT_FOUND.
+
+ @param This Protocol instance pointer.
+ @param TestedMemorySize Return the tested extended memory size.
+ @param TotalMemorySize Return the whole system physical memory size, this
+ value may be changed if in some case some error
+ DIMMs be disabled.
+ @param ErrorOut Any time the memory error occurs, this will be
+ TRUE.
+ @param IfTestAbort Indicate if the user press "ESC" to skip the memory
+ test.
+
+ @retval EFI_SUCCESS One block of memory test ok, the block size is hide
+ internally.
+ @retval EFI_NOT_FOUND Indicate all the non-tested memory blocks have
+ already go through.
+ @retval EFI_DEVICE_ERROR Mis-compare error, and no agent can handle it
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ )
+{
+ *ErrorOut = FALSE;
+ *TestedMemorySize = mTestedSystemMemory;
+ *TotalMemorySize = mTotalSystemMemory;
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ The memory test finished.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.Finished.
+ It simply returns EFI_SUCCESS.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Successful free all the generic memory test driver
+ allocated resource and notify to platform memory
+ test driver that memory test finished.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Provide capability to test compatible range which used by some special
+ driver required using memory range before BDS perform memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.CompatibleRangeTest.
+ It simply sets the memory range to system memory.
+
+ @param This Protocol instance pointer.
+ @param StartAddress The start address of the memory range.
+ @param Length The memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range must be below 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+
+ gDS->RemoveMemorySpace (StartAddress, Length);
+
+ gDS->AddMemorySpace (
+ EfiGcdMemoryTypeSystemMemory,
+ StartAddress,
+ Length,
+ Descriptor.Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h
new file mode 100644
index 0000000000..5065bf93b5
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h
@@ -0,0 +1,138 @@
+/** @file
+ Include file of the NULL memory test 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 _NULL_MEMORY_TEST_H_
+#define _NULL_MEMORY_TEST_H_
+
+
+#include <PiDxe.h>
+#include <Protocol/GenericMemoryTest.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Definition of memory status.
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+/**
+ Initialize the generic memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.MemoryTestInit.
+ It simply promotes untested reserved memory to system memory without real test.
+
+ @param This Protocol instance pointer.
+ @param Level The coverage level of the memory test.
+ @param RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test initialized correctly.
+ @retval EFI_NO_MEDIA There is not any non-tested memory found, in this
+ function if not any non-tesed memory found means
+ that the memory test driver have not detect any
+ non-tested extended memory of current system.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ );
+
+/**
+ Perform the memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.PerformMemoryTest.
+ It simply returns EFI_NOT_FOUND.
+
+ @param This Protocol instance pointer.
+ @param TestedMemorySize Return the tested extended memory size.
+ @param TotalMemorySize Return the whole system physical memory size, this
+ value may be changed if in some case some error
+ DIMMs be disabled.
+ @param ErrorOut Any time the memory error occurs, this will be
+ TRUE.
+ @param IfTestAbort Indicate if the user press "ESC" to skip the memory
+ test.
+
+ @retval EFI_SUCCESS One block of memory test ok, the block size is hide
+ internally.
+ @retval EFI_NOT_FOUND Indicate all the non-tested memory blocks have
+ already go through.
+ @retval EFI_DEVICE_ERROR Mis-compare error, and no agent can handle it
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ );
+
+/**
+ The memory test finished.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.Finished.
+ It simply returns EFI_SUCCESS.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Successful free all the generic memory test driver
+ allocated resource and notify to platform memory
+ test driver that memory test finished.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ );
+
+/**
+ Provide capability to test compatible range which used by some special
+ driver required using memory range before BDS perform memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.CompatibleRangeTest.
+ It simply set the memory range to system memory.
+
+ @param This Protocol instance pointer.
+ @param StartAddress The start address of the memory range.
+ @param Length The memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range must be below 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ );
+
+#endif
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
new file mode 100644
index 0000000000..3db2784c77
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
@@ -0,0 +1,63 @@
+## @file
+# This driver installs Generic Memory Test Protocol which does not perform real memory test.
+# Also clears memory when the MemoryOverwriteRequest bit is set.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NullMemoryTestDxe
+ MODULE_UNI_FILE = NullMemoryTestDxe.uni
+ FILE_GUID = 96B5C032-DF4C-4b6e-8232-438DCF448D0E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GenericMemoryTestEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ NullMemoryTest.h
+ NullMemoryTest.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ BroxtonPlatformPkg/PlatformPkg.dec # required for CMOSMap.h
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseLib
+ IoLib
+
+[Protocols]
+ gEfiGenericMemTestProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiMemoryOverwriteControlDataGuid
+
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ NullMemoryTestDxeExtra.uni
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni
new file mode 100644
index 0000000000..5dd1545aa7
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni
Binary files differ
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni
new file mode 100644
index 0000000000..997aba5a6e
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni
Binary files differ
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..107dd16a6a
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.c
@@ -0,0 +1,1424 @@
+/** @file
+ All Pcd Ppi services are implemented here.
+
+ 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.
+
+**/
+
+#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
+ }
+};
+
+/**
+ 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;
+ PEI_PCD_DATABASE *DataBase;
+ EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor;
+
+ DataBase = BuildPcdDatabase (FileHandle);
+
+ //
+ // Add shadow callback and PostMem logic so we can reinstall the Ppis before CAR is removed.
+ //
+ Status = (*PeiServices)->RegisterForShadow (FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = PeiServicesLocatePpi (
+ &gPcdPpiGuid, // GUID
+ 0, // INSTANCE
+ &PeiPpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR
+ NULL // PPI
+ );
+ if (Status == EFI_SUCCESS) {
+ Status = PeiServicesReInstallPpi (PeiPpiDescriptor, &mPpiList[0]);
+ }
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiPcdPpiGuid, // GUID
+ 0, // INSTANCE
+ &PeiPpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR
+ NULL // PPI
+ );
+ if (Status == EFI_SUCCESS) {
+ Status = PeiServicesReInstallPpi (PeiPpiDescriptor, &mPpiList[1]);
+ }
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install PCD_PPI and EFI_PEI_PCD_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Only install PcdInfo PPI when PCD info content is present.
+ //
+ if (DataBase->PcdNameTableOffset != 0) {
+ //
+ // Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList2[0]);
+ 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 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. 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
+ )
+{
+ GetPcdDatabase()->SystemSkuId = (SKU_ID) SkuId;
+
+ 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 (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+
+ for ( ; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExTokenNumber == *TokenNumber) {
+ 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;
+ SKU_ID *SkuIdTable;
+ SIZE_INFO *SizeTable;
+ UINTN Index;
+
+ 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 {
+ if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ return SizeTable[SizeTableIdx + 1];
+ } else {
+ //
+ // We have these entry for SKU enabled PCD entry
+ // 1) MAX SIZE
+ // 2) Current Size for each SKU_ID (It is equal to MaxSku).
+ //
+ SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, Database);
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (SkuIdTable[1 + Index] == Database->SystemSkuId) {
+ return SizeTable[SizeTableIdx + 1 + Index];
+ }
+ }
+ 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;
+ SKU_ID *SkuIdTable;
+ SIZE_INFO *SizeTable;
+ UINTN Index;
+ 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;
+ }
+
+ if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
+ //
+ // 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;
+ } else {
+ //
+ // We have these entry for SKU enabled PCD entry
+ // 1) MAX SIZE
+ // 2) Current Size for each SKU_ID (It is equal to MaxSku).
+ //
+ SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, Database);
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (SkuIdTable[1 + Index] == Database->SystemSkuId) {
+ SizeTable[SizeTableIdx + 1 + Index] = (SIZE_INFO) *CurrentSize;
+ return TRUE;
+ }
+ }
+ 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..2f55cff0c9
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Pcd.inf
@@ -0,0 +1,353 @@
+## @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_SKU_ENABLED
+# 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 - 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.
+#
+##
+
+[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.
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_CONSUMES
+ gPcdPpiGuid ## PRODUCES
+ gEfiPeiPcdPpiGuid ## PRODUCES
+ gGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiFullPcdDatabaseEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry || gEfiMdeModulePkgTokenSpaceGuid.PcdPeiFullPcdDatabaseEnable ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PcdPeimExtra.uni
+
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..10a19908f5
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.c
@@ -0,0 +1,1221 @@
+/** @file
+ The driver internal functions are implmented here.
+ They build Pei PCD database, and provide access service to PCD database.
+
+ 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.
+
+**/
+
+#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;
+ UINTN Size;
+ UINTN MaxSize;
+
+ //
+ // 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);
+
+ Size = (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
+
+ if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {
+ if (Size == 0) {
+ GetPtrTypeSize (TokenNumber, &MaxSize, Database);
+ } else {
+ MaxSize = Size;
+ }
+ LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize);
+ }
+
+ 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;
+}
+
+/**
+ Find the local token number according to system SKU ID.
+
+ @param LocalTokenNumber PCD token number
+ @param Size The size of PCD entry.
+
+ @return Token number according to system SKU ID.
+
+**/
+UINT32
+GetSkuEnabledTokenNumber (
+ UINT32 LocalTokenNumber,
+ UINTN Size
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ SKU_HEAD *SkuHead;
+ SKU_ID *SkuIdTable;
+ INTN Index;
+ UINT8 *Value;
+ BOOLEAN FoundSku;
+
+ PeiPcdDb = GetPcdDatabase ();
+
+ ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);
+
+ SkuHead = (SKU_HEAD *) ((UINT8 *)PeiPcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
+ Value = (UINT8 *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuDataStartOffset));
+ SkuIdTable = (SKU_ID *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuIdTableOffset));
+
+ //
+ // Find the current system's SKU ID entry in SKU ID table.
+ //
+ FoundSku = FALSE;
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (PeiPcdDb->SystemSkuId == SkuIdTable[Index + 1]) {
+ FoundSku = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Find the default SKU ID entry in SKU ID table.
+ //
+ if(!FoundSku) {
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (0 == SkuIdTable[Index + 1]) {
+ break;
+ }
+ }
+ }
+ ASSERT (Index < SkuIdTable[0]);
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ Value = (UINT8 *) &(((VPD_HEAD *) Value)[Index]);
+ return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_VPD);
+
+ case PCD_TYPE_HII:
+ Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
+ return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII);
+
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
+ return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII | PCD_TYPE_STRING);
+
+ case PCD_TYPE_STRING:
+ Value = (UINT8 *) &(((STRING_HEAD *) Value)[Index]);
+ return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_STRING);
+
+ case PCD_TYPE_DATA:
+ Value += Size * Index;
+ return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_DATA);
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ ASSERT (FALSE);
+
+ return 0;
+}
+
+/**
+ 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 SKU ID table from PCD database.
+
+ @param LocalTokenNumberTableIdx Index of local token number in token number table.
+ @param Database PCD database.
+
+ @return Pointer to SKU ID array table
+
+**/
+SKU_ID *
+GetSkuIdArray (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ SKU_HEAD *SkuHead;
+ UINTN LocalTokenNumber;
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
+
+ ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);
+
+ SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
+
+ return (SKU_ID *) ((UINT8 *)Database + SkuHead->SkuIdTableOffset);
+
+}
+
+/**
+ 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;
+ SKU_ID *SkuIdTable;
+
+ 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 {
+ if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTableIdx += 2;
+ } else {
+ //
+ // We have these entry for SKU enabled PCD entry
+ // 1) MAX SIZE
+ // 2) Current Size for each SKU_ID (It is equal to MaxSku).
+ //
+ SkuIdTable = GetSkuIdArray (Index, Database);
+ SizeTableIdx += (UINTN)*SkuIdTable + 1;
+ }
+ }
+ }
+
+ }
+
+ 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..e54c812e2a
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/PCD/Pei/Service.h
@@ -0,0 +1,1120 @@
+/** @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 <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 5
+
+//
+// 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
+ );
+
+/**
+ Find the local token number according to system SKU ID.
+
+ @param LocalTokenNumber PCD token number
+ @param Size The size of PCD entry.
+
+ @return Token number according to system SKU ID.
+
+**/
+UINT32
+GetSkuEnabledTokenNumber (
+ UINT32 LocalTokenNumber,
+ UINTN Size
+ );
+
+/**
+ 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 SKU ID tabble from PCD database.
+
+ @param LocalTokenNumberTableIdx Index of local token number in token number table.
+ @param Database PCD Database in PEI phase
+
+ @return Pointer to SKU ID array table
+
+**/
+SKU_ID *
+GetSkuIdArray (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+/**
+ 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
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c
new file mode 100644
index 0000000000..ed9d48234f
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -0,0 +1,1185 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+ 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.
+
+**/
+
+#include "Variable.h"
+
+//
+// Module globals
+//
+EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
+ PeiGetVariable,
+ PeiGetNextVariableName
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ &mVariablePpi
+};
+
+
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return PeiServicesInstallPpi (&mPpiListVariable);
+}
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+
+/**
+ This code gets the pointer to the last variable memory pointer byte.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return VARIABLE_HEADER* pointer to last unavailable Variable Header.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This code gets the size of variable header.
+
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ if (AuthFlag) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+/**
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->NameSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+ }
+}
+
+
+/**
+ This code gets the size of data of variable.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->DataSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+ }
+}
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable, AuthFlag);
+ Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+ return (UINT8 *) Value;
+}
+
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN Value;
+
+ Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+ Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = HEADER_ALIGN (Value);
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) {
+ //
+ // Next variable is in spare block.
+ //
+ Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress);
+ }
+ }
+
+ return (VARIABLE_HEADER *) Value;
+}
+
+/**
+ Get variable store status.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ }
+
+ if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Name1 Pointer to one variable name.
+ @param Name2 Pointer to another variable name.
+ @param NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialNameSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name1 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name2 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the variable in our database
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param VariableName Name of the variable to compare to 'Variable'
+ @param VendorGuid GUID of the variable to compare to 'Variable'
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VOID *Point;
+ EFI_GUID *TempVendorGuid;
+
+ TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+ if (VariableName[0] == 0) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID a UINT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *) VendorGuid)[0] == ((INT32 *) TempVendorGuid)[0]) &&
+ (((INT32 *) VendorGuid)[1] == ((INT32 *) TempVendorGuid)[1]) &&
+ (((INT32 *) VendorGuid)[2] == ((INT32 *) TempVendorGuid)[2]) &&
+ (((INT32 *) VendorGuid)[3] == ((INT32 *) TempVendorGuid)[3])
+ ) {
+ ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+ Point = (VOID *) GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param Type The type of the variable store.
+ @param StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->FtwLastWriteData = NULL;
+ StoreInfo->AuthFlag = FALSE;
+ VariableStoreHeader = NULL;
+ switch (Type) {
+ case VariableStoreTypeHob:
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = TRUE;
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = FALSE;
+ }
+ }
+ break;
+
+ case VariableStoreTypeNv:
+ //if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) { // Override
+ //
+ // The content of NV storage for variable is not reliable in recovery boot mode.
+ //
+
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
+ PcdGet64 (PcdFlashNvStorageVariableBase64) :
+ PcdGet32 (PcdFlashNvStorageVariableBase)
+ );
+ //
+ // First let FvHeader point to NV storage base.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;
+
+ //
+ // Check the FTW last write data hob.
+ //
+ BackUpOffset = 0;
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ //
+ // Let FvHeader point to spare block.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;
+ DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ StoreInfo->FtwLastWriteData = FtwLastWriteData;
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
+ //
+ }
+ }
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ break;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);
+
+ StoreInfo->AuthFlag = (BOOLEAN) (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));
+
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // If it's the first time to access variable region in flash, create a guid hob to record
+ // VAR_ADDED type variable info.
+ // Note that as the resource of PEI phase is limited, only store the limited number of
+ // VAR_ADDED type variables to reduce access time.
+ //
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+ StoreInfo->IndexTable->Length = 0;
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->GoneThrough = 0;
+ }
+ //} // Override
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ StoreInfo->VariableStoreHeader = VariableStoreHeader;
+ return VariableStoreHeader;
+}
+
+/**
+ Get variable header that has consecutive content.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PartialHeaderSize;
+
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable > (UINTN) SpareAddress) &&
+ (((UINTN) Variable - (UINTN) SpareAddress + (UINTN) TargetAddress) >= (UINTN) GetEndPointer (StoreInfo->VariableStoreHeader))) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN) TargetAddress)) {
+ //
+ // Variable header pointed by Variable is inconsecutive,
+ // create a guid hob to combine the two partial variable header content together.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+ PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+ }
+ }
+ } else {
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+ Get variable name or data to output buffer.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param Size Variable name/data size.
+ @param Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {
+ //
+ // Variable name/data is inconsecutive.
+ //
+ PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem (Buffer, NameOrData, PartialSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);
+ return;
+ }
+ }
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+ Find the variable in the specified variable store.
+
+ @param StoreInfo Pointer to the store info structure.
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableEx (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *LastVariable;
+ VARIABLE_HEADER *MaxIndex;
+ UINTN Index;
+ UINTN Offset;
+ BOOLEAN StopRecord;
+ VARIABLE_HEADER *InDeletedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ VARIABLE_HEADER *VariableHeader;
+
+ VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+ if (VariableStoreHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (~VariableStoreHeader->Size == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ IndexTable = StoreInfo->IndexTable;
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
+
+ InDeletedVariable = NULL;
+
+ //
+ // No Variable Address equals zero, so 0 as initial value is safe.
+ //
+ MaxIndex = NULL;
+ VariableHeader = NULL;
+
+ if (IndexTable != NULL) {
+ //
+ // traverse the variable index table to look for varible.
+ // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
+ //
+ for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
+ ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
+ Offset += IndexTable->Index[Index];
+ MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset);
+ GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+ if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (IndexTable->GoneThrough != 0) {
+ //
+ // If the table has all the existing variables indexed, return.
+ //
+ PtrTrack->CurrPtr = InDeletedVariable;
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+ }
+ }
+
+ if (MaxIndex != NULL) {
+ //
+ // HOB exists but the variable cannot be found in HOB
+ // If not found in HOB, then let's start from the MaxIndex we've found.
+ //
+ Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
+ LastVariable = MaxIndex;
+ } else {
+ //
+ // Start Pointers for the variable.
+ // Actual Data Pointer where data can be written.
+ //
+ Variable = PtrTrack->StartPtr;
+ LastVariable = PtrTrack->StartPtr;
+ }
+
+ //
+ // Find the variable by walk through variable store
+ //
+ StopRecord = FALSE;
+ while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // Record Variable in VariableIndex HOB
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ Offset = (UINTN) Variable - (UINTN) LastVariable;
+ if ((Offset > 0x0FFFF) || (IndexTable->Length == sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
+ //
+ // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
+ // or the record buffer is full.
+ //
+ StopRecord = TRUE;
+ } else {
+ IndexTable->Index[IndexTable->Length++] = (UINT16) Offset;
+ LastVariable = Variable;
+ }
+ }
+
+ if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+ }
+ //
+ // If gone through the VariableStore, that means we never find in Firmware any more.
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ IndexTable->GoneThrough = 1;
+ }
+
+ PtrTrack->CurrPtr = InDeletedVariable;
+
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+ Find the variable in HOB and Non-Volatile variable storages.
+
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param StoreInfo Return the store info.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+**/
+EFI_STATUS
+FindVariable (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_TYPE Type;
+
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ GetVariableStore (Type, StoreInfo);
+ Status = FindVariableEx (
+ StoreInfo,
+ VariableName,
+ VendorGuid,
+ PtrTrack
+ );
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_HEADER *VariableHeader;
+
+ if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableHeader = NULL;
+
+ //
+ // Find existing variable
+ //
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
+ //
+ // Get data size
+ //
+ VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
+
+ if (Attributes != NULL) {
+ *Attributes = VariableHeader->Attributes;
+ }
+
+ *DataSize = VarDataSize;
+ return EFI_SUCCESS;
+ } else {
+ *DataSize = VarDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_STORE_TYPE Type;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariableInHob;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ UINTN VarNameSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_INFO StoreInfoForNv;
+ VARIABLE_STORE_INFO StoreInfoForHob;
+
+ if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableHeader = NULL;
+
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable
+ //
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+
+ VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+ VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
+
+ while (TRUE) {
+ //
+ // Switch from HOB to Non-Volatile.
+ //
+ while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+ //
+ // Find current storage index
+ //
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+ break;
+ }
+ }
+ ASSERT (Type < VariableStoreTypeMax);
+ //
+ // Switch to next storage
+ //
+ for (Type++; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] != NULL) {
+ break;
+ }
+ }
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (Type == VariableStoreTypeMax) {
+ return EFI_NOT_FOUND;
+ }
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.CurrPtr = Variable.StartPtr;
+ GetVariableStore (Type, &StoreInfo);
+ }
+
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ Status = FindVariableEx (
+ &StoreInfo,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ //
+ // Don't return NV variable when HOB overrides it
+ //
+ if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
+ (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
+ ) {
+ Status = FindVariableEx (
+ &StoreInfoForHob,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariableInHob
+ );
+ if (!EFI_ERROR (Status)) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ ASSERT (VarNameSize != 0);
+
+ if (VarNameSize <= *VariableNameSize) {
+ GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *) VariableName);
+
+ CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ //
+ // Variable is found
+ //
+ return Status;
+ } else {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+ }
+}
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h
new file mode 100644
index 0000000000..98a6760354
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -0,0 +1,151 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+ 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_VARIABLE_H_
+#define _PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VariableIndexTable.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+
+typedef enum {
+ VariableStoreTypeHob,
+ VariableStoreTypeNv,
+ VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ //
+ // If it is not NULL, it means there may be an inconsecutive variable whose
+ // partial content is still in NV storage, but another partial content is backed up
+ // in spare block.
+ //
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ BOOLEAN AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+#endif
+
diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
new file mode 100644
index 0000000000..bcfd845de4
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -0,0 +1,77 @@
+## @file
+# Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiVariable
+ MODULE_UNI_FILE = PeiVariable.uni
+ FILE_GUID = 34C8C28F-B61C-45a2-8F2E-89E46BECC63B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VariableServicesLib
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Variable.c
+ Variable.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ HobLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+
+[Guids]
+ ## CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiAuthenticatedVariableGuid
+ ## SOMETIMES_CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableGuid
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableIndexTableGuid
+ gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## HOB
+ ## CONSUMES ## GUID # Dependence
+ gEdkiiFaultTolerantWriteGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiVariableExtra.uni
+