public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib
@ 2023-06-01  3:02 Zhiguang Liu
  2023-06-05  3:26 ` [edk2-devel] " Ni, Ray
  0 siblings, 1 reply; 2+ messages in thread
From: Zhiguang Liu @ 2023-06-01  3:02 UTC (permalink / raw)
  To: devel; +Cc: Zhiguang Liu, Michael D Kinney, Michael Kubacki, Sean Brogan

This library supports a PeiServicesTablePointerLib implementation
that allows code dependent upon PeiServicesTable to operate in an
isolated execution environment such as within the context of a
host-based unit test framework.

The unit test should initialize the PeiServicesTable database with
any required elements (e.g. PPIs, Hob etc.) prior to the services
being invoked by code under test.

It is strongly recommended to clean any global databases by using
EFI_PEI_SERVICES.ResetSystem2 after every unit test so the tests
execute in a predictable manner from a clean state.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
---
 .../UnitTestPeiServicesTablePointerLib.c      | 215 ++++++
 .../UnitTestPeiServicesTablePointerLib.h      | 658 ++++++++++++++++++
 .../UnitTestPeiServicesTablePointerLib.inf    |  38 +
 .../UnitTestPeiServicesTablePointerLib.uni    |  12 +
 .../UnitTestPeiServicesTablePointerLibHob.c   | 162 +++++
 .../UnitTestPeiServicesTablePointerLibMisc.c  | 430 ++++++++++++
 .../UnitTestPeiServicesTablePointerLibPpi.c   | 485 +++++++++++++
 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc |   1 +
 .../UnitTestFrameworkPkgHost.dsc.inc          |   1 +
 9 files changed, 2002 insertions(+)
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibHob.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibMisc.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibPpi.c

diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.c b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.c
new file mode 100644
index 0000000000..62ba0048dd
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.c
@@ -0,0 +1,215 @@
+/** @file
+  This library supports a PEI Service table Pointer library implementation that
+  allows code dependent upon PEI Service to operate in an isolated execution environment
+  such as within the context of a host-based unit test framework.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UnitTestPeiServicesTablePointerLib.h"
+
+#define MAX_PPI_COUNT  100
+#define MAX_HOB_SIZE   SIZE_32MB
+
+///
+/// Pei service instance
+///
+EFI_PEI_SERVICES  mPeiServices = {
+  {
+    PEI_SERVICES_SIGNATURE,
+    PEI_SERVICES_REVISION,
+    sizeof (EFI_PEI_SERVICES),
+    0,
+    0
+  },
+  UnitTestInstallPpi,   // InstallPpi
+  UnitTestReInstallPpi, // ReInstallPpi
+  UnitTestLocatePpi,    // LocatePpi
+  UnitTestNotifyPpi,    // NotifyPpi
+
+  UnitTestGetBootMode,  // GetBootMode
+  UnitTestSetBootMode,  // SetBootMode
+
+  UnitTestGetHobList, // GetHobList
+  UnitTestCreateHob,  // CreateHob
+
+  UnitTestFfsFindNextVolume,  // FfsFindNextVolume
+  UnitTestFfsFindNextFile,    // FfsFindNextFile
+  UnitTestFfsFindSectionData, // FfsFindSectionData
+
+  UnitTestInstallPeiMemory, // InstallPeiMemory
+  UnitTestAllocatePages,    // AllocatePages
+  UnitTestAllocatePool,     // AllocatePool
+  (EFI_PEI_COPY_MEM)CopyMem,
+  (EFI_PEI_SET_MEM)SetMem,
+
+  UnitTestReportStatusCode, // ReportStatusCode
+  UnitTestResetSystem,      // ResetSystem
+
+  NULL,  // CpuIo
+  NULL,  // PciCfg
+
+  UnitTestFfsFindFileByName,   // FfsFindFileByName
+  UnitTestFfsGetFileInfo,      // FfsGetFileInfo
+  UnitTestFfsGetVolumeInfo,    // FfsGetVolumeInfo
+  UnitTestRegisterForShadow,   // RegisterForShadow
+  UnitTestFfsFindSectionData3, // FfsFindSectionData3
+  UnitTestFfsGetFileInfo2,     // FfsGetFileInfo2
+  UnitTestResetSystem2,        // ResetSystem2
+  UnitTestFreePages,           // FreePages
+};
+
+EFI_PEI_SERVICES   *mPeiServicesPointer = &mPeiServices;
+BOOLEAN            PSInitDone           = FALSE;
+PEI_CORE_INSTANCE  mPrivateData;
+VOID               *mHobBuffer;
+VOID               *mPpiBuffer;
+VOID               *mPpiNotifyBuffer;
+
+/**
+  Allocate Buffer Or Clear Buffer For Global Data.
+**/
+VOID
+AllocateBufferOrClearBufferForGlobalData (
+  VOID
+  )
+{
+  ZeroMem (&mPrivateData, sizeof (mPrivateData));
+  if (!PSInitDone) {
+    mHobBuffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_HOB_SIZE));
+    ASSERT (mHobBuffer != NULL);
+
+    mPpiBuffer = AllocateZeroPool (sizeof (PEI_PPI_LIST_POINTERS) * MAX_PPI_COUNT);
+    ASSERT (mPpiBuffer != NULL);
+
+    mPpiNotifyBuffer = AllocateZeroPool (sizeof (PEI_PPI_LIST_POINTERS) * MAX_PPI_COUNT);
+    ASSERT (mPpiNotifyBuffer != NULL);
+
+    PSInitDone = TRUE;
+  } else {
+    ZeroMem (mHobBuffer, MAX_HOB_SIZE);
+    ZeroMem (mPpiBuffer, sizeof (PEI_PPI_LIST_POINTERS) * MAX_PPI_COUNT);
+    ZeroMem (mPpiNotifyBuffer, sizeof (PEI_PPI_LIST_POINTERS) * MAX_PPI_COUNT);
+  }
+
+  mPrivateData.PpiData.PpiList.PpiPtrs  = mPpiBuffer;
+  mPrivateData.PpiData.PpiList.MaxCount = MAX_PPI_COUNT;
+
+  mPrivateData.PpiData.DispatchNotifyList.NotifyPtrs = mPpiNotifyBuffer;
+  mPrivateData.PpiData.DispatchNotifyList.MaxCount   = MAX_PPI_COUNT;
+
+  mPrivateData.HobList.Raw = mHobBuffer;
+  UnitTestCoreBuildHobHandoffInfoTable (0, (EFI_PHYSICAL_ADDRESS)(UINTN)mHobBuffer, MAX_HOB_SIZE);
+}
+
+/**
+  Resets the entire platform.
+
+  @param[in] ResetType      The type of reset to perform.
+  @param[in] ResetStatus    The status code for the reset.
+  @param[in] DataSize       The size, in bytes, of ResetData.
+  @param[in] ResetData      For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+                            the data buffer starts with a Null-terminated string, optionally
+                            followed by additional binary data. The string is a description
+                            that the caller may use to further indicate the reason for the
+                            system reset.
+
+**/
+VOID
+EFIAPI
+UnitTestResetSystem2 (
+  IN EFI_RESET_TYPE  ResetType,
+  IN EFI_STATUS      ResetStatus,
+  IN UINTN           DataSize,
+  IN VOID            *ResetData OPTIONAL
+  )
+{
+  AllocateBufferOrClearBufferForGlobalData ();
+}
+
+/**
+  Retrieves the cached value of the PEI Services Table pointer.
+
+  Returns the cached value of the PEI Services Table pointer in a CPU specific manner
+  as specified in the CPU binding section of the Platform Initialization Pre-EFI
+  Initialization Core Interface Specification.
+
+  If the cached PEI Services Table pointer is NULL, then ASSERT().
+
+  @return  The pointer to PeiServices.
+
+**/
+CONST EFI_PEI_SERVICES **
+EFIAPI
+GetPeiServicesTablePointer (
+  VOID
+  )
+{
+  return (CONST EFI_PEI_SERVICES **)&mPeiServices;
+}
+
+/**
+  Caches a pointer PEI Services Table.
+
+  Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
+  in a CPU specific manner as specified in the CPU binding section of the Platform Initialization
+  Pre-EFI Initialization Core Interface Specification.
+
+  If PeiServicesTablePointer is NULL, then ASSERT().
+
+  @param    PeiServicesTablePointer   The address of PeiServices pointer.
+**/
+VOID
+EFIAPI
+SetPeiServicesTablePointer (
+  IN CONST EFI_PEI_SERVICES  **PeiServicesTablePointer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Perform CPU specific actions required to migrate the PEI Services Table
+  pointer from temporary RAM to permanent RAM.
+
+  For IA32 CPUs, the PEI Services Table pointer is stored in the 4 bytes
+  immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+  For X64 CPUs, the PEI Services Table pointer is stored in the 8 bytes
+  immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+  For Itanium and ARM CPUs, a the PEI Services Table Pointer is stored in
+  a dedicated CPU register.  This means that there is no memory storage
+  associated with storing the PEI Services Table pointer, so no additional
+  migration actions are required for Itanium or ARM CPUs.
+
+**/
+VOID
+EFIAPI
+MigratePeiServicesTablePointer (
+  VOID
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  The constructor function init PeiServicesTable with clean buffer.
+
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestUefiBootServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  AllocateBufferOrClearBufferForGlobalData ();
+  return EFI_SUCCESS;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
new file mode 100644
index 0000000000..3b7b526ece
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
@@ -0,0 +1,658 @@
+/** @file
+  An internal header file for the Unit Test instance of the PEI services Table Pointer Library.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_SERVICES_TABLE_POINTER_LIB_UNIT_TEST_H_
+#define PEI_SERVICES_TABLE_POINTER_LIB_UNIT_TEST_H_
+
+#include <Base.h>
+#include <PiPei.h>
+#include <Pi/PiMultiPhase.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UnitTestLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Uefi.h>
+
+///
+/// Forward declaration for PEI_CORE_INSTANCE
+///
+typedef struct _PEI_CORE_INSTANCE PEI_CORE_INSTANCE;
+
+///
+/// Pei Core private data structures
+///
+typedef union {
+  EFI_PEI_PPI_DESCRIPTOR       *Ppi;
+  EFI_PEI_NOTIFY_DESCRIPTOR    *Notify;
+  VOID                         *Raw;
+} PEI_PPI_LIST_POINTERS;
+
+///
+/// Number of PEI_PPI_LIST_POINTERS to grow by each time we run out of room
+///
+#define PPI_GROWTH_STEP              64
+#define CALLBACK_NOTIFY_GROWTH_STEP  32
+#define DISPATCH_NOTIFY_GROWTH_STEP  8
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  UINTN                    LastDispatchedCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    *PpiPtrs;
+} PEI_PPI_LIST;
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    *NotifyPtrs;
+} PEI_CALLBACK_NOTIFY_LIST;
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  UINTN                    LastDispatchedCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    *NotifyPtrs;
+} PEI_DISPATCH_NOTIFY_LIST;
+
+///
+/// PPI database structure which contains three links:
+/// PpiList, CallbackNotifyList and DispatchNotifyList.
+///
+typedef struct {
+  ///
+  /// PPI List.
+  ///
+  PEI_PPI_LIST                PpiList;
+  ///
+  /// Notify List at dispatch level.
+  ///
+  PEI_CALLBACK_NOTIFY_LIST    CallbackNotifyList;
+  ///
+  /// Notify List at callback level.
+  ///
+  PEI_DISPATCH_NOTIFY_LIST    DispatchNotifyList;
+} PEI_PPI_DATABASE;
+
+///
+/// Pei Core private data structure instance
+///
+struct _PEI_CORE_INSTANCE {
+  PEI_PPI_DATABASE        PpiData;
+  EFI_PEI_HOB_POINTERS    HobList;
+};
+
+extern PEI_CORE_INSTANCE  mPrivateData;
+#define PEI_CORE_INSTANCE_FROM_PS_THIS(a)  &mPrivateData
+
+VOID
+ProcessNotify (
+  IN PEI_CORE_INSTANCE  *PrivateData,
+  IN UINTN              NotifyType,
+  IN INTN               InstallStartIndex,
+  IN INTN               InstallStopIndex,
+  IN INTN               NotifyStartIndex,
+  IN INTN               NotifyStopIndex
+  );
+
+/**
+
+  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
+UnitTestInstallPpi (
+  IN CONST EFI_PEI_SERVICES        **PeiServices,
+  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
+  );
+
+/**
+
+  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
+UnitTestReInstallPpi (
+  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
+UnitTestLocatePpi (
+  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
+  );
+
+/**
+
+  This function installs a notification service to be called back when a given
+  interface is installed or reinstalled. The purpose of the service is to publish
+  an interface that other parties can use to call additional PPIs that may materialize later.
+
+  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param NotifyList         Pointer to list of Descriptors to notify upon.
+
+  @retval EFI_SUCCESS           if successful
+  @retval EFI_OUT_OF_RESOURCES  if no space in the database
+  @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestNotifyPpi (
+  IN CONST EFI_PEI_SERVICES           **PeiServices,
+  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
+  );
+
+/**
+  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
+UnitTestGetHobList (
+  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
+UnitTestCreateHob (
+  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
+UnitTestCoreBuildHobHandoffInfoTable (
+  IN EFI_BOOT_MODE         BootMode,
+  IN EFI_PHYSICAL_ADDRESS  MemoryBegin,
+  IN UINT64                MemoryLength
+  );
+
+/**
+  Resets the entire platform.
+
+  @param[in] ResetType      The type of reset to perform.
+  @param[in] ResetStatus    The status code for the reset.
+  @param[in] DataSize       The size, in bytes, of ResetData.
+  @param[in] ResetData      For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+                            the data buffer starts with a Null-terminated string, optionally
+                            followed by additional binary data. The string is a description
+                            that the caller may use to further indicate the reason for the
+                            system reset.
+
+**/
+VOID
+EFIAPI
+UnitTestResetSystem2 (
+  IN EFI_RESET_TYPE  ResetType,
+  IN EFI_STATUS      ResetStatus,
+  IN UINTN           DataSize,
+  IN VOID            *ResetData OPTIONAL
+  );
+
+/**
+  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
+UnitTestGetBootMode (
+  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
+UnitTestSetBootMode (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_BOOT_MODE           BootMode
+  );
+
+/**
+  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
+UnitTestFfsFindNextVolume (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN     UINTN               Instance,
+  IN OUT EFI_PEI_FV_HANDLE   *VolumeHandle
+  );
+
+/**
+  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
+UnitTestFfsFindNextFile (
+  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
+UnitTestFfsFindSectionData (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN     EFI_SECTION_TYPE     SectionType,
+  IN     EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT VOID                    **SectionData
+  );
+
+/**
+
+  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 permanent 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
+UnitTestInstallPeiMemory (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    MemoryBegin,
+  IN UINT64                  MemoryLength
+  );
+
+/**
+  The purpose of the service is to publish an interface that allows
+  PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+  Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+  After InstallPeiMemory() is called, PEI will allocate pages within the region
+  of memory provided by InstallPeiMemory() service in a best-effort fashion.
+  Location-specific allocations are not managed by the PEI foundation code.
+
+  @param  PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param  MemoryType       The type of memory to allocate.
+  @param  Pages            The number of contiguous 4 KB pages to allocate.
+  @param  Memory           Pointer to a physical address. On output, the address is set to the base
+                           of the page range that was allocated.
+
+  @retval EFI_SUCCESS           The memory range was successfully allocated.
+  @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
+  @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+                                EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+                                EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestAllocatePages (
+  IN CONST EFI_PEI_SERVICES      **PeiServices,
+  IN       EFI_MEMORY_TYPE       MemoryType,
+  IN       UINTN                 Pages,
+  OUT      EFI_PHYSICAL_ADDRESS  *Memory
+  );
+
+/**
+
+  Pool allocation service. Before permanent memory is discovered, the pool will
+  be allocated in the heap in temporary memory. Generally, the size of the heap in temporary
+  memory does not exceed 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
+UnitTestAllocatePool (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN       UINTN             Size,
+  OUT      VOID              **Buffer
+  );
+
+/**
+
+  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
+UnitTestReportStatusCode (
+  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
+UnitTestResetSystem (
+  IN CONST EFI_PEI_SERVICES  **PeiServices
+  );
+
+/**
+  Find a file within a volume by its name.
+
+  @param FileName        A pointer to the name of the file to find within the firmware volume.
+  @param VolumeHandle    The firmware volume to search
+  @param FileHandle      Upon exit, points to the found file's handle
+                         or NULL if it could not be found.
+
+  @retval EFI_SUCCESS            File was found.
+  @retval EFI_NOT_FOUND          File was not found.
+  @retval EFI_INVALID_PARAMETER  VolumeHandle or FileHandle or FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFfsFindFileByName (
+  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
+UnitTestFfsGetFileInfo (
+  IN EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT EFI_FV_FILE_INFO    *FileInfo
+  );
+
+/**
+  Returns information about the specified volume.
+
+  This function returns information about a specific firmware
+  volume, including its name, type, attributes, starting address
+  and size.
+
+  @param VolumeHandle   Handle of the volume.
+  @param VolumeInfo     Upon exit, points to the volume's information.
+
+  @retval EFI_SUCCESS             Volume information returned.
+  @retval EFI_INVALID_PARAMETER   If VolumeHandle does not represent a valid volume.
+  @retval EFI_INVALID_PARAMETER   If VolumeHandle is NULL.
+  @retval EFI_SUCCESS             Information successfully returned.
+  @retval EFI_INVALID_PARAMETER   The volume designated by the VolumeHandle is not available.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFfsGetVolumeInfo (
+  IN EFI_PEI_FV_HANDLE  VolumeHandle,
+  OUT EFI_FV_INFO       *VolumeInfo
+  );
+
+/**
+This routine enables a PEIM to register itself for shadow when the PEI Foundation
+discovers 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
+UnitTestRegisterForShadow (
+  IN 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           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
+UnitTestFfsFindSectionData3 (
+  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
+  );
+
+/**
+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
+UnitTestFfsGetFileInfo2 (
+  IN EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT EFI_FV_FILE_INFO2   *FileInfo
+  );
+
+/**
+Frees memory pages.
+
+@param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+@param[in] Memory             The base physical address of the pages to be freed.
+@param[in] Pages              The number of contiguous 4 KB pages to free.
+
+@retval EFI_SUCCESS           The requested pages were freed.
+@retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+@retval EFI_NOT_FOUND         The requested memory pages were not allocated with
+                              AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFreePages (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    Memory,
+  IN UINTN                   Pages
+  );
+
+#endif
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
new file mode 100644
index 0000000000..c43f4cb1b5
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
@@ -0,0 +1,38 @@
+## @file
+# Pei Services Table Pointer Lib for unit tests implementation.
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = UnitTestPeiServicesTablePointerLib
+  MODULE_UNI_FILE                = UnitTestPeiServicesTablePointerLib.uni
+  FILE_GUID                      = 55F23CD2-9BB1-41EE-AB10-550B638210E1
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PeiServicesTablePointerLib
+
+  CONSTRUCTOR                    = UnitTestPeiServicesTablePointerLibConstructor
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  UnitTestPeiServicesTablePointerLib.h
+  UnitTestPeiServicesTablePointerLib.c
+  UnitTestPeiServicesTablePointerLibMisc.c
+  UnitTestPeiServicesTablePointerLibPpi.c
+  UnitTestPeiServicesTablePointerLibHob.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  UnitTestLib
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.uni b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.uni
new file mode 100644
index 0000000000..ca2118533a
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.uni
@@ -0,0 +1,12 @@
+// /** @file
+//  Pei Services Table Pointer Lib for unit tests implementation.
+//
+//  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Pei Services Table Pointer Lib for unit tests."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Pei Services Table Pointer Lib for unit tests."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibHob.c b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibHob.c
new file mode 100644
index 0000000000..2d4ffe8c59
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibHob.c
@@ -0,0 +1,162 @@
+/** @file
+  This file implements some PEI services about Hob.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UnitTestPeiServicesTablePointerLib.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
+UnitTestGetHobList (
+  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
+UnitTestCreateHob (
+  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 = UnitTestGetHobList (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 ((DEBUG_ERROR, "PeiCreateHob fail: Length - 0x%08x\n", (UINTN)Length));
+    DEBUG ((DEBUG_ERROR, "  FreeMemoryTop    - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryTop));
+    DEBUG ((DEBUG_ERROR, "  FreeMemoryBottom - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryBottom));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  *Hob                                        = (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
+UnitTestCoreBuildHobHandoffInfoTable (
+  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/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibMisc.c b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibMisc.c
new file mode 100644
index 0000000000..90955bf482
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibMisc.c
@@ -0,0 +1,430 @@
+/** @file
+  This file implements some PEI services.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UnitTestPeiServicesTablePointerLib.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
+UnitTestGetBootMode (
+  IN  CONST EFI_PEI_SERVICES  **PeiServices,
+  IN  OUT   EFI_BOOT_MODE     *BootMode
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  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
+UnitTestSetBootMode (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_BOOT_MODE           BootMode
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  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
+UnitTestFfsFindNextVolume (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN     UINTN               Instance,
+  IN OUT EFI_PEI_FV_HANDLE   *VolumeHandle
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  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
+UnitTestFfsFindNextFile (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN UINT8                    SearchType,
+  IN EFI_PEI_FV_HANDLE        FvHandle,
+  IN OUT EFI_PEI_FILE_HANDLE  *FileHandle
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  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
+UnitTestFfsFindSectionData (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN     EFI_SECTION_TYPE     SectionType,
+  IN     EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT VOID                    **SectionData
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+
+  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 permanent 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
+UnitTestInstallPeiMemory (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    MemoryBegin,
+  IN UINT64                  MemoryLength
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  The purpose of the service is to publish an interface that allows
+  PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+  Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+  After InstallPeiMemory() is called, PEI will allocate pages within the region
+  of memory provided by InstallPeiMemory() service in a best-effort fashion.
+  Location-specific allocations are not managed by the PEI foundation code.
+
+  @param  PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param  MemoryType       The type of memory to allocate.
+  @param  Pages            The number of contiguous 4 KB pages to allocate.
+  @param  Memory           Pointer to a physical address. On output, the address is set to the base
+                           of the page range that was allocated.
+
+  @retval EFI_SUCCESS           The memory range was successfully allocated.
+  @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
+  @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+                                EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+                                EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestAllocatePages (
+  IN CONST EFI_PEI_SERVICES      **PeiServices,
+  IN       EFI_MEMORY_TYPE       MemoryType,
+  IN       UINTN                 Pages,
+  OUT      EFI_PHYSICAL_ADDRESS  *Memory
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+
+  Pool allocation service. Before permanent memory is discovered, the pool will
+  be allocated in the heap in temporary memory. Generally, the size of the heap in temporary
+  memory does not exceed 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
+UnitTestAllocatePool (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN       UINTN             Size,
+  OUT      VOID              **Buffer
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+
+  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
+UnitTestReportStatusCode (
+  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
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+
+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
+UnitTestResetSystem (
+  IN CONST EFI_PEI_SERVICES  **PeiServices
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  Find a file within a volume by its name.
+
+  @param FileName        A pointer to the name of the file to find within the firmware volume.
+  @param VolumeHandle    The firmware volume to search
+  @param FileHandle      Upon exit, points to the found file's handle
+                         or NULL if it could not be found.
+
+  @retval EFI_SUCCESS            File was found.
+  @retval EFI_NOT_FOUND          File was not found.
+  @retval EFI_INVALID_PARAMETER  VolumeHandle or FileHandle or FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFfsFindFileByName (
+  IN  CONST EFI_GUID       *FileName,
+  IN  EFI_PEI_FV_HANDLE    VolumeHandle,
+  OUT EFI_PEI_FILE_HANDLE  *FileHandle
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  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
+UnitTestFfsGetFileInfo (
+  IN EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT EFI_FV_FILE_INFO    *FileInfo
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+  Returns information about the specified volume.
+
+  This function returns information about a specific firmware
+  volume, including its name, type, attributes, starting address
+  and size.
+
+  @param VolumeHandle   Handle of the volume.
+  @param VolumeInfo     Upon exit, points to the volume's information.
+
+  @retval EFI_SUCCESS             Volume information returned.
+  @retval EFI_INVALID_PARAMETER   If VolumeHandle does not represent a valid volume.
+  @retval EFI_INVALID_PARAMETER   If VolumeHandle is NULL.
+  @retval EFI_SUCCESS             Information successfully returned.
+  @retval EFI_INVALID_PARAMETER   The volume designated by the VolumeHandle is not available.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFfsGetVolumeInfo (
+  IN EFI_PEI_FV_HANDLE  VolumeHandle,
+  OUT EFI_FV_INFO       *VolumeInfo
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+This routine enables a PEIM to register itself for shadow when the PEI Foundation
+discovers 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
+UnitTestRegisterForShadow (
+  IN EFI_PEI_FILE_HANDLE  FileHandle
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+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
+UnitTestFfsFindSectionData3 (
+  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
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+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
+UnitTestFfsGetFileInfo2 (
+  IN EFI_PEI_FILE_HANDLE  FileHandle,
+  OUT EFI_FV_FILE_INFO2   *FileInfo
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+Frees memory pages.
+
+@param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+@param[in] Memory             The base physical address of the pages to be freed.
+@param[in] Pages              The number of contiguous 4 KB pages to free.
+
+@retval EFI_SUCCESS           The requested pages were freed.
+@retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+@retval EFI_NOT_FOUND         The requested memory pages were not allocated with
+                              AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestFreePages (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    Memory,
+  IN UINTN                   Pages
+  )
+{
+  return EFI_NOT_AVAILABLE_YET;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibPpi.c b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibPpi.c
new file mode 100644
index 0000000000..09f4094dad
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLibPpi.c
@@ -0,0 +1,485 @@
+/** @file
+  This file implements some PEI services about PPI.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UnitTestPeiServicesTablePointerLib.h"
+
+/**
+
+  This function installs an interface in the PEI PPI database by GUID.
+  The purpose of the service is to publish an interface that other parties
+  can use to call additional PEIMs.
+
+  @param PeiServices                An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param PpiList                    Pointer to a list of PEI PPI Descriptors.
+  @param Single                     TRUE if only single entry in the PpiList.
+                                    FALSE if the PpiList is ended with an entry which has the
+                                    EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+  @retval EFI_SUCCESS              if all PPIs in PpiList are successfully installed.
+  @retval EFI_INVALID_PARAMETER    if PpiList is NULL pointer
+                                   if any PPI in PpiList is not valid
+  @retval EFI_OUT_OF_RESOURCES     if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+InternalPeiInstallPpi (
+  IN CONST EFI_PEI_SERVICES        **PeiServices,
+  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList,
+  IN BOOLEAN                       Single
+  )
+{
+  PEI_CORE_INSTANCE  *PrivateData;
+  PEI_PPI_LIST       *PpiListPointer;
+  UINTN              Index;
+  UINTN              LastCount;
+
+  if (PpiList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+  PpiListPointer = &PrivateData->PpiData.PpiList;
+  Index          = PpiListPointer->CurrentCount;
+  LastCount      = 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 ( ; ;) {
+    //
+    // 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) {
+      PpiListPointer->CurrentCount = LastCount;
+      DEBUG ((DEBUG_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (Index >= PpiListPointer->MaxCount) {
+      //
+      // Run out of room, assert.
+      //
+      ASSERT (Index < PpiListPointer->MaxCount);
+    }
+
+    DEBUG ((DEBUG_INFO, "Install PPI: %g\n", PpiList->Guid));
+    PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)PpiList;
+    Index++;
+    PpiListPointer->CurrentCount++;
+
+    if (Single) {
+      //
+      // Only single entry in the PpiList.
+      //
+      break;
+    } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+               EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
+    {
+      //
+      // Continue until the end of the PPI List.
+      //
+      break;
+    }
+
+    //
+    // Go to the next descriptor.
+    //
+    PpiList++;
+  }
+
+  //
+  // Process any callback level notifies for newly installed PPIs.
+  //
+  ProcessNotify (
+    PrivateData,
+    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+    LastCount,
+    PpiListPointer->CurrentCount,
+    0,
+    PrivateData->PpiData.CallbackNotifyList.CurrentCount
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This function installs an interface in the PEI PPI database by GUID.
+  The purpose of the service is to publish an interface that other parties
+  can use to call additional PEIMs.
+
+  @param PeiServices                An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param PpiList                    Pointer to a list of PEI PPI Descriptors.
+
+  @retval EFI_SUCCESS              if all PPIs in PpiList are successfully installed.
+  @retval EFI_INVALID_PARAMETER    if PpiList is NULL pointer
+                                   if any PPI in PpiList is not valid
+  @retval EFI_OUT_OF_RESOURCES     if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestInstallPpi (
+  IN CONST EFI_PEI_SERVICES        **PeiServices,
+  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
+  )
+{
+  return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
+}
+
+/**
+
+  This function reinstalls an interface in the PEI PPI database by GUID.
+  The purpose of the service is to publish an interface that other parties can
+  use to replace an interface of the same name in the protocol database with a
+  different interface.
+
+  @param PeiServices            An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param OldPpi                 Pointer to the old PEI PPI Descriptors.
+  @param NewPpi                 Pointer to the new PEI PPI Descriptors.
+
+  @retval EFI_SUCCESS           if the operation was successful
+  @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
+  @retval EFI_INVALID_PARAMETER if NewPpi is not valid
+  @retval EFI_NOT_FOUND         if the PPI was not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestReInstallPpi (
+  IN CONST EFI_PEI_SERVICES        **PeiServices,
+  IN CONST EFI_PEI_PPI_DESCRIPTOR  *OldPpi,
+  IN CONST EFI_PEI_PPI_DESCRIPTOR  *NewPpi
+  )
+{
+  PEI_CORE_INSTANCE  *PrivateData;
+  UINTN              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.PpiList.CurrentCount; Index++) {
+    if (OldPpi == PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi) {
+      break;
+    }
+  }
+
+  if (Index == PrivateData->PpiData.PpiList.CurrentCount) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Replace the old PPI with the new one.
+  //
+  DEBUG ((DEBUG_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
+  PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)NewPpi;
+
+  //
+  // Process any callback level notifies for the newly installed PPI.
+  //
+  ProcessNotify (
+    PrivateData,
+    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+    Index,
+    Index+1,
+    0,
+    PrivateData->PpiData.CallbackNotifyList.CurrentCount
+    );
+
+  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
+UnitTestLocatePpi (
+  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;
+  UINTN                   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.PpiList.CurrentCount; Index++) {
+    TempPtr   = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
+    CheckGuid = TempPtr->Guid;
+
+    //
+    // Don't use CompareGuid function here for performance reasons.
+    // Instead we compare the GUID as INT32 at a time and branch
+    // on the first failed comparison.
+    //
+    if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
+        (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
+        (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
+        (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
+    {
+      if (Instance == 0) {
+        if (PpiDescriptor != NULL) {
+          *PpiDescriptor = TempPtr;
+        }
+
+        if (Ppi != NULL) {
+          *Ppi = TempPtr->Ppi;
+        }
+
+        return EFI_SUCCESS;
+      }
+
+      Instance--;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+
+  This function installs a notification service to be called back when a given
+  interface is installed or reinstalled. The purpose of the service is to publish
+  an interface that other parties can use to call additional PPIs that may materialize later.
+
+  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param NotifyList         Pointer to list of Descriptors to notify upon.
+  @param Single             TRUE if only single entry in the NotifyList.
+                            FALSE if the NotifyList is ended with an entry which has the
+                            EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+  @retval EFI_SUCCESS           if successful
+  @retval EFI_OUT_OF_RESOURCES  if no space in the database
+  @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+InternalPeiNotifyPpi (
+  IN CONST EFI_PEI_SERVICES           **PeiServices,
+  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList,
+  IN BOOLEAN                          Single
+  )
+{
+  PEI_CORE_INSTANCE         *PrivateData;
+  PEI_CALLBACK_NOTIFY_LIST  *CallbackNotifyListPointer;
+  UINTN                     CallbackNotifyIndex;
+  UINTN                     LastCallbackNotifyCount;
+  PEI_DISPATCH_NOTIFY_LIST  *DispatchNotifyListPointer;
+  UINTN                     DispatchNotifyIndex;
+  UINTN                     LastDispatchNotifyCount;
+
+  if (NotifyList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+  CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
+  CallbackNotifyIndex       = CallbackNotifyListPointer->CurrentCount;
+  LastCallbackNotifyCount   = CallbackNotifyIndex;
+
+  DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
+  DispatchNotifyIndex       = DispatchNotifyListPointer->CurrentCount;
+  LastDispatchNotifyCount   = DispatchNotifyIndex;
+
+  //
+  // 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 ( ; ;) {
+    //
+    // If some of the PPI data is invalid restore original Notify PPI database value
+    //
+    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
+      CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
+      DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
+      DEBUG ((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
+      if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
+        //
+        // Run out of room, assert.
+        //
+        ASSERT (CallbackNotifyIndex < CallbackNotifyListPointer->MaxCount);
+      }
+
+      CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
+      CallbackNotifyIndex++;
+      CallbackNotifyListPointer->CurrentCount++;
+    } else {
+      ASSERT ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0);
+    }
+
+    DEBUG ((DEBUG_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
+
+    if (Single) {
+      //
+      // Only single entry in the NotifyList.
+      //
+      break;
+    } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+               EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
+    {
+      //
+      // Continue until the end of the Notify List.
+      //
+      break;
+    }
+
+    //
+    // Go to the next descriptor.
+    //
+    NotifyList++;
+  }
+
+  //
+  // Process any callback level notifies for all previously installed PPIs.
+  //
+  ProcessNotify (
+    PrivateData,
+    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+    0,
+    PrivateData->PpiData.PpiList.CurrentCount,
+    LastCallbackNotifyCount,
+    CallbackNotifyListPointer->CurrentCount
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This function installs a notification service to be called back when a given
+  interface is installed or reinstalled. The purpose of the service is to publish
+  an interface that other parties can use to call additional PPIs that may materialize later.
+
+  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+  @param NotifyList         Pointer to list of Descriptors to notify upon.
+
+  @retval EFI_SUCCESS           if successful
+  @retval EFI_OUT_OF_RESOURCES  if no space in the database
+  @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestNotifyPpi (
+  IN CONST EFI_PEI_SERVICES           **PeiServices,
+  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
+  )
+{
+  return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
+}
+
+/**
+
+  Process 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
+ProcessNotify (
+  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;
+
+  for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
+    if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
+      NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
+    } else {
+      NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
+    }
+
+    CheckGuid = NotifyDescriptor->Guid;
+
+    for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
+      SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[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 ((
+          DEBUG_INFO,
+          "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
+          SearchGuid,
+          NotifyDescriptor->Notify
+          ));
+        NotifyDescriptor->Notify (
+                            (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
+                            NotifyDescriptor,
+                            (PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
+                            );
+      }
+    }
+  }
+}
diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc
index a76e31d97d..872d9c0d8c 100644
--- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc
+++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc
@@ -35,6 +35,7 @@
   UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf
   UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf
   UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLib.inf
+  UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
 
   UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf
   UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf
diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
index 7866c36e66..5217de31e4 100644
--- a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
+++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
@@ -21,6 +21,7 @@
   DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
   MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
   UefiBootServicesTableLib|UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLib.inf
+  PeiServicesTablePointerLib|UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
 
 [BuildOptions]
   GCC:*_*_*_CC_FLAGS = -fno-pie
-- 
2.31.1.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [edk2-devel] [PATCH] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib
  2023-06-01  3:02 [PATCH] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib Zhiguang Liu
@ 2023-06-05  3:26 ` Ni, Ray
  0 siblings, 0 replies; 2+ messages in thread
From: Ni, Ray @ 2023-06-05  3:26 UTC (permalink / raw)
  To: devel@edk2.groups.io, Liu, Zhiguang
  Cc: Kinney, Michael D, Michael Kubacki, Sean Brogan

> +/**
> +  Allocate Buffer Or Clear Buffer For Global Data.
> +**/
> +VOID
> +AllocateBufferOrClearBufferForGlobalData (
> +  VOID
> +  )
> +{
> +  ZeroMem (&mPrivateData, sizeof (mPrivateData));
> +  if (!PSInitDone) {

1. "PSInitDone" doesn't follow edk2 coding style.


> +    mHobBuffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_HOB_SIZE));

2. If the size to allocate is fixed, can you just declare in global variable instead of allocating?

3. Can you evaluate all the allocations and try to avoid them? This helps to remove the dep on MemoryAllocationLib.

3. "CallbackNotifyList" is not initialized. 

Thanks,
Ray

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-06-05  3:26 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-01  3:02 [PATCH] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib Zhiguang Liu
2023-06-05  3:26 ` [edk2-devel] " Ni, Ray

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox