It looks like you're following a similar pattern to a library instance already in UnitTestFrameworkPkg/Library like UnitTestUefiBootServicesTableLib. I can't find where these types of libraries are explicitly called out in the UnitTestFrameworkPkg/ReadMe.md file [1]. You don't need to add it in this patch, but we might want to explain these in the readme (unless I just missed it).

They are not really a pure mock since they have a self-contained functional implementation of some structures typically in core modules like the PPI and HOB lists. They might also have more code outside the unit being tested than is ideal in a unit test, but they are useful for code that has dependencies in global databases.

[1] - https://github.com/tianocore/edk2/blob/master/UnitTestFrameworkPkg/ReadMe.md#unit-test-locationlayout-rules

There's some code I think is unnecessary in a unit test implementation like surrounding this NULL pointer check with debug code markers in UnitTestGetHobList():

  DEBUG_CODE_BEGIN ();
  if (HobList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG_CODE_END ();

Can you please simply check if the pointer is NULL?

Reviewed-by: Michael Kubacki <michael.kuba...@microsoft.com>

On 6/6/2023 1:40 AM, Zhiguang Liu wrote:
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.kin...@intel.com>
Cc: Michael Kubacki <mikub...@linux.microsoft.com>
Cc: Sean Brogan <sean.bro...@microsoft.com>
Signed-off-by: Zhiguang Liu <zhiguang....@intel.com>
---
  .../UnitTestPeiServicesTablePointerLib.c      | 187 +++++
  .../UnitTestPeiServicesTablePointerLib.h      | 653 ++++++++++++++++++
  .../UnitTestPeiServicesTablePointerLib.inf    |  37 +
  .../UnitTestPeiServicesTablePointerLib.uni    |  12 +
  .../UnitTestPeiServicesTablePointerLibHob.c   | 162 +++++
  .../UnitTestPeiServicesTablePointerLibMisc.c  | 430 ++++++++++++
  .../UnitTestPeiServicesTablePointerLibPpi.c   | 485 +++++++++++++
  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc |   1 +
  .../UnitTestFrameworkPkgHost.dsc.inc          |   1 +
  9 files changed, 1968 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..a1b982fbae
--- /dev/null
+++ 
b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.c
@@ -0,0 +1,187 @@
+/** @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"
+
+///
+/// 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
+};
+
+PEI_CORE_INSTANCE  mPrivateData;
+UINT8              mHobBuffer[MAX_HOB_SIZE];
+VOID               *mPeiServicesPointer;
+
+/**
+  Clear Buffer For Global Data.
+**/
+VOID
+ClearGlobalData (
+  VOID
+  )
+{
+  ZeroMem (&mPrivateData, sizeof (mPrivateData));
+  mPrivateData.PpiData.PpiList.MaxCount            = MAX_PPI_COUNT;
+  mPrivateData.PpiData.CallbackNotifyList.MaxCount = MAX_PPI_COUNT;
+  mPrivateData.PpiData.DispatchNotifyList.MaxCount = MAX_PPI_COUNT;
+
+  ZeroMem (mHobBuffer, MAX_HOB_SIZE);
+  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
+  )
+{
+  ClearGlobalData ();
+}
+
+/**
+  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
+  )
+{
+  mPeiServicesPointer = &mPeiServices;
+  return (CONST EFI_PEI_SERVICES **)&mPeiServicesPointer;
+}
+
+/**
+  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.
+
+  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+UnitTestPeiServicesTablePointerLibConstructor (
+  VOID
+  )
+{
+  ClearGlobalData ();
+  return EFI_SUCCESS;
+}
diff --git 
a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
 
b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
new file mode 100644
index 0000000000..e411d08a86
--- /dev/null
+++ 
b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.h
@@ -0,0 +1,653 @@
+/** @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/UnitTestLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Uefi.h>
+
+#define MAX_PPI_COUNT  100
+#define MAX_HOB_SIZE   SIZE_32MB
+
+///
+/// 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;
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  UINTN                    LastDispatchedCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    PpiPtrs[MAX_PPI_COUNT];
+} PEI_PPI_LIST;
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    NotifyPtrs[MAX_PPI_COUNT];
+} PEI_CALLBACK_NOTIFY_LIST;
+
+typedef struct {
+  UINTN                    CurrentCount;
+  UINTN                    MaxCount;
+  UINTN                    LastDispatchedCount;
+  ///
+  /// MaxCount number of entries.
+  ///
+  PEI_PPI_LIST_POINTERS    NotifyPtrs[MAX_PPI_COUNT];
+} 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..59d86c9db8
--- /dev/null
+++ 
b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
@@ -0,0 +1,37 @@
+## @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                    = BASE
+  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
+  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


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105805): https://edk2.groups.io/g/devel/message/105805
Mute This Topic: https://groups.io/mt/99357915/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to