public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ni, Ray" <ray.ni@intel.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
	"Liu, Zhiguang" <zhiguang.liu@intel.com>
Cc: "Kinney, Michael D" <michael.d.kinney@intel.com>,
	Michael Kubacki <mikuback@linux.microsoft.com>,
	Sean Brogan <sean.brogan@microsoft.com>
Subject: Re: [edk2-devel] [PATCH v2] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib
Date: Tue, 6 Jun 2023 05:47:45 +0000	[thread overview]
Message-ID: <MN6PR11MB8244589789C5C6BFF1F9463C8C52A@MN6PR11MB8244.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20230606054001.1289-1-zhiguang.liu@intel.com>

Reviewed-by: Ray Ni <ray.ni@intel.com>

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Zhiguang Liu
> Sent: Tuesday, June 6, 2023 1:40 PM
> To: devel@edk2.groups.io
> Cc: Liu, Zhiguang <zhiguang.liu@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Michael Kubacki
> <mikuback@linux.microsoft.com>; Sean Brogan <sean.brogan@microsoft.com>
> Subject: [edk2-devel] [PATCH v2] UnitTestFrameworkPkg: Add
> UnitTestPeiServicesTablePointerLib
> 
> 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      | 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/UnitTestPeiS
> ervicesTablePointerLib.c
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLib.h
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLib.inf
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLib.uni
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLibHob.c
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLibMisc.c
>  create mode 100644
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLibPpi.c
> 
> diff --git
> a/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.c
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.c
> new file mode 100644
> index 0000000000..a1b982fbae
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.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/UnitTestPe
> iServicesTablePointerLib.h
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.h
> new file mode 100644
> index 0000000000..e411d08a86
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.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/UnitTestPe
> iServicesTablePointerLib.inf
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.inf
> new file mode 100644
> index 0000000000..59d86c9db8
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.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/UnitTestPe
> iServicesTablePointerLib.uni
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.uni
> new file mode 100644
> index 0000000000..ca2118533a
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLib.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/UnitTestPe
> iServicesTablePointerLibHob.c
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibHob.c
> new file mode 100644
> index 0000000000..2d4ffe8c59
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibHob.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/UnitTestPe
> iServicesTablePointerLibMisc.c
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibMisc.c
> new file mode 100644
> index 0000000000..90955bf482
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibMisc.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/UnitTestPe
> iServicesTablePointerLibPpi.c
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibPpi.c
> new file mode 100644
> index 0000000000..09f4094dad
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPe
> iServicesTablePointerLibPpi.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/UnitTest
> PersistenceLibSimpleFileSystem.inf
> 
> UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.
> inf
> 
> UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiB
> ootServicesTableLib.inf
> +
> UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiS
> ervicesTablePointerLib.inf
> 
> 
> UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestD
> xe.inf
> 
> UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestP
> ei.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.in
> f
> 
> MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLib
> Posix/MemoryAllocationLibPosix.inf
> 
> UefiBootServicesTableLib|UnitTestFrameworkPkg/Library/UnitTestUefiBootServi
> cesTableLib/UnitTestUefiBootServicesTableLib.inf
> +
> PeiServicesTablePointerLib|UnitTestFrameworkPkg/Library/UnitTestPeiServicesT
> ablePointerLib/UnitTestPeiServicesTablePointerLib.inf
> 
>  [BuildOptions]
>    GCC:*_*_*_CC_FLAGS = -fno-pie
> --
> 2.31.1.windows.1
> 
> 
> 
> 
> 


  reply	other threads:[~2023-06-06  5:48 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-06  5:40 [PATCH v2] UnitTestFrameworkPkg: Add UnitTestPeiServicesTablePointerLib Zhiguang Liu
2023-06-06  5:47 ` Ni, Ray [this message]
2023-06-06 15:28 ` [edk2-devel] " Michael Kubacki
2023-06-12  5:07   ` Zhiguang Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=MN6PR11MB8244589789C5C6BFF1F9463C8C52A@MN6PR11MB8244.namprd11.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox