[edk2-devel] [Patch v2 08/28] MdeModulePkg: Add new Variable functionality

Judah Vang posted 28 patches 1 month, 3 weeks ago
[edk2-devel] [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
Posted by Judah Vang 1 month, 3 weeks ago
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594

Provide new APIs for retrieving variable information.
Add new function stubs for retrieving Protected
variable information.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 MdeModulePkg/Universal/Variable/Pei/VariablePei.inf   |  10 +-
 MdeModulePkg/Universal/Variable/Pei/Variable.h        |  80 +-
 MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++++++
 MdeModulePkg/Universal/Variable/Pei/VariableStore.h   | 116 +++
 MdeModulePkg/Universal/Variable/Pei/Variable.c        | 886 +++---------------
 MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 ++++++++++++++++++++
 MdeModulePkg/Universal/Variable/Pei/VariableStore.c   | 305 +++++++
 7 files changed, 1891 insertions(+), 756 deletions(-)

diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
index 7cbdd2385e8f..af172126a011 100644
--- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
+++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -3,7 +3,7 @@
 #
 #  This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
 #
-#  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -26,6 +26,10 @@ [Defines]
 [Sources]
   Variable.c
   Variable.h
+  VariableStore.c
+  VariableStore.h
+  VariableParsing.c
+  VariableParsing.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -39,6 +43,7 @@ [LibraryClasses]
   DebugLib
   PeiServicesTablePointerLib
   PeiServicesLib
+  ProtectedVariableLib
 
 [Guids]
   ## CONSUMES             ## GUID # Variable store header
@@ -56,7 +61,8 @@ [Guids]
   gEdkiiFaultTolerantWriteGuid
 
 [Ppis]
-  gEfiPeiReadOnlyVariable2PpiGuid   ## PRODUCES
+  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
+  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase      ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h
index 7f9ad5bfc357..115426edd626 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.h
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -2,7 +2,7 @@
   The internal header file includes the common header files, defines
   internal structure and functions used by PeiVariable module.
 
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -20,11 +20,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Library/BaseMemoryLib.h>
 #include <Library/PeiServicesTablePointerLib.h>
 #include <Library/PeiServicesLib.h>
+#include <Library/ProtectedVariableLib.h>
 
 #include <Guid/VariableFormat.h>
 #include <Guid/VariableIndexTable.h>
 #include <Guid/SystemNvDataGuid.h>
 #include <Guid/FaultTolerantWrite.h>
+#include <Guid/ProtectedVariable.h>
 
 typedef enum {
   VariableStoreTypeHob,
@@ -142,4 +144,80 @@ PeiGetNextVariableName (
   IN OUT EFI_GUID                            *VariableGuid
   );
 
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  );
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+
+  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  );
+
 #endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
new file mode 100644
index 000000000000..d7af6cb6e8be
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
@@ -0,0 +1,309 @@
+/** @file
+  The internal header file includes the common header files, defines
+  internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_PARSING_H_
+#define PEI_VARIABLE_PARSING_H_
+
+#include "Variable.h"
+
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+  This code checks if variable header is valid or not.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+
+  @retval TRUE      Variable header is valid.
+  @retval FALSE     Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable
+  );
+
+/**
+  This code gets the pointer to the next variable header.
+
+  @param[in]  StoreInfo         Pointer to variable store info structure.
+  @param[in]  Variable          Pointer to the Variable Header.
+  @param[in]  VariableHeader    Pointer to the Variable Header that has consecutive content.
+
+  @return  A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_STORE_INFO  *StoreInfo,
+  IN  VARIABLE_HEADER      *Variable,
+  IN  VARIABLE_HEADER      *VariableHeader
+  );
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in]  Variable   Pointer to the Variable Header.
+  @param[in]  AuthFlag   Authenticated variable flag.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the pointer to the variable name.
+
+  @param[in]   Variable  Pointer to the Variable Header.
+  @param[in]   AuthFlag  Authenticated variable flag.
+
+  @return  A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the size of name of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the size of data of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the pointer to the variable data.
+
+  @param[in]   Variable         Pointer to the Variable Header.
+  @param[in]   VariableHeader   Pointer to the Variable Header that has consecutive content.
+  @param[in]   AuthFlag         Authenticated variable flag.
+
+  @return  A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableHeader,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  Get variable header that has consecutive content.
+
+  @param[in]  StoreInfo      Pointer to variable store info structure.
+  @param[in]  Variable       Pointer to the Variable Header.
+  @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+  @retval TRUE          Variable header is valid.
+  @retval FALSE         Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN VARIABLE_HEADER      *Variable,
+  OUT VARIABLE_HEADER     **VariableHeader
+  );
+
+/**
+  This code gets the size of variable header.
+
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFlag
+  );
+
+/**
+  Get variable name or data to output buffer.
+
+  @param[in]  StoreInfo     Pointer to variable store info structure.
+  @param[in]  NameOrData    Pointer to the variable name/data that may be inconsecutive.
+  @param[in]  Size          Variable name/data size.
+  @param[out] Buffer        Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN UINT8                *NameOrData,
+  IN UINTN                Size,
+  OUT UINT8               *Buffer
+  );
+
+/**
+  This function compares a variable with variable entries in database.
+
+  @param[in]  StoreInfo     Pointer to variable store info structure.
+  @param[in]  Variable      Pointer to the variable in our database
+  @param[in]  VariableHeader Pointer to the Variable Header that has consecutive content.
+  @param[in]  VariableName  Name of the variable to compare to 'Variable'
+  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
+  @param[out] PtrTrack      Variable Track Pointer structure that contains Variable Information.
+
+  @retval EFI_SUCCESS    Found match variable
+  @retval EFI_NOT_FOUND  Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+  IN  VARIABLE_STORE_INFO     *StoreInfo,
+  IN  VARIABLE_HEADER         *Variable,
+  IN  VARIABLE_HEADER         *VariableHeader,
+  IN  CONST CHAR16            *VariableName,
+  IN  CONST EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  );
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+  VariableStart and/or VariableEnd can be given optionally for the situation
+  in which the valid storage space is smaller than the VariableStore->Size.
+  This usually happens when PEI variable services make a compact variable
+  cache to save memory, which cannot make use VariableStore->Size to determine
+  the correct variable storage range.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
+  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
+  @retval EFI_SUCCESS            The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
+  );
+
+/**
+
+  Retrieve details about a variable and return them in VariableInfo->Header.
+
+  If VariableInfo->Address is given, this function will calculate its offset
+  relative to given variable storage via VariableStore; Otherwise, it will try
+  other internal variable storages or cached copies. It's assumed that, for all
+  copies of NV variable storage, all variables are stored in the same relative
+  position. If VariableInfo->Address is found in the range of any storage copies,
+  its offset relative to that storage should be the same in other copies.
+
+  If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+  this function will return the variable memory address inside VariableStore,
+  if given, via VariableInfo->Address; Otherwise, the address of other storage
+  copies will be returned, if any.
+
+  For a new variable whose offset has not been determined, a value of -1 as
+  VariableInfo->Offset should be passed to skip the offset calculation.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Address
+                                 and VariableInfo->Offset are NULL (0).
+  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
+                                 any given or internal storage copies.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
+  );
+
+/**
+
+  Find variable specified with input parameters.
+
+  @param[in] StoreInfo             Pointer to variable information.
+  @param[in] VariableName          Pointer to variable name.
+  @param[in] VendorGuid            Pointer to variable GUID.
+  @param[in] PtrTrack              Pointer to variable track.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Address
+                                 and VariableInfo->Offset are NULL (0).
+  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
+                                 any given or internal storage copies.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+FindVariableEx (
+  IN VARIABLE_STORE_INFO      *StoreInfo,
+  IN CONST CHAR16             *VariableName,
+  IN CONST EFI_GUID           *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
new file mode 100644
index 000000000000..6e2f6f939bab
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
@@ -0,0 +1,116 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_STORE_H_
+#define PEI_VARIABLE_STORE_H_
+
+/**
+  Get variable store status.
+
+  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval  EfiRaw      Variable store is raw
+  @retval  EfiValid    Variable store is valid
+  @retval  EfiInvalid  Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+  Reports HOB variable store is available or not.
+
+  @retval EFI_NOT_READY  HOB variable store info not available.
+  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
+  @retval EFI_SUCCESS    HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+  VOID
+  );
+
+/**
+  Get HOB variable store.
+
+  @param[out] StoreInfo             Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  );
+
+/**
+  Get NV variable store.
+
+  @param[out] StoreInfo             Return the store info.
+  @param[out] VariableStoreHeader   Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+  OUT VARIABLE_STORE_INFO         *StoreInfo,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
+  );
+
+/**
+  Return the variable store header and the store info based on the Index.
+
+  @param[in]  Type       The type of the variable store.
+  @param[out] StoreInfo  Return the store info.
+
+  @return  Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+  IN VARIABLE_STORE_TYPE   Type,
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  );
+
+/**
+  Make a cached copy of NV variable storage.
+
+  To save memory in PEI phase, only valid variables are copied into cache.
+  An IndexTable could be used to store the offset (relative to NV storage
+  base) of each copied variable, in case we need to restore the storage
+  as the same (valid) variables layout as in original one.
+
+  Variables with valid format and following state can be taken as valid:
+    - with state VAR_ADDED;
+    - with state VAR_IN_DELETED_TRANSITION but without the same variable
+      with state VAR_ADDED;
+    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
+      MetaDataHmacVar.
+
+  @param[out]     StoreCacheBase    Base address of variable storage cache.
+  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
+  @param[out]     IndexTable        Buffer of index (offset) table with entries of
+                                    VariableNumber.
+  @param[out]     VariableNumber    Number of valid variables.
+  @param[out]     AuthFlag          Aut-variable indicator.
+
+  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or StoreCacheBase.
+  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
+  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
+  @return EFI_SUCCESS           NV variable storage is cached successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitNvVariableStore (
+  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
+  IN OUT  UINT32             *StoreCacheSize,
+  OUT  UINT32                *IndexTable OPTIONAL,
+  OUT  UINT32                *VariableNumber OPTIONAL,
+  OUT  BOOLEAN               *AuthFlag OPTIONAL
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c
index b36dd0de67b2..ce790946626e 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -2,20 +2,22 @@
   Implement ReadOnly Variable Services required by PEIM and install
   PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
 
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
 Copyright (c) Microsoft Corporation.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
 #include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableStore.h"
 
 //
 // Module globals
 //
 EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
-  PeiGetVariable,
-  PeiGetNextVariableName
+  PeiGetVariableEx,
+  PeiGetNextVariableNameEx
 };
 
 EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
@@ -41,759 +43,33 @@ PeimInitializeVariableServices (
   IN CONST EFI_PEI_SERVICES     **PeiServices
   )
 {
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
+
+  //
+  // If protected variable services are not supported, EFI_UNSUPPORTED should
+  // be always returned. Check it here.
+  //
+  ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+  ContextIn.StructSize    = sizeof (ContextIn);
+
+  ContextIn.MaxVariableSize             = 0;
+  ContextIn.VariableServiceUser         = FromPeiModule;
+  ContextIn.GetVariableInfo             = GetVariableInfo;
+  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
+  ContextIn.FindVariableSmm             = NULL;
+  ContextIn.UpdateVariableStore         = NULL;
+  ContextIn.UpdateVariable              = NULL;
+  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
+
+  Status = ProtectedVariableLibInitialize (&ContextIn);
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    return Status;
+  }
+
   return PeiServicesInstallPpi (&mPpiListVariable);
 }
 
-/**
-
-  Gets the pointer to the first variable header in given variable store area.
-
-  @param VarStoreHeader  Pointer to the Variable Store Header.
-
-  @return Pointer to the first variable header.
-
-**/
-VARIABLE_HEADER *
-GetStartPointer (
-  IN VARIABLE_STORE_HEADER  *VarStoreHeader
-  )
-{
-  //
-  // The start of variable store
-  //
-  return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
-}
-
-/**
-
-  Gets the pointer to the end of the variable storage area.
-
-  This function gets pointer to the end of the variable storage
-  area, according to the input variable store header.
-
-  @param VarStoreHeader  Pointer to the Variable Store Header.
-
-  @return Pointer to the end of the variable storage area.
-
-**/
-VARIABLE_HEADER *
-GetEndPointer (
-  IN VARIABLE_STORE_HEADER  *VarStoreHeader
-  )
-{
-  //
-  // The end of variable store
-  //
-  return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
-}
-
-/**
-  This code checks if variable header is valid or not.
-
-  @param  Variable  Pointer to the Variable Header.
-
-  @retval TRUE      Variable header is valid.
-  @retval FALSE     Variable header is not valid.
-
-**/
-BOOLEAN
-IsValidVariableHeader (
-  IN  VARIABLE_HEADER  *Variable
-  )
-{
-  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/**
-  This code gets the size of variable header.
-
-  @param AuthFlag   Authenticated variable flag.
-
-  @return Size of variable header in bytes in type UINTN.
-
-**/
-UINTN
-GetVariableHeaderSize (
-  IN  BOOLEAN  AuthFlag
-  )
-{
-  UINTN  Value;
-
-  if (AuthFlag) {
-    Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
-  } else {
-    Value = sizeof (VARIABLE_HEADER);
-  }
-
-  return Value;
-}
-
-/**
-  This code gets the size of name of variable.
-
-  @param  Variable  Pointer to the Variable Header.
-  @param  AuthFlag  Authenticated variable flag.
-
-  @return Size of variable in bytes in type UINTN.
-
-**/
-UINTN
-NameSizeOfVariable (
-  IN  VARIABLE_HEADER  *Variable,
-  IN  BOOLEAN          AuthFlag
-  )
-{
-  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
-
-  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
-  if (AuthFlag) {
-    if ((AuthVariable->State == (UINT8)(-1)) ||
-        (AuthVariable->DataSize == (UINT32)(-1)) ||
-        (AuthVariable->NameSize == (UINT32)(-1)) ||
-        (AuthVariable->Attributes == (UINT32)(-1)))
-    {
-      return 0;
-    }
-
-    return (UINTN)AuthVariable->NameSize;
-  } else {
-    if ((Variable->State == (UINT8)(-1)) ||
-        (Variable->DataSize == (UINT32)(-1)) ||
-        (Variable->NameSize == (UINT32)(-1)) ||
-        (Variable->Attributes == (UINT32)(-1)))
-    {
-      return 0;
-    }
-
-    return (UINTN)Variable->NameSize;
-  }
-}
-
-/**
-  This code gets the size of data of variable.
-
-  @param  Variable  Pointer to the Variable Header.
-  @param  AuthFlag  Authenticated variable flag.
-
-  @return Size of variable in bytes in type UINTN.
-
-**/
-UINTN
-DataSizeOfVariable (
-  IN  VARIABLE_HEADER  *Variable,
-  IN  BOOLEAN          AuthFlag
-  )
-{
-  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
-
-  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
-  if (AuthFlag) {
-    if ((AuthVariable->State == (UINT8)(-1)) ||
-        (AuthVariable->DataSize == (UINT32)(-1)) ||
-        (AuthVariable->NameSize == (UINT32)(-1)) ||
-        (AuthVariable->Attributes == (UINT32)(-1)))
-    {
-      return 0;
-    }
-
-    return (UINTN)AuthVariable->DataSize;
-  } else {
-    if ((Variable->State == (UINT8)(-1)) ||
-        (Variable->DataSize == (UINT32)(-1)) ||
-        (Variable->NameSize == (UINT32)(-1)) ||
-        (Variable->Attributes == (UINT32)(-1)))
-    {
-      return 0;
-    }
-
-    return (UINTN)Variable->DataSize;
-  }
-}
-
-/**
-  This code gets the pointer to the variable name.
-
-  @param   Variable  Pointer to the Variable Header.
-  @param   AuthFlag  Authenticated variable flag.
-
-  @return  A CHAR16* pointer to Variable Name.
-
-**/
-CHAR16 *
-GetVariableNamePtr (
-  IN VARIABLE_HEADER  *Variable,
-  IN BOOLEAN          AuthFlag
-  )
-{
-  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
-}
-
-/**
-  This code gets the pointer to the variable guid.
-
-  @param Variable   Pointer to the Variable Header.
-  @param AuthFlag   Authenticated variable flag.
-
-  @return A EFI_GUID* pointer to Vendor Guid.
-
-**/
-EFI_GUID *
-GetVendorGuidPtr (
-  IN VARIABLE_HEADER  *Variable,
-  IN BOOLEAN          AuthFlag
-  )
-{
-  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
-
-  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
-  if (AuthFlag) {
-    return &AuthVariable->VendorGuid;
-  } else {
-    return &Variable->VendorGuid;
-  }
-}
-
-/**
-  This code gets the pointer to the variable data.
-
-  @param   Variable         Pointer to the Variable Header.
-  @param   VariableHeader   Pointer to the Variable Header that has consecutive content.
-  @param   AuthFlag         Authenticated variable flag.
-
-  @return  A UINT8* pointer to Variable Data.
-
-**/
-UINT8 *
-GetVariableDataPtr (
-  IN  VARIABLE_HEADER  *Variable,
-  IN  VARIABLE_HEADER  *VariableHeader,
-  IN  BOOLEAN          AuthFlag
-  )
-{
-  UINTN  Value;
-
-  //
-  // Be careful about pad size for alignment
-  //
-  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
-  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
-  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
-
-  return (UINT8 *)Value;
-}
-
-/**
-  This code gets the pointer to the next variable header.
-
-  @param  StoreInfo         Pointer to variable store info structure.
-  @param  Variable          Pointer to the Variable Header.
-  @param  VariableHeader    Pointer to the Variable Header that has consecutive content.
-
-  @return  A VARIABLE_HEADER* pointer to next variable header.
-
-**/
-VARIABLE_HEADER *
-GetNextVariablePtr (
-  IN  VARIABLE_STORE_INFO  *StoreInfo,
-  IN  VARIABLE_HEADER      *Variable,
-  IN  VARIABLE_HEADER      *VariableHeader
-  )
-{
-  EFI_PHYSICAL_ADDRESS  TargetAddress;
-  EFI_PHYSICAL_ADDRESS  SpareAddress;
-  UINTN                 Value;
-
-  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
-  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
-  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
-  //
-  // Be careful about pad size for alignment
-  //
-  Value = HEADER_ALIGN (Value);
-
-  if (StoreInfo->FtwLastWriteData != NULL) {
-    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
-    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
-    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
-      //
-      // Next variable is in spare block.
-      //
-      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
-    }
-  }
-
-  return (VARIABLE_HEADER *)Value;
-}
-
-/**
-  Get variable store status.
-
-  @param  VarStoreHeader  Pointer to the Variable Store Header.
-
-  @retval  EfiRaw      Variable store is raw
-  @retval  EfiValid    Variable store is valid
-  @retval  EfiInvalid  Variable store is invalid
-
-**/
-VARIABLE_STORE_STATUS
-GetVariableStoreStatus (
-  IN VARIABLE_STORE_HEADER  *VarStoreHeader
-  )
-{
-  if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
-       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
-      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
-      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
-      )
-  {
-    return EfiValid;
-  }
-
-  if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
-      (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
-      (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
-      (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
-      (VarStoreHeader->Size == 0xffffffff) &&
-      (VarStoreHeader->Format == 0xff) &&
-      (VarStoreHeader->State == 0xff)
-      )
-  {
-    return EfiRaw;
-  } else {
-    return EfiInvalid;
-  }
-}
-
-/**
-  Compare two variable names, one of them may be inconsecutive.
-
-  @param StoreInfo      Pointer to variable store info structure.
-  @param Name1          Pointer to one variable name.
-  @param Name2          Pointer to another variable name.
-  @param NameSize       Variable name size.
-
-  @retval TRUE          Name1 and Name2 are identical.
-  @retval FALSE         Name1 and Name2 are not identical.
-
-**/
-BOOLEAN
-CompareVariableName (
-  IN VARIABLE_STORE_INFO  *StoreInfo,
-  IN CONST CHAR16         *Name1,
-  IN CONST CHAR16         *Name2,
-  IN UINTN                NameSize
-  )
-{
-  EFI_PHYSICAL_ADDRESS  TargetAddress;
-  EFI_PHYSICAL_ADDRESS  SpareAddress;
-  UINTN                 PartialNameSize;
-
-  if (StoreInfo->FtwLastWriteData != NULL) {
-    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
-    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
-    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
-      //
-      // Name1 is inconsecutive.
-      //
-      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
-      //
-      // Partial content is in NV storage.
-      //
-      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
-        //
-        // Another partial content is in spare block.
-        //
-        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
-          return TRUE;
-        }
-      }
-
-      return FALSE;
-    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
-      //
-      // Name2 is inconsecutive.
-      //
-      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
-      //
-      // Partial content is in NV storage.
-      //
-      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
-        //
-        // Another partial content is in spare block.
-        //
-        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
-          return TRUE;
-        }
-      }
-
-      return FALSE;
-    }
-  }
-
-  //
-  // Both Name1 and Name2 are consecutive.
-  //
-  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  This function compares a variable with variable entries in database.
-
-  @param  StoreInfo     Pointer to variable store info structure.
-  @param  Variable      Pointer to the variable in our database
-  @param  VariableHeader Pointer to the Variable Header that has consecutive content.
-  @param  VariableName  Name of the variable to compare to 'Variable'
-  @param  VendorGuid    GUID of the variable to compare to 'Variable'
-  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.
-
-  @retval EFI_SUCCESS    Found match variable
-  @retval EFI_NOT_FOUND  Variable not found
-
-**/
-EFI_STATUS
-CompareWithValidVariable (
-  IN  VARIABLE_STORE_INFO     *StoreInfo,
-  IN  VARIABLE_HEADER         *Variable,
-  IN  VARIABLE_HEADER         *VariableHeader,
-  IN  CONST CHAR16            *VariableName,
-  IN  CONST EFI_GUID          *VendorGuid,
-  OUT VARIABLE_POINTER_TRACK  *PtrTrack
-  )
-{
-  VOID      *Point;
-  EFI_GUID  *TempVendorGuid;
-
-  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
-
-  if (VariableName[0] == 0) {
-    PtrTrack->CurrPtr = Variable;
-    return EFI_SUCCESS;
-  } else {
-    //
-    // Don't use CompareGuid function here for performance reasons.
-    // Instead we compare the GUID a UINT32 at a time and branch
-    // on the first failed comparison.
-    //
-    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
-        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
-        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
-        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
-        )
-    {
-      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
-      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
-      if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
-        PtrTrack->CurrPtr = Variable;
-        return EFI_SUCCESS;
-      }
-    }
-  }
-
-  return EFI_NOT_FOUND;
-}
-
-/**
-  Get HOB variable store.
-
-  @param[out] StoreInfo             Return the store info.
-  @param[out] VariableStoreHeader   Return variable store header.
-
-**/
-VOID
-GetHobVariableStore (
-  OUT VARIABLE_STORE_INFO    *StoreInfo,
-  OUT VARIABLE_STORE_HEADER  **VariableStoreHeader
-  )
-{
-  EFI_HOB_GUID_TYPE  *GuidHob;
-
-  //
-  // Make sure there is no more than one Variable HOB.
-  //
-  DEBUG_CODE_BEGIN ();
-  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
-  if (GuidHob != NULL) {
-    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
-      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
-      ASSERT (FALSE);
-    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
-      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
-      ASSERT (FALSE);
-    }
-  } else {
-    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
-    if (GuidHob != NULL) {
-      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
-        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
-        ASSERT (FALSE);
-      }
-    }
-  }
-
-  DEBUG_CODE_END ();
-
-  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
-  if (GuidHob != NULL) {
-    *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
-    StoreInfo->AuthFlag  = TRUE;
-  } else {
-    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
-    if (GuidHob != NULL) {
-      *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
-      StoreInfo->AuthFlag  = FALSE;
-    }
-  }
-}
-
-/**
-  Return the variable store header and the store info based on the Index.
-
-  @param Type       The type of the variable store.
-  @param StoreInfo  Return the store info.
-
-  @return  Pointer to the variable store header.
-**/
-VARIABLE_STORE_HEADER *
-GetVariableStore (
-  IN VARIABLE_STORE_TYPE   Type,
-  OUT VARIABLE_STORE_INFO  *StoreInfo
-  )
-{
-  EFI_HOB_GUID_TYPE                     *GuidHob;
-  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
-  VARIABLE_STORE_HEADER                 *VariableStoreHeader;
-  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
-  UINT32                                NvStorageSize;
-  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
-  UINT32                                BackUpOffset;
-
-  StoreInfo->IndexTable       = NULL;
-  StoreInfo->FtwLastWriteData = NULL;
-  StoreInfo->AuthFlag         = FALSE;
-  VariableStoreHeader         = NULL;
-  switch (Type) {
-    case VariableStoreTypeHob:
-      GetHobVariableStore (StoreInfo, &VariableStoreHeader);
-
-      break;
-
-    case VariableStoreTypeNv:
-      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
-        //
-        // Emulated non-volatile variable mode is not enabled.
-        //
-
-        NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
-        NvStorageBase = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
-                                               PcdGet64 (PcdFlashNvStorageVariableBase64) :
-                                               PcdGet32 (PcdFlashNvStorageVariableBase)
-                                               );
-        ASSERT (NvStorageBase != 0);
-
-        //
-        // First let FvHeader point to NV storage base.
-        //
-        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
-
-        //
-        // Check the FTW last write data hob.
-        //
-        BackUpOffset = 0;
-        GuidHob      = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
-        if (GuidHob != NULL) {
-          FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
-          if (FtwLastWriteData->TargetAddress == NvStorageBase) {
-            //
-            // Let FvHeader point to spare block.
-            //
-            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FtwLastWriteData->SpareAddress;
-            DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
-          } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
-            StoreInfo->FtwLastWriteData = FtwLastWriteData;
-            //
-            // Flash NV storage from the offset is backed up in spare block.
-            //
-            BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);
-            DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress));
-            //
-            // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
-            //
-          }
-        }
-
-        //
-        // Check if the Firmware Volume is not corrupted
-        //
-        if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
-          DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
-          break;
-        }
-
-        VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);
-
-        StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));
-
-        GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
-        if (GuidHob != NULL) {
-          StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
-        } else {
-          //
-          // If it's the first time to access variable region in flash, create a guid hob to record
-          // VAR_ADDED type variable info.
-          // Note that as the resource of PEI phase is limited, only store the limited number of
-          // VAR_ADDED type variables to reduce access time.
-          //
-          StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
-          StoreInfo->IndexTable->Length      = 0;
-          StoreInfo->IndexTable->StartPtr    = GetStartPointer (VariableStoreHeader);
-          StoreInfo->IndexTable->EndPtr      = GetEndPointer (VariableStoreHeader);
-          StoreInfo->IndexTable->GoneThrough = 0;
-        }
-      }
-
-      break;
-
-    default:
-      ASSERT (FALSE);
-      break;
-  }
-
-  StoreInfo->VariableStoreHeader = VariableStoreHeader;
-  return VariableStoreHeader;
-}
-
-/**
-  Get variable header that has consecutive content.
-
-  @param StoreInfo      Pointer to variable store info structure.
-  @param Variable       Pointer to the Variable Header.
-  @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
-
-  @retval TRUE          Variable header is valid.
-  @retval FALSE         Variable header is not valid.
-
-**/
-BOOLEAN
-GetVariableHeader (
-  IN VARIABLE_STORE_INFO  *StoreInfo,
-  IN VARIABLE_HEADER      *Variable,
-  OUT VARIABLE_HEADER     **VariableHeader
-  )
-{
-  EFI_PHYSICAL_ADDRESS  TargetAddress;
-  EFI_PHYSICAL_ADDRESS  SpareAddress;
-  EFI_HOB_GUID_TYPE     *GuidHob;
-  UINTN                 PartialHeaderSize;
-
-  if (Variable == NULL) {
-    return FALSE;
-  }
-
-  //
-  // First assume variable header pointed by Variable is consecutive.
-  //
-  *VariableHeader = Variable;
-
-  if (StoreInfo->FtwLastWriteData != NULL) {
-    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
-    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
-    if (((UINTN)Variable > (UINTN)SpareAddress) &&
-        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
-    {
-      //
-      // Reach the end of variable store.
-      //
-      return FALSE;
-    }
-
-    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
-      //
-      // Variable header pointed by Variable is inconsecutive,
-      // create a guid hob to combine the two partial variable header content together.
-      //
-      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
-      if (GuidHob != NULL) {
-        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
-      } else {
-        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
-        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
-        //
-        // Partial content is in NV storage.
-        //
-        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
-        //
-        // Another partial content is in spare block.
-        //
-        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
-      }
-    }
-  } else {
-    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
-      //
-      // Reach the end of variable store.
-      //
-      return FALSE;
-    }
-  }
-
-  return IsValidVariableHeader (*VariableHeader);
-}
-
-/**
-  Get variable name or data to output buffer.
-
-  @param  StoreInfo     Pointer to variable store info structure.
-  @param  NameOrData    Pointer to the variable name/data that may be inconsecutive.
-  @param  Size          Variable name/data size.
-  @param  Buffer        Pointer to output buffer to hold the variable name/data.
-
-**/
-VOID
-GetVariableNameOrData (
-  IN VARIABLE_STORE_INFO  *StoreInfo,
-  IN UINT8                *NameOrData,
-  IN UINTN                Size,
-  OUT UINT8               *Buffer
-  )
-{
-  EFI_PHYSICAL_ADDRESS  TargetAddress;
-  EFI_PHYSICAL_ADDRESS  SpareAddress;
-  UINTN                 PartialSize;
-
-  if (StoreInfo->FtwLastWriteData != NULL) {
-    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
-    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
-    if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
-      //
-      // Variable name/data is inconsecutive.
-      //
-      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
-      //
-      // Partial content is in NV storage.
-      //
-      CopyMem (Buffer, NameOrData, PartialSize);
-      //
-      // Another partial content is in spare block.
-      //
-      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
-      return;
-    }
-  }
-
-  //
-  // Variable name/data is consecutive.
-  //
-  CopyMem (Buffer, NameOrData, Size);
-}
-
 /**
   Find the variable in the specified variable store.
 
@@ -1246,3 +522,107 @@ PeiGetNextVariableName (
     }
   }
 }
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was be found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // If variable protection is employed, always get variable data through
+  // ProtectedVariableLib.
+  //
+  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid, Attributes, DataSize, Data);
+  if (Status != EFI_UNSUPPORTED) {
+    return Status;
+  }
+
+  return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize, Data);
+}
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+                            On return, the size of the variable name buffer.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // If variable protection is employed, always get next variable through
+  // ProtectedVariableLib.
+  //
+  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName, VariableGuid);
+  if (Status != EFI_UNSUPPORTED) {
+    return Status;
+  }
+
+  return PeiGetNextVariableName (This, VariableNameSize, VariableName, VariableGuid);
+}
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
new file mode 100644
index 000000000000..2d605d39cbb6
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
@@ -0,0 +1,941 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableStore.h"
+
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  //
+  // The start of variable store
+  //
+  return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store
+  //
+  return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
+}
+
+/**
+  This code checks if variable header is valid or not.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+
+  @retval TRUE      Variable header is valid.
+  @retval FALSE     Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable
+  )
+{
+  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  This code gets the size of variable header.
+
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFlag
+  )
+{
+  UINTN  Value;
+
+  if (AuthFlag) {
+    Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+  } else {
+    Value = sizeof (VARIABLE_HEADER);
+  }
+
+  return Value;
+}
+
+/**
+  This code gets the size of name of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    if ((AuthVariable->State == (UINT8)(-1)) ||
+        (AuthVariable->DataSize == (UINT32)(-1)) ||
+        (AuthVariable->NameSize == (UINT32)(-1)) ||
+        (AuthVariable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)AuthVariable->NameSize;
+  } else {
+    if ((Variable->State == (UINT8)(-1)) ||
+        (Variable->DataSize == (UINT32)(-1)) ||
+        (Variable->NameSize == (UINT32)(-1)) ||
+        (Variable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)Variable->NameSize;
+  }
+}
+
+/**
+  This code gets the size of data of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    if ((AuthVariable->State == (UINT8)(-1)) ||
+        (AuthVariable->DataSize == (UINT32)(-1)) ||
+        (AuthVariable->NameSize == (UINT32)(-1)) ||
+        (AuthVariable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)AuthVariable->DataSize;
+  } else {
+    if ((Variable->State == (UINT8)(-1)) ||
+        (Variable->DataSize == (UINT32)(-1)) ||
+        (Variable->NameSize == (UINT32)(-1)) ||
+        (Variable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)Variable->DataSize;
+  }
+}
+
+/**
+  This code gets the pointer to the variable name.
+
+  @param[in]   Variable  Pointer to the Variable Header.
+  @param[in]   AuthFlag  Authenticated variable flag.
+
+  @return  A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  )
+{
+  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in] Variable   Pointer to the Variable Header.
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    return &AuthVariable->VendorGuid;
+  } else {
+    return &Variable->VendorGuid;
+  }
+}
+
+/**
+  This code gets the pointer to the variable data.
+
+  @param[in]   Variable         Pointer to the Variable Header.
+  @param[in]   VariableHeader   Pointer to the Variable Header that has consecutive content.
+  @param[in]   AuthFlag         Authenticated variable flag.
+
+  @return  A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableHeader,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  UINTN  Value;
+
+  //
+  // Be careful about pad size for alignment
+  //
+  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
+  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+  return (UINT8 *)Value;
+}
+
+/**
+  This code gets the pointer to the next variable header.
+
+  @param[in]  StoreInfo         Pointer to variable store info structure.
+  @param[in]  Variable          Pointer to the Variable Header.
+  @param[in]  VariableHeader    Pointer to the Variable Header that has consecutive content.
+
+  @return  A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_STORE_INFO  *StoreInfo,
+  IN  VARIABLE_HEADER      *Variable,
+  IN  VARIABLE_HEADER      *VariableHeader
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 Value;
+
+  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+  //
+  // Be careful about pad size for alignment
+  //
+  Value = HEADER_ALIGN (Value);
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
+      //
+      // Next variable is in spare block.
+      //
+      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
+    }
+  }
+
+  return (VARIABLE_HEADER *)Value;
+}
+
+/**
+  Compare two variable names, one of them may be inconsecutive.
+
+  @param[in] StoreInfo      Pointer to variable store info structure.
+  @param[in] Name1          Pointer to one variable name.
+  @param[in] Name2          Pointer to another variable name.
+  @param[in] NameSize       Variable name size.
+
+  @retval TRUE          Name1 and Name2 are identical.
+  @retval FALSE         Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN CONST CHAR16         *Name1,
+  IN CONST CHAR16         *Name2,
+  IN UINTN                NameSize
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 PartialNameSize;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
+      //
+      // Name1 is inconsecutive.
+      //
+      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
+      //
+      // Partial content is in NV storage.
+      //
+      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
+        //
+        // Another partial content is in spare block.
+        //
+        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+          return TRUE;
+        }
+      }
+
+      return FALSE;
+    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
+      //
+      // Name2 is inconsecutive.
+      //
+      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
+      //
+      // Partial content is in NV storage.
+      //
+      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
+        //
+        // Another partial content is in spare block.
+        //
+        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+          return TRUE;
+        }
+      }
+
+      return FALSE;
+    }
+  }
+
+  //
+  // Both Name1 and Name2 are consecutive.
+  //
+  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  This function compares a variable with variable entries in database.
+
+  @param[in]   StoreInfo        Pointer to variable store info structure.
+  @param[in]   Variable         Pointer to the variable in our database
+  @param[in]   VariableHeader   Pointer to the Variable Header that has
+                                consecutive content.
+  @param[in]   VariableName     Name of the variable to compare to 'Variable'
+  @param[in]   VendorGuid       GUID of the variable to compare to 'Variable'
+  @param[out]  PtrTrack         Variable Track Pointer structure that contains
+                                Variable Information.
+
+  @retval EFI_SUCCESS    Found match variable
+  @retval EFI_NOT_FOUND  Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+  IN  VARIABLE_STORE_INFO     *StoreInfo,
+  IN  VARIABLE_HEADER         *Variable,
+  IN  VARIABLE_HEADER         *VariableHeader,
+  IN  CONST CHAR16            *VariableName,
+  IN  CONST EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  )
+{
+  VOID      *Point;
+  EFI_GUID  *TempVendorGuid;
+
+  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+  if (VariableName[0] == 0) {
+    PtrTrack->CurrPtr = Variable;
+    return EFI_SUCCESS;
+  } else {
+    //
+    // Don't use CompareGuid function here for performance reasons.
+    // Instead we compare the GUID a UINT32 at a time and branch
+    // on the first failed comparison.
+    //
+    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
+        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
+        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
+        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
+        )
+    {
+      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+      if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+        PtrTrack->CurrPtr = Variable;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get variable header that has consecutive content.
+
+  @param[in]  StoreInfo       Pointer to variable store info structure.
+  @param[in]  Variable        Pointer to the Variable Header.
+  @param[out] VariableHeader  Pointer to Pointer to the Variable Header
+                              that has consecutive content.
+
+  @retval TRUE          Variable header is valid.
+  @retval FALSE         Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN VARIABLE_HEADER      *Variable,
+  OUT VARIABLE_HEADER     **VariableHeader
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  EFI_HOB_GUID_TYPE     *GuidHob;
+  UINTN                 PartialHeaderSize;
+
+  if (Variable == NULL) {
+    return FALSE;
+  }
+
+  //
+  // First assume variable header pointed by Variable is consecutive.
+  //
+  *VariableHeader = Variable;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Variable > (UINTN)SpareAddress) &&
+        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
+    {
+      //
+      // Reach the end of variable store.
+      //
+      return FALSE;
+    }
+
+    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
+      //
+      // Variable header pointed by Variable is inconsecutive,
+      // create a guid hob to combine the two partial variable header content together.
+      //
+      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+      if (GuidHob != NULL) {
+        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+      } else {
+        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
+        //
+        // Partial content is in NV storage.
+        //
+        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
+        //
+        // Another partial content is in spare block.
+        //
+        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+      }
+    }
+  } else {
+    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+      //
+      // Reach the end of variable store.
+      //
+      return FALSE;
+    }
+  }
+
+  return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+  Get variable name or data to output buffer.
+
+  @param[in]   StoreInfo     Pointer to variable store info structure.
+  @param[in]   NameOrData    Pointer to the variable name/data that may be inconsecutive.
+  @param[in]   Size          Variable name/data size.
+  @param[out]  Buffer        Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN UINT8                *NameOrData,
+  IN UINTN                Size,
+  OUT UINT8               *Buffer
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 PartialSize;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
+      //
+      // Variable name/data is inconsecutive.
+      //
+      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
+      //
+      // Partial content is in NV storage.
+      //
+      CopyMem (Buffer, NameOrData, PartialSize);
+      //
+      // Another partial content is in spare block.
+      //
+      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
+      return;
+    }
+  }
+
+  //
+  // Variable name/data is consecutive.
+  //
+  CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+
+  Internal function to retrieve variable information.
+
+  @param[in,out] VariableInfo     Pointer to variable information.
+  @param[in]     StoreInfo        Pointer to store copy of variable (optional).
+  @param[in]     VariablePtr      Pointer to variable buffer.
+  @param[in]     VariableHeader   Pointer to variable header.
+
+  @retval EFI_INVALID_PARAMETER  One ore more required parameters are NULL.
+  @retval EFI_BUFFER_TOO_SMALL   Given buffer is too small to hold data.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfoInternal (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo,
+  IN      VARIABLE_STORE_INFO      *StoreInfo OPTIONAL,
+  IN      VARIABLE_HEADER          *VariablePtr,
+  IN      VARIABLE_HEADER          *VariableHeader
+  )
+{
+  VARIABLE_HEADER                *VariableBuffer;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariableHeader;
+  UINTN                          NameSize;
+  UINTN                          DataSize;
+  UINTN                          VariableSize;
+
+  if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader == NULL)) {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariablePtr != NULL);
+    ASSERT (VariableHeader != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableBuffer = VariableInfo->Buffer;
+
+  //
+  // Make a copy of the whole variable if VariableInfo->Buffer is given. But
+  // don't do this if StoreInfo is not given, because VariableInfo->Buffer
+  // has already hold a copy of variable in such situation.
+  //
+  NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+  DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+    if (StoreInfo != NULL) {
+      CopyMem (
+        VariableBuffer,
+        VariableHeader,
+        GetVariableHeaderSize (VariableInfo->Flags.Auth)
+        );
+      GetVariableNameOrData (
+        StoreInfo,
+        (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+        NameSize,
+        (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
+        );
+      GetVariableNameOrData (
+        StoreInfo,
+        (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo->Flags.Auth),
+        DataSize,
+        (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader, VariableInfo->Flags.Auth)
+        );
+    } else {
+      //
+      // Suppose the variable is in consecutive space.
+      //
+      VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
+                     + NameSize + GET_PAD_SIZE (NameSize)
+                     + DataSize;
+      CopyMem (VariableBuffer, VariablePtr, VariableSize);
+    }
+  }
+
+  //
+  // Generally, if no consecutive buffer passed in, don't return back any data.
+  //
+  // If follow pointers are NULL, return back pointers to following data inside
+  // VariableInfo->Buffer, if it's given.
+  //
+  //  VariableInfo->Header.VariableName
+  //  VariableInfo->Header.Data
+  //  VariableInfo->Header.VendorGuid
+  //  VariableInfo->Header.TimeStamp
+  //
+  // Otherwise, suppose they're buffers used to hold a copy of corresponding
+  // data.
+  //
+  //
+
+  //
+  // AuthVariable header
+  //
+  if (VariableInfo->Flags.Auth) {
+    AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableHeader;
+
+    VariableInfo->Header.State          = AuthVariableHeader->State;
+    VariableInfo->Header.Attributes     = AuthVariableHeader->Attributes;
+    VariableInfo->Header.PubKeyIndex    = AuthVariableHeader->PubKeyIndex;
+    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+                                            &(AuthVariableHeader->MonotonicCount)
+                                            );
+    if (VariableInfo->Header.TimeStamp != NULL) {
+      CopyMem (
+        VariableInfo->Header.TimeStamp,
+        &AuthVariableHeader->TimeStamp,
+        sizeof (EFI_TIME)
+        );
+    } else if (VariableBuffer != NULL) {
+      AuthVariableHeader             = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+      VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
+    }
+  } else {
+    VariableInfo->Header.State          = VariableHeader->State;
+    VariableInfo->Header.Attributes     = VariableHeader->Attributes;
+    VariableInfo->Header.PubKeyIndex    = 0;
+    VariableInfo->Header.MonotonicCount = 0;
+    VariableInfo->Header.TimeStamp      = NULL;
+  }
+
+  //
+  // VendorGuid
+  //
+  if (VariableInfo->Header.VendorGuid != NULL) {
+    CopyGuid (
+      VariableInfo->Header.VendorGuid,
+      GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.VendorGuid
+      = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
+  }
+
+  //
+  // VariableName
+  //
+  if (  (VariableInfo->Header.VariableName != NULL)
+     && (VariableInfo->Header.NameSize >= NameSize))
+  {
+    GetVariableNameOrData (
+      StoreInfo,
+      (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+      NameSize,
+      (UINT8 *)VariableInfo->Header.VariableName
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.VariableName
+      = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
+  } else if (VariableInfo->Header.VariableName != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // Data
+  //
+  if (  (VariableInfo->Header.Data != NULL)
+     && (VariableInfo->Header.DataSize >= DataSize))
+  {
+    GetVariableNameOrData (
+      StoreInfo,
+      GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
+      DataSize,
+      VariableInfo->Header.Data
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.Data
+      = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo->Flags.Auth);
+  } else if (VariableInfo->Header.Data != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // Update size information about name & data.
+  //
+  VariableInfo->Header.NameSize = NameSize;
+  VariableInfo->Header.DataSize = DataSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Retrieve details about a variable, given by VariableInfo->Buffer or
+  VariableInfo->Index, and pass the details back in VariableInfo->Header.
+
+  This function is used to resolve the variable data structure into
+  VariableInfo->Header, for easier access later without revisiting the variable
+  data in variable store. If pointers in the structure of VariableInfo->Header
+  are not NULL, it's supposed that they are buffers passed in to hold a copy of
+  data of corresponding data fields in variable data structure. Otherwise, this
+  function simply returns pointers pointing to address of those data fields.
+
+  The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
+  If VariableInfo->Index is given, this function finds the corresponding variable
+  first from variable storage according to the Index.
+
+  If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
+  that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
+  requested variable data to be returned.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Buffer
+                                 and VariableInfo->Index are NULL (0).
+  @retval EFI_NOT_FOUND          If given Buffer or Index is out of range of
+                                 any given or internal storage copies.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
+  )
+{
+  VARIABLE_HEADER      *VariablePtr;
+  VARIABLE_HEADER      *VariableHeader;
+  VARIABLE_STORE_TYPE  StoreType;
+  VARIABLE_STORE_INFO  StoreInfo;
+  UINTN                Offset;
+
+  if ((VariableInfo == NULL) ||
+      ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+  {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo->Buffer != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StoreInfo.VariableStoreHeader = NULL;
+  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+    GetVariableStore (StoreType, &StoreInfo);
+    if (StoreInfo.VariableStoreHeader != NULL) {
+      break;
+    }
+  }
+
+  ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+  //
+  // No StoreIndex? Don't retrieve variable information from store but just from
+  // VariableInfo->Buffer.
+  //
+  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+    VariablePtr    = VariableInfo->Buffer;
+    VariableHeader = VariablePtr;
+
+    return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr, VariableHeader);
+  }
+
+  Offset = (UINTN)VariableInfo->StoreIndex;
+  if (  (StoreInfo.FtwLastWriteData != NULL)
+     && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                    - (UINTN)StoreInfo.VariableStoreHeader)))
+  {
+    Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+               - (UINTN)StoreInfo.VariableStoreHeader);
+    VariablePtr = (VARIABLE_HEADER *)
+                  ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+  } else {
+    VariablePtr = (VARIABLE_HEADER *)
+                  ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+  }
+
+  //
+  // Note that variable might be in unconsecutive space. Always get a copy
+  // of its header in consecutive buffer.
+  //
+  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+    return EFI_NOT_FOUND;
+  }
+
+  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
+
+  VariableStart and/or VariableEnd can be given optionally for the situation
+  in which the valid storage space is smaller than the VariableStore->Size.
+  This usually happens when PEI variable services make a compact variable
+  cache to save memory, which cannot make use VariableStore->Size to determine
+  the correct variable storage range.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
+  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
+  @retval EFI_SUCCESS            The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
+  )
+{
+  VARIABLE_HEADER      *VariablePtr;
+  VARIABLE_HEADER      *VariableHeader;
+  VARIABLE_STORE_INFO  StoreInfo;
+  VARIABLE_STORE_TYPE  StoreType;
+  UINTN                Offset;
+
+  if (VariableInfo == NULL) {
+    ASSERT (VariableInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StoreInfo.VariableStoreHeader = NULL;
+  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+    GetVariableStore (StoreType, &StoreInfo);
+    if (StoreInfo.VariableStoreHeader != NULL) {
+      break;
+    }
+  }
+
+  ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+  //
+  // VariableInfo->StoreIndex is supposed to be the index to variable found
+  // last time. Use it to get the variable next to it in store. If it's invalid,
+  // return the first variable available in store.
+  //
+  VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
+  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+    VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
+  } else {
+    Offset = (UINTN)VariableInfo->StoreIndex;
+    if (  (StoreInfo.FtwLastWriteData != NULL)
+       && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                      - (UINTN)StoreInfo.VariableStoreHeader)))
+    {
+      Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                 - (UINTN)StoreInfo.VariableStoreHeader);
+      VariablePtr = (VARIABLE_HEADER *)
+                    ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+    } else {
+      VariablePtr = (VARIABLE_HEADER *)
+                    ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+    }
+
+    //
+    // Note that variable might be in unconsecutive space. Always get a copy
+    // of its header in consecutive buffer.
+    //
+    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+      return EFI_NOT_FOUND;
+    }
+
+    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
+  }
+
+  //
+  // Get a copy of variable header in consecutive buffer.
+  //
+  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Use the offset to the start of variable store as index of the variable.
+  //
+  if (  (StoreInfo.FtwLastWriteData == NULL)
+     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData->TargetAddress))
+  {
+    VariableInfo->StoreIndex
+      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
+  } else {
+    VariableInfo->StoreIndex
+      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                 - (UINTN)StoreInfo.VariableStoreHeader);
+    VariableInfo->StoreIndex
+      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData->SpareAddress);
+  }
+
+  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
+    VariableInfo->Buffer = VariablePtr;
+  }
+
+  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
new file mode 100644
index 000000000000..72bd17a43048
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
@@ -0,0 +1,305 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+/**
+  Get variable store status.
+
+  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval  EfiRaw      Variable store is raw
+  @retval  EfiValid    Variable store is valid
+  @retval  EfiInvalid  Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
+      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
+      )
+  {
+    return EfiValid;
+  }
+
+  if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
+      (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
+      (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
+      (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
+      (VarStoreHeader->Size == 0xffffffff) &&
+      (VarStoreHeader->Format == 0xff) &&
+      (VarStoreHeader->State == 0xff)
+      )
+  {
+    return EfiRaw;
+  } else {
+    return EfiInvalid;
+  }
+}
+
+/**
+  Reports HOB variable store is available or not.
+
+  @retval EFI_NOT_READY  HOB variable store info not available.
+  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
+  @retval EFI_SUCCESS    HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+  VOID               *VariableStoreInfoHob;
+
+  //
+  // Discover if Variable Store Info Hob has been published by platform driver.
+  // It contains information regards to HOB or NV Variable Store availability
+  //
+  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
+  if (GuidHob == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  //
+  // Check if HOB Variable Store is available
+  //
+  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
+  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // This might be NV Variable Store
+  //
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get HOB variable store.
+
+  @param[out] StoreInfo             Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  //
+  // Make sure there is no more than one Variable HOB.
+  //
+  DEBUG_CODE_BEGIN ();
+  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+  if (GuidHob != NULL) {
+    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+      ASSERT (FALSE);
+    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+      ASSERT (FALSE);
+    }
+  } else {
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+    if (GuidHob != NULL) {
+      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+        ASSERT (FALSE);
+      }
+    }
+  }
+
+  DEBUG_CODE_END ();
+
+  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+  if (GuidHob != NULL) {
+    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+    StoreInfo->AuthFlag            = TRUE;
+  } else {
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+    if (GuidHob != NULL) {
+      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+      StoreInfo->AuthFlag            = FALSE;
+    }
+  }
+}
+
+/**
+  Get NV variable store.
+
+  @param[out] StoreInfo             Return the store info.
+  @param[out] VariableFvHeader      Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+  OUT VARIABLE_STORE_INFO         *StoreInfo,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
+  )
+{
+  EFI_HOB_GUID_TYPE                     *GuidHob;
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
+  VARIABLE_STORE_HEADER                 *StoreHeader;
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
+  UINT32                                NvStorageSize;
+  UINT32                                BackUpOffset;
+
+  NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+  NvStorageBase = (EFI_PHYSICAL_ADDRESS)
+                  (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0)
+                  ? PcdGet64 (PcdFlashNvStorageVariableBase64)
+                  : PcdGet32 (PcdFlashNvStorageVariableBase);
+  ASSERT (NvStorageBase != 0);
+
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
+
+  //
+  // Check the FTW last write data hob.
+  //
+  BackUpOffset     = 0;
+  FtwLastWriteData = NULL;
+  HobData          = NULL;
+  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+
+  if (GuidHob != NULL) {
+    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
+    if (HobData->TargetAddress == NvStorageBase) {
+      //
+      // Let FvHeader point to spare block.
+      //
+      DEBUG ((
+        EFI_D_INFO,
+        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
+        (UINTN)HobData->SpareAddress
+        ));
+
+      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData->SpareAddress;
+      HobData  = NULL;
+    } else if ((HobData->TargetAddress > NvStorageBase) &&
+               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
+    {
+      //
+      // Flash NV storage from the offset is backed up in spare block.
+      //
+      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
+      DEBUG ((
+        EFI_D_INFO,
+        "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n",
+        BackUpOffset,
+        (UINTN)FtwLastWriteData->SpareAddress
+        ));
+      //
+      // At least one block data in flash NV storage is still valid, so still
+      // leave FvHeader point to NV storage base.
+      //
+    }
+  }
+
+  if (StoreInfo != NULL) {
+    StoreInfo->FtwLastWriteData = HobData;
+  }
+
+  if (VariableFvHeader != NULL) {
+    *VariableFvHeader = FvHeader;
+  }
+
+  //
+  // Check if the Firmware Volume is not corrupted
+  //
+  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
+      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
+  {
+    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+  } else {
+    StoreHeader = NULL;
+    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+  }
+
+  if (StoreInfo != NULL) {
+    StoreInfo->VariableStoreHeader = StoreHeader;
+    if (StoreHeader != NULL) {
+      StoreInfo->AuthFlag = CompareGuid (
+                              &StoreHeader->Signature,
+                              &gEfiAuthenticatedVariableGuid
+                              );
+    }
+  }
+}
+
+/**
+  Return the variable store header and the store info based on the Index.
+
+  @param[in]  Type       The type of the variable store.
+  @param[out] StoreInfo  Return the store info.
+
+  @return  Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+  IN VARIABLE_STORE_TYPE   Type,
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  StoreInfo->VariableStoreHeader = NULL;
+  StoreInfo->IndexTable          = NULL;
+  StoreInfo->FtwLastWriteData    = NULL;
+  StoreInfo->AuthFlag            = FALSE;
+  switch (Type) {
+    case VariableStoreTypeHob:
+      GetHobVariableStore (StoreInfo);
+      break;
+
+    case VariableStoreTypeNv:
+      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+        //
+        // Emulated non-volatile variable mode is not enabled.
+        //
+        GetNvVariableStore (StoreInfo, NULL);
+        if (StoreInfo->VariableStoreHeader != NULL) {
+          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+          if (GuidHob != NULL) {
+            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+          } else {
+            //
+            // If it's the first time to access variable region in flash, create a guid hob to record
+            // VAR_ADDED type variable info.
+            // Note that as the resource of PEI phase is limited, only store the limited number of
+            // VAR_ADDED type variables to reduce access time.
+            //
+            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+            StoreInfo->IndexTable->Length      = 0;
+            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo->VariableStoreHeader);
+            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo->VariableStoreHeader);
+            StoreInfo->IndexTable->GoneThrough = 0;
+          }
+        }
+      }
+
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+
+  return StoreInfo->VariableStoreHeader;
+}
-- 
2.35.1.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#89426): https://edk2.groups.io/g/devel/message/89426
Mute This Topic: https://groups.io/mt/90781893/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
Posted by Wang, Jian J 1 month ago
Judah,

One general comment: please add variable store provision/recovery flow and
explanations in the readme.

See my other inline comments below.

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> Provide new APIs for retrieving variable information.
> Add new function stubs for retrieving Protected
> variable information.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  MdeModulePkg/Universal/Variable/Pei/VariablePei.inf   |  10 +-
>  MdeModulePkg/Universal/Variable/Pei/Variable.h        |  80 +-
>  MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++++++
>  MdeModulePkg/Universal/Variable/Pei/VariableStore.h   | 116 +++
>  MdeModulePkg/Universal/Variable/Pei/Variable.c        | 886 +++---------------
>  MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941
> ++++++++++++++++++++
>  MdeModulePkg/Universal/Variable/Pei/VariableStore.c   | 305 +++++++
>  7 files changed, 1891 insertions(+), 756 deletions(-)
> 
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> index 7cbdd2385e8f..af172126a011 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> @@ -3,7 +3,7 @@
>  #
>  #  This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.
>  #
> -#  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
>  ##
> @@ -26,6 +26,10 @@ [Defines]
>  [Sources]
>    Variable.c
>    Variable.h
> +  VariableStore.c
> +  VariableStore.h
> +  VariableParsing.c
> +  VariableParsing.h
> 
>  [Packages]
>    MdePkg/MdePkg.dec
> @@ -39,6 +43,7 @@ [LibraryClasses]
>    DebugLib
>    PeiServicesTablePointerLib
>    PeiServicesLib
> +  ProtectedVariableLib
> 
>  [Guids]
>    ## CONSUMES             ## GUID # Variable store header
> @@ -56,7 +61,8 @@ [Guids]
>    gEdkiiFaultTolerantWriteGuid
> 
>  [Ppis]
> -  gEfiPeiReadOnlyVariable2PpiGuid   ## PRODUCES
> +  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
> +  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
> 
>  [Pcd]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase      ##
> SOMETIMES_CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h
> b/MdeModulePkg/Universal/Variable/Pei/Variable.h
> index 7f9ad5bfc357..115426edd626 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/Variable.h
> +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h
> @@ -2,7 +2,7 @@
>    The internal header file includes the common header files, defines
>    internal structure and functions used by PeiVariable module.
> 
> -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  **/
> @@ -20,11 +20,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/PeiServicesTablePointerLib.h>
>  #include <Library/PeiServicesLib.h>
> +#include <Library/ProtectedVariableLib.h>
> 
>  #include <Guid/VariableFormat.h>
>  #include <Guid/VariableIndexTable.h>
>  #include <Guid/SystemNvDataGuid.h>
>  #include <Guid/FaultTolerantWrite.h>
> +#include <Guid/ProtectedVariable.h>
> 
>  typedef enum {
>    VariableStoreTypeHob,
> @@ -142,4 +144,80 @@ PeiGetNextVariableName (
>    IN OUT EFI_GUID                            *VariableGuid
>    );
> 
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +
> +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  );
> +
>  #endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> new file mode 100644
> index 000000000000..d7af6cb6e8be
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> @@ -0,0 +1,309 @@
> +/** @file
> +  The internal header file includes the common header files, defines
> +  internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_PARSING_H_
> +#define PEI_VARIABLE_PARSING_H_
> +
> +#include "Variable.h"
> +
> +/**
> +
> +  Gets the pointer to the first variable header in given variable store area.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the first variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetStartPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +
> +  Gets the pointer to the end of the variable storage area.
> +
> +  This function gets pointer to the end of the variable storage
> +  area, according to the input variable store header.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the end of the variable storage area.
> +
> +**/
> +VARIABLE_HEADER *
> +GetEndPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +  This code checks if variable header is valid or not.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +
> +  @retval TRUE      Variable header is valid.
> +  @retval FALSE     Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> +  IN  VARIABLE_HEADER  *Variable
> +  );
> +
> +/**
> +  This code gets the pointer to the next variable header.
> +
> +  @param[in]  StoreInfo         Pointer to variable store info structure.
> +  @param[in]  Variable          Pointer to the Variable Header.
> +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> +
> +  @return  A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> +  IN  VARIABLE_HEADER      *Variable,
> +  IN  VARIABLE_HEADER      *VariableHeader
> +  );
> +
> +/**
> +  This code gets the pointer to the variable guid.
> +
> +  @param[in]  Variable   Pointer to the Variable Header.
> +  @param[in]  AuthFlag   Authenticated variable flag.
> +
> +  @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable name.
> +
> +  @param[in]   Variable  Pointer to the Variable Header.
> +  @param[in]   AuthFlag  Authenticated variable flag.
> +
> +  @return  A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of name of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of data of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable data.
> +
> +  @param[in]   Variable         Pointer to the Variable Header.
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]   AuthFlag         Authenticated variable flag.
> +
> +  @return  A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  VARIABLE_HEADER  *VariableHeader,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  Get variable header that has consecutive content.
> +
> +  @param[in]  StoreInfo      Pointer to variable store info structure.
> +  @param[in]  Variable       Pointer to the Variable Header.
> +  @param[out] VariableHeader Pointer to Pointer to the Variable Header that
> has consecutive content.
> +
> +  @retval TRUE          Variable header is valid.
> +  @retval FALSE         Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN VARIABLE_HEADER      *Variable,
> +  OUT VARIABLE_HEADER     **VariableHeader
> +  );
> +
> +/**
> +  This code gets the size of variable header.
> +
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> +  IN  BOOLEAN  AuthFlag
> +  );
> +
> +/**
> +  Get variable name or data to output buffer.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> +  @param[in]  Size          Variable name/data size.
> +  @param[out] Buffer        Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN UINT8                *NameOrData,
> +  IN UINTN                Size,
> +  OUT UINT8               *Buffer
> +  );
> +
> +/**
> +  This function compares a variable with variable entries in database.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  Variable      Pointer to the variable in our database
> +  @param[in]  VariableHeader Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]  VariableName  Name of the variable to compare to 'Variable'
> +  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
> +  @param[out] PtrTrack      Variable Track Pointer structure that contains
> Variable Information.
> +
> +  @retval EFI_SUCCESS    Found match variable
> +  @retval EFI_NOT_FOUND  Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> +  IN  VARIABLE_HEADER         *Variable,
> +  IN  VARIABLE_HEADER         *VariableHeader,
> +  IN  CONST CHAR16            *VariableName,
> +  IN  CONST EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within VariableStore.
> +
> +  If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
> +  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
> +  @retval EFI_SUCCESS            The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  );
> +
> +/**
> +
> +  Retrieve details about a variable and return them in VariableInfo->Header.
> +
> +  If VariableInfo->Address is given, this function will calculate its offset
> +  relative to given variable storage via VariableStore; Otherwise, it will try
> +  other internal variable storages or cached copies. It's assumed that, for all
> +  copies of NV variable storage, all variables are stored in the same relative
> +  position. If VariableInfo->Address is found in the range of any storage copies,
> +  its offset relative to that storage should be the same in other copies.
> +
> +  If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> +  this function will return the variable memory address inside VariableStore,
> +  if given, via VariableInfo->Address; Otherwise, the address of other storage
> +  copies will be returned, if any.
> +
> +  For a new variable whose offset has not been determined, a value of -1 as
> +  VariableInfo->Offset should be passed to skip the offset calculation.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Address
> +                                 and VariableInfo->Offset are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
> +                                 any given or internal storage copies.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  );
> +
> +/**
> +
> +  Find variable specified with input parameters.
> +
> +  @param[in] StoreInfo             Pointer to variable information.
> +  @param[in] VariableName          Pointer to variable name.
> +  @param[in] VendorGuid            Pointer to variable GUID.
> +  @param[in] PtrTrack              Pointer to variable track.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Address
> +                                 and VariableInfo->Offset are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
> +                                 any given or internal storage copies.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +FindVariableEx (
> +  IN VARIABLE_STORE_INFO      *StoreInfo,
> +  IN CONST CHAR16             *VariableName,
> +  IN CONST EFI_GUID           *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> new file mode 100644
> index 000000000000..6e2f6f939bab
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> @@ -0,0 +1,116 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_STORE_H_
> +#define PEI_VARIABLE_STORE_H_
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  );
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableStoreHeader   Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  );
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Make a cached copy of NV variable storage.
> +
> +  To save memory in PEI phase, only valid variables are copied into cache.
> +  An IndexTable could be used to store the offset (relative to NV storage
> +  base) of each copied variable, in case we need to restore the storage
> +  as the same (valid) variables layout as in original one.
> +
> +  Variables with valid format and following state can be taken as valid:
> +    - with state VAR_ADDED;
> +    - with state VAR_IN_DELETED_TRANSITION but without the same variable
> +      with state VAR_ADDED;
> +    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
> +      MetaDataHmacVar.
> +
> +  @param[out]     StoreCacheBase    Base address of variable storage cache.
> +  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
> +  @param[out]     IndexTable        Buffer of index (offset) table with entries of
> +                                    VariableNumber.
> +  @param[out]     VariableNumber    Number of valid variables.
> +  @param[out]     AuthFlag          Aut-variable indicator.
> +
> +  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or
> StoreCacheBase.
> +  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
> +  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
> +  @return EFI_SUCCESS           NV variable storage is cached successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitNvVariableStore (
> +  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
> +  IN OUT  UINT32             *StoreCacheSize,
> +  OUT  UINT32                *IndexTable OPTIONAL,
> +  OUT  UINT32                *VariableNumber OPTIONAL,
> +  OUT  BOOLEAN               *AuthFlag OPTIONAL
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c
> b/MdeModulePkg/Universal/Variable/Pei/Variable.c
> index b36dd0de67b2..ce790946626e 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
> +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
> @@ -2,20 +2,22 @@
>    Implement ReadOnly Variable Services required by PEIM and install
>    PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> 
> -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
>  Copyright (c) Microsoft Corporation.<BR>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  **/
> 
>  #include "Variable.h"
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> 
>  //
>  // Module globals
>  //
>  EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
> -  PeiGetVariable,
> -  PeiGetNextVariableName
> +  PeiGetVariableEx,
> +  PeiGetNextVariableNameEx
>  };
> 
>  EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
> @@ -41,759 +43,33 @@ PeimInitializeVariableServices (
>    IN CONST EFI_PEI_SERVICES     **PeiServices
>    )
>  {
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
> +
> +  //
> +  // If protected variable services are not supported, EFI_UNSUPPORTED should
> +  // be always returned. Check it here.
> +  //
> +  ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +  ContextIn.StructSize    = sizeof (ContextIn);
> +
> +  ContextIn.MaxVariableSize             = 0;
> +  ContextIn.VariableServiceUser         = FromPeiModule;
> +  ContextIn.GetVariableInfo             = GetVariableInfo;
> +  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
> +  ContextIn.FindVariableSmm             = NULL;
> +  ContextIn.UpdateVariableStore         = NULL;
> +  ContextIn.UpdateVariable              = NULL;
> +  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
> +
> +  Status = ProtectedVariableLibInitialize (&ContextIn);
> +  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> +    return Status;
> +  }
> +
>    return PeiServicesInstallPpi (&mPpiListVariable);
>  }
> 
> -/**
> -
> -  Gets the pointer to the first variable header in given variable store area.
> -
> -  @param VarStoreHeader  Pointer to the Variable Store Header.
> -
> -  @return Pointer to the first variable header.
> -
> -**/
> -VARIABLE_HEADER *
> -GetStartPointer (
> -  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> -  )
> -{
> -  //
> -  // The start of variable store
> -  //
> -  return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
> -}
> -
> -/**
> -
> -  Gets the pointer to the end of the variable storage area.
> -
> -  This function gets pointer to the end of the variable storage
> -  area, according to the input variable store header.
> -
> -  @param VarStoreHeader  Pointer to the Variable Store Header.
> -
> -  @return Pointer to the end of the variable storage area.
> -
> -**/
> -VARIABLE_HEADER *
> -GetEndPointer (
> -  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> -  )
> -{
> -  //
> -  // The end of variable store
> -  //
> -  return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader +
> VarStoreHeader->Size);
> -}
> -
> -/**
> -  This code checks if variable header is valid or not.
> -
> -  @param  Variable  Pointer to the Variable Header.
> -
> -  @retval TRUE      Variable header is valid.
> -  @retval FALSE     Variable header is not valid.
> -
> -**/
> -BOOLEAN
> -IsValidVariableHeader (
> -  IN  VARIABLE_HEADER  *Variable
> -  )
> -{
> -  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> -    return FALSE;
> -  }
> -
> -  return TRUE;
> -}
> -
> -/**
> -  This code gets the size of variable header.
> -
> -  @param AuthFlag   Authenticated variable flag.
> -
> -  @return Size of variable header in bytes in type UINTN.
> -
> -**/
> -UINTN
> -GetVariableHeaderSize (
> -  IN  BOOLEAN  AuthFlag
> -  )
> -{
> -  UINTN  Value;
> -
> -  if (AuthFlag) {
> -    Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
> -  } else {
> -    Value = sizeof (VARIABLE_HEADER);
> -  }
> -
> -  return Value;
> -}
> -
> -/**
> -  This code gets the size of name of variable.
> -
> -  @param  Variable  Pointer to the Variable Header.
> -  @param  AuthFlag  Authenticated variable flag.
> -
> -  @return Size of variable in bytes in type UINTN.
> -
> -**/
> -UINTN
> -NameSizeOfVariable (
> -  IN  VARIABLE_HEADER  *Variable,
> -  IN  BOOLEAN          AuthFlag
> -  )
> -{
> -  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> -
> -  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> -  if (AuthFlag) {
> -    if ((AuthVariable->State == (UINT8)(-1)) ||
> -        (AuthVariable->DataSize == (UINT32)(-1)) ||
> -        (AuthVariable->NameSize == (UINT32)(-1)) ||
> -        (AuthVariable->Attributes == (UINT32)(-1)))
> -    {
> -      return 0;
> -    }
> -
> -    return (UINTN)AuthVariable->NameSize;
> -  } else {
> -    if ((Variable->State == (UINT8)(-1)) ||
> -        (Variable->DataSize == (UINT32)(-1)) ||
> -        (Variable->NameSize == (UINT32)(-1)) ||
> -        (Variable->Attributes == (UINT32)(-1)))
> -    {
> -      return 0;
> -    }
> -
> -    return (UINTN)Variable->NameSize;
> -  }
> -}
> -
> -/**
> -  This code gets the size of data of variable.
> -
> -  @param  Variable  Pointer to the Variable Header.
> -  @param  AuthFlag  Authenticated variable flag.
> -
> -  @return Size of variable in bytes in type UINTN.
> -
> -**/
> -UINTN
> -DataSizeOfVariable (
> -  IN  VARIABLE_HEADER  *Variable,
> -  IN  BOOLEAN          AuthFlag
> -  )
> -{
> -  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> -
> -  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> -  if (AuthFlag) {
> -    if ((AuthVariable->State == (UINT8)(-1)) ||
> -        (AuthVariable->DataSize == (UINT32)(-1)) ||
> -        (AuthVariable->NameSize == (UINT32)(-1)) ||
> -        (AuthVariable->Attributes == (UINT32)(-1)))
> -    {
> -      return 0;
> -    }
> -
> -    return (UINTN)AuthVariable->DataSize;
> -  } else {
> -    if ((Variable->State == (UINT8)(-1)) ||
> -        (Variable->DataSize == (UINT32)(-1)) ||
> -        (Variable->NameSize == (UINT32)(-1)) ||
> -        (Variable->Attributes == (UINT32)(-1)))
> -    {
> -      return 0;
> -    }
> -
> -    return (UINTN)Variable->DataSize;
> -  }
> -}
> -
> -/**
> -  This code gets the pointer to the variable name.
> -
> -  @param   Variable  Pointer to the Variable Header.
> -  @param   AuthFlag  Authenticated variable flag.
> -
> -  @return  A CHAR16* pointer to Variable Name.
> -
> -**/
> -CHAR16 *
> -GetVariableNamePtr (
> -  IN VARIABLE_HEADER  *Variable,
> -  IN BOOLEAN          AuthFlag
> -  )
> -{
> -  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> -}
> -
> -/**
> -  This code gets the pointer to the variable guid.
> -
> -  @param Variable   Pointer to the Variable Header.
> -  @param AuthFlag   Authenticated variable flag.
> -
> -  @return A EFI_GUID* pointer to Vendor Guid.
> -
> -**/
> -EFI_GUID *
> -GetVendorGuidPtr (
> -  IN VARIABLE_HEADER  *Variable,
> -  IN BOOLEAN          AuthFlag
> -  )
> -{
> -  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> -
> -  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> -  if (AuthFlag) {
> -    return &AuthVariable->VendorGuid;
> -  } else {
> -    return &Variable->VendorGuid;
> -  }
> -}
> -
> -/**
> -  This code gets the pointer to the variable data.
> -
> -  @param   Variable         Pointer to the Variable Header.
> -  @param   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> -  @param   AuthFlag         Authenticated variable flag.
> -
> -  @return  A UINT8* pointer to Variable Data.
> -
> -**/
> -UINT8 *
> -GetVariableDataPtr (
> -  IN  VARIABLE_HEADER  *Variable,
> -  IN  VARIABLE_HEADER  *VariableHeader,
> -  IN  BOOLEAN          AuthFlag
> -  )
> -{
> -  UINTN  Value;
> -
> -  //
> -  // Be careful about pad size for alignment
> -  //
> -  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> -  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> -  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> -
> -  return (UINT8 *)Value;
> -}
> -
> -/**
> -  This code gets the pointer to the next variable header.
> -
> -  @param  StoreInfo         Pointer to variable store info structure.
> -  @param  Variable          Pointer to the Variable Header.
> -  @param  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> -
> -  @return  A VARIABLE_HEADER* pointer to next variable header.
> -
> -**/
> -VARIABLE_HEADER *
> -GetNextVariablePtr (
> -  IN  VARIABLE_STORE_INFO  *StoreInfo,
> -  IN  VARIABLE_HEADER      *Variable,
> -  IN  VARIABLE_HEADER      *VariableHeader
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS  TargetAddress;
> -  EFI_PHYSICAL_ADDRESS  SpareAddress;
> -  UINTN                 Value;
> -
> -  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> >AuthFlag);
> -  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> -  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> >AuthFlag));
> -  //
> -  // Be careful about pad size for alignment
> -  //
> -  Value = HEADER_ALIGN (Value);
> -
> -  if (StoreInfo->FtwLastWriteData != NULL) {
> -    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> -    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> -    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> (UINTN)TargetAddress)) {
> -      //
> -      // Next variable is in spare block.
> -      //
> -      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> -    }
> -  }
> -
> -  return (VARIABLE_HEADER *)Value;
> -}
> -
> -/**
> -  Get variable store status.
> -
> -  @param  VarStoreHeader  Pointer to the Variable Store Header.
> -
> -  @retval  EfiRaw      Variable store is raw
> -  @retval  EfiValid    Variable store is valid
> -  @retval  EfiInvalid  Variable store is invalid
> -
> -**/
> -VARIABLE_STORE_STATUS
> -GetVariableStoreStatus (
> -  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> -  )
> -{
> -  if ((CompareGuid (&VarStoreHeader->Signature,
> &gEfiAuthenticatedVariableGuid) ||
> -       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
> -      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
> -      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
> -      )
> -  {
> -    return EfiValid;
> -  }
> -
> -  if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
> -      (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
> -      (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
> -      (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
> -      (VarStoreHeader->Size == 0xffffffff) &&
> -      (VarStoreHeader->Format == 0xff) &&
> -      (VarStoreHeader->State == 0xff)
> -      )
> -  {
> -    return EfiRaw;
> -  } else {
> -    return EfiInvalid;
> -  }
> -}
> -
> -/**
> -  Compare two variable names, one of them may be inconsecutive.
> -
> -  @param StoreInfo      Pointer to variable store info structure.
> -  @param Name1          Pointer to one variable name.
> -  @param Name2          Pointer to another variable name.
> -  @param NameSize       Variable name size.
> -
> -  @retval TRUE          Name1 and Name2 are identical.
> -  @retval FALSE         Name1 and Name2 are not identical.
> -
> -**/
> -BOOLEAN
> -CompareVariableName (
> -  IN VARIABLE_STORE_INFO  *StoreInfo,
> -  IN CONST CHAR16         *Name1,
> -  IN CONST CHAR16         *Name2,
> -  IN UINTN                NameSize
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS  TargetAddress;
> -  EFI_PHYSICAL_ADDRESS  SpareAddress;
> -  UINTN                 PartialNameSize;
> -
> -  if (StoreInfo->FtwLastWriteData != NULL) {
> -    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> -    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> -    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> NameSize) > (UINTN)TargetAddress)) {
> -      //
> -      // Name1 is inconsecutive.
> -      //
> -      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> -      //
> -      // Partial content is in NV storage.
> -      //
> -      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0)
> {
> -        //
> -        // Another partial content is in spare block.
> -        //
> -        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> -          return TRUE;
> -        }
> -      }
> -
> -      return FALSE;
> -    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> NameSize) > (UINTN)TargetAddress)) {
> -      //
> -      // Name2 is inconsecutive.
> -      //
> -      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> -      //
> -      // Partial content is in NV storage.
> -      //
> -      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0)
> {
> -        //
> -        // Another partial content is in spare block.
> -        //
> -        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> -          return TRUE;
> -        }
> -      }
> -
> -      return FALSE;
> -    }
> -  }
> -
> -  //
> -  // Both Name1 and Name2 are consecutive.
> -  //
> -  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> -    return TRUE;
> -  }
> -
> -  return FALSE;
> -}
> -
> -/**
> -  This function compares a variable with variable entries in database.
> -
> -  @param  StoreInfo     Pointer to variable store info structure.
> -  @param  Variable      Pointer to the variable in our database
> -  @param  VariableHeader Pointer to the Variable Header that has consecutive
> content.
> -  @param  VariableName  Name of the variable to compare to 'Variable'
> -  @param  VendorGuid    GUID of the variable to compare to 'Variable'
> -  @param  PtrTrack      Variable Track Pointer structure that contains Variable
> Information.
> -
> -  @retval EFI_SUCCESS    Found match variable
> -  @retval EFI_NOT_FOUND  Variable not found
> -
> -**/
> -EFI_STATUS
> -CompareWithValidVariable (
> -  IN  VARIABLE_STORE_INFO     *StoreInfo,
> -  IN  VARIABLE_HEADER         *Variable,
> -  IN  VARIABLE_HEADER         *VariableHeader,
> -  IN  CONST CHAR16            *VariableName,
> -  IN  CONST EFI_GUID          *VendorGuid,
> -  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> -  )
> -{
> -  VOID      *Point;
> -  EFI_GUID  *TempVendorGuid;
> -
> -  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
> -
> -  if (VariableName[0] == 0) {
> -    PtrTrack->CurrPtr = Variable;
> -    return EFI_SUCCESS;
> -  } else {
> -    //
> -    // Don't use CompareGuid function here for performance reasons.
> -    // Instead we compare the GUID a UINT32 at a time and branch
> -    // on the first failed comparison.
> -    //
> -    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> -        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> -        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> -        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> -        )
> -    {
> -      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> -      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> -      if (CompareVariableName (StoreInfo, VariableName, Point,
> NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> -        PtrTrack->CurrPtr = Variable;
> -        return EFI_SUCCESS;
> -      }
> -    }
> -  }
> -
> -  return EFI_NOT_FOUND;
> -}
> -
> -/**
> -  Get HOB variable store.
> -
> -  @param[out] StoreInfo             Return the store info.
> -  @param[out] VariableStoreHeader   Return variable store header.
> -
> -**/
> -VOID
> -GetHobVariableStore (
> -  OUT VARIABLE_STORE_INFO    *StoreInfo,
> -  OUT VARIABLE_STORE_HEADER  **VariableStoreHeader
> -  )
> -{
> -  EFI_HOB_GUID_TYPE  *GuidHob;
> -
> -  //
> -  // Make sure there is no more than one Variable HOB.
> -  //
> -  DEBUG_CODE_BEGIN ();
> -  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> -  if (GuidHob != NULL) {
> -    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB
> (GuidHob)) != NULL)) {
> -      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
> -      ASSERT (FALSE);
> -    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
> -      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable
> HOBs\n"));
> -      ASSERT (FALSE);
> -    }
> -  } else {
> -    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> -    if (GuidHob != NULL) {
> -      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) !=
> NULL)) {
> -        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
> -        ASSERT (FALSE);
> -      }
> -    }
> -  }
> -
> -  DEBUG_CODE_END ();
> -
> -  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> -  if (GuidHob != NULL) {
> -    *VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> -    StoreInfo->AuthFlag  = TRUE;
> -  } else {
> -    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> -    if (GuidHob != NULL) {
> -      *VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> -      StoreInfo->AuthFlag  = FALSE;
> -    }
> -  }
> -}
> -
> -/**
> -  Return the variable store header and the store info based on the Index.
> -
> -  @param Type       The type of the variable store.
> -  @param StoreInfo  Return the store info.
> -
> -  @return  Pointer to the variable store header.
> -**/
> -VARIABLE_STORE_HEADER *
> -GetVariableStore (
> -  IN VARIABLE_STORE_TYPE   Type,
> -  OUT VARIABLE_STORE_INFO  *StoreInfo
> -  )
> -{
> -  EFI_HOB_GUID_TYPE                     *GuidHob;
> -  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
> -  VARIABLE_STORE_HEADER                 *VariableStoreHeader;
> -  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
> -  UINT32                                NvStorageSize;
> -  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
> -  UINT32                                BackUpOffset;
> -
> -  StoreInfo->IndexTable       = NULL;
> -  StoreInfo->FtwLastWriteData = NULL;
> -  StoreInfo->AuthFlag         = FALSE;
> -  VariableStoreHeader         = NULL;
> -  switch (Type) {
> -    case VariableStoreTypeHob:
> -      GetHobVariableStore (StoreInfo, &VariableStoreHeader);
> -
> -      break;
> -
> -    case VariableStoreTypeNv:
> -      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> -        //
> -        // Emulated non-volatile variable mode is not enabled.
> -        //
> -
> -        NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> -        NvStorageBase = (EFI_PHYSICAL_ADDRESS)(PcdGet64
> (PcdFlashNvStorageVariableBase64) != 0 ?
> -                                               PcdGet64 (PcdFlashNvStorageVariableBase64) :
> -                                               PcdGet32 (PcdFlashNvStorageVariableBase)
> -                                               );
> -        ASSERT (NvStorageBase != 0);
> -
> -        //
> -        // First let FvHeader point to NV storage base.
> -        //
> -        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> -
> -        //
> -        // Check the FTW last write data hob.
> -        //
> -        BackUpOffset = 0;
> -        GuidHob      = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> -        if (GuidHob != NULL) {
> -          FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> -          if (FtwLastWriteData->TargetAddress == NvStorageBase) {
> -            //
> -            // Let FvHeader point to spare block.
> -            //
> -            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER
> *)(UINTN)FtwLastWriteData->SpareAddress;
> -            DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare
> block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
> -          } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
> (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
> -            StoreInfo->FtwLastWriteData = FtwLastWriteData;
> -            //
> -            // Flash NV storage from the offset is backed up in spare block.
> -            //
> -            BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress -
> NvStorageBase);
> -            DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from
> offset: %x is backed up in spare block: 0x%x\n", BackUpOffset,
> (UINTN)FtwLastWriteData->SpareAddress));
> -            //
> -            // At least one block data in flash NV storage is still valid, so still leave
> FvHeader point to NV storage base.
> -            //
> -          }
> -        }
> -
> -        //
> -        // Check if the Firmware Volume is not corrupted
> -        //
> -        if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid
> (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
> -          DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> -          break;
> -        }
> -
> -        VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader +
> FvHeader->HeaderLength);
> -
> -        StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader-
> >Signature, &gEfiAuthenticatedVariableGuid));
> -
> -        GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> -        if (GuidHob != NULL) {
> -          StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> -        } else {
> -          //
> -          // If it's the first time to access variable region in flash, create a guid hob
> to record
> -          // VAR_ADDED type variable info.
> -          // Note that as the resource of PEI phase is limited, only store the limited
> number of
> -          // VAR_ADDED type variables to reduce access time.
> -          //
> -          StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE *)BuildGuidHob
> (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> -          StoreInfo->IndexTable->Length      = 0;
> -          StoreInfo->IndexTable->StartPtr    = GetStartPointer
> (VariableStoreHeader);
> -          StoreInfo->IndexTable->EndPtr      = GetEndPointer (VariableStoreHeader);
> -          StoreInfo->IndexTable->GoneThrough = 0;
> -        }
> -      }
> -
> -      break;
> -
> -    default:
> -      ASSERT (FALSE);
> -      break;
> -  }
> -
> -  StoreInfo->VariableStoreHeader = VariableStoreHeader;
> -  return VariableStoreHeader;
> -}
> -
> -/**
> -  Get variable header that has consecutive content.
> -
> -  @param StoreInfo      Pointer to variable store info structure.
> -  @param Variable       Pointer to the Variable Header.
> -  @param VariableHeader Pointer to Pointer to the Variable Header that has
> consecutive content.
> -
> -  @retval TRUE          Variable header is valid.
> -  @retval FALSE         Variable header is not valid.
> -
> -**/
> -BOOLEAN
> -GetVariableHeader (
> -  IN VARIABLE_STORE_INFO  *StoreInfo,
> -  IN VARIABLE_HEADER      *Variable,
> -  OUT VARIABLE_HEADER     **VariableHeader
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS  TargetAddress;
> -  EFI_PHYSICAL_ADDRESS  SpareAddress;
> -  EFI_HOB_GUID_TYPE     *GuidHob;
> -  UINTN                 PartialHeaderSize;
> -
> -  if (Variable == NULL) {
> -    return FALSE;
> -  }
> -
> -  //
> -  // First assume variable header pointed by Variable is consecutive.
> -  //
> -  *VariableHeader = Variable;
> -
> -  if (StoreInfo->FtwLastWriteData != NULL) {
> -    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> -    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> -    if (((UINTN)Variable > (UINTN)SpareAddress) &&
> -        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> -    {
> -      //
> -      // Reach the end of variable store.
> -      //
> -      return FALSE;
> -    }
> -
> -    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> -      //
> -      // Variable header pointed by Variable is inconsecutive,
> -      // create a guid hob to combine the two partial variable header content
> together.
> -      //
> -      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> -      if (GuidHob != NULL) {
> -        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
> -      } else {
> -        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid,
> GetVariableHeaderSize (StoreInfo->AuthFlag));
> -        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> -        //
> -        // Partial content is in NV storage.
> -        //
> -        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> PartialHeaderSize);
> -        //
> -        // Another partial content is in spare block.
> -        //
> -        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> PartialHeaderSize);
> -      }
> -    }
> -  } else {
> -    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> -      //
> -      // Reach the end of variable store.
> -      //
> -      return FALSE;
> -    }
> -  }
> -
> -  return IsValidVariableHeader (*VariableHeader);
> -}
> -
> -/**
> -  Get variable name or data to output buffer.
> -
> -  @param  StoreInfo     Pointer to variable store info structure.
> -  @param  NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> -  @param  Size          Variable name/data size.
> -  @param  Buffer        Pointer to output buffer to hold the variable name/data.
> -
> -**/
> -VOID
> -GetVariableNameOrData (
> -  IN VARIABLE_STORE_INFO  *StoreInfo,
> -  IN UINT8                *NameOrData,
> -  IN UINTN                Size,
> -  OUT UINT8               *Buffer
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS  TargetAddress;
> -  EFI_PHYSICAL_ADDRESS  SpareAddress;
> -  UINTN                 PartialSize;
> -
> -  if (StoreInfo->FtwLastWriteData != NULL) {
> -    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> -    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> -    if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> -      //
> -      // Variable name/data is inconsecutive.
> -      //
> -      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> -      //
> -      // Partial content is in NV storage.
> -      //
> -      CopyMem (Buffer, NameOrData, PartialSize);
> -      //
> -      // Another partial content is in spare block.
> -      //
> -      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> PartialSize);
> -      return;
> -    }
> -  }
> -
> -  //
> -  // Variable name/data is consecutive.
> -  //
> -  CopyMem (Buffer, NameOrData, Size);
> -}
> -
>  /**
>    Find the variable in the specified variable store.
> 
> @@ -1246,3 +522,107 @@ PeiGetNextVariableName (
>      }
>    }
>  }
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get variable data through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid,
> Attributes, DataSize, Data);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize,
> Data);
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get next variable through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName,
> VariableGuid);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetNextVariableName (This, VariableNameSize, VariableName,
> VariableGuid);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> new file mode 100644
> index 000000000000..2d605d39cbb6
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> @@ -0,0 +1,941 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Variable.h"
> +#include "VariableStore.h"
> +
> +/**
> +
> +  Gets the pointer to the first variable header in given variable store area.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the first variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetStartPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  )
> +{
> +  //
> +  // The start of variable store
> +  //
> +  return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
> +}
> +
> +/**
> +
> +  Gets the pointer to the end of the variable storage area.
> +
> +  This function gets pointer to the end of the variable storage
> +  area, according to the input variable store header.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the end of the variable storage area.
> +
> +**/
> +VARIABLE_HEADER *
> +GetEndPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  )
> +{
> +  //
> +  // The end of variable store
> +  //
> +  return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader +
> VarStoreHeader->Size);
> +}
> +
> +/**
> +  This code checks if variable header is valid or not.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +
> +  @retval TRUE      Variable header is valid.
> +  @retval FALSE     Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> +  IN  VARIABLE_HEADER  *Variable
> +  )
> +{
> +  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  This code gets the size of variable header.
> +
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> +  IN  BOOLEAN  AuthFlag
> +  )
> +{
> +  UINTN  Value;
> +
> +  if (AuthFlag) {
> +    Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
> +  } else {
> +    Value = sizeof (VARIABLE_HEADER);
> +  }
> +
> +  return Value;
> +}
> +
> +/**
> +  This code gets the size of name of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    if ((AuthVariable->State == (UINT8)(-1)) ||
> +        (AuthVariable->DataSize == (UINT32)(-1)) ||
> +        (AuthVariable->NameSize == (UINT32)(-1)) ||
> +        (AuthVariable->Attributes == (UINT32)(-1)))
> +    {
> +      return 0;
> +    }
> +
> +    return (UINTN)AuthVariable->NameSize;
> +  } else {
> +    if ((Variable->State == (UINT8)(-1)) ||
> +        (Variable->DataSize == (UINT32)(-1)) ||
> +        (Variable->NameSize == (UINT32)(-1)) ||
> +        (Variable->Attributes == (UINT32)(-1)))
> +    {
> +      return 0;
> +    }
> +
> +    return (UINTN)Variable->NameSize;
> +  }
> +}
> +
> +/**
> +  This code gets the size of data of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    if ((AuthVariable->State == (UINT8)(-1)) ||
> +        (AuthVariable->DataSize == (UINT32)(-1)) ||
> +        (AuthVariable->NameSize == (UINT32)(-1)) ||
> +        (AuthVariable->Attributes == (UINT32)(-1)))
> +    {
> +      return 0;
> +    }
> +
> +    return (UINTN)AuthVariable->DataSize;
> +  } else {
> +    if ((Variable->State == (UINT8)(-1)) ||
> +        (Variable->DataSize == (UINT32)(-1)) ||
> +        (Variable->NameSize == (UINT32)(-1)) ||
> +        (Variable->Attributes == (UINT32)(-1)))
> +    {
> +      return 0;
> +    }
> +
> +    return (UINTN)Variable->DataSize;
> +  }
> +}
> +
> +/**
> +  This code gets the pointer to the variable name.
> +
> +  @param[in]   Variable  Pointer to the Variable Header.
> +  @param[in]   AuthFlag  Authenticated variable flag.
> +
> +  @return  A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  )
> +{
> +  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> +}
> +
> +/**
> +  This code gets the pointer to the variable guid.
> +
> +  @param[in] Variable   Pointer to the Variable Header.
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    return &AuthVariable->VendorGuid;
> +  } else {
> +    return &Variable->VendorGuid;
> +  }
> +}
> +
> +/**
> +  This code gets the pointer to the variable data.
> +
> +  @param[in]   Variable         Pointer to the Variable Header.
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]   AuthFlag         Authenticated variable flag.
> +
> +  @return  A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  VARIABLE_HEADER  *VariableHeader,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  UINTN  Value;
> +
> +  //
> +  // Be careful about pad size for alignment
> +  //
> +  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> +  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> +  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> +
> +  return (UINT8 *)Value;
> +}
> +
> +/**
> +  This code gets the pointer to the next variable header.
> +
> +  @param[in]  StoreInfo         Pointer to variable store info structure.
> +  @param[in]  Variable          Pointer to the Variable Header.
> +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> +
> +  @return  A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> +  IN  VARIABLE_HEADER      *Variable,
> +  IN  VARIABLE_HEADER      *VariableHeader
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 Value;
> +
> +  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> >AuthFlag);
> +  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> +  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> >AuthFlag));
> +  //
> +  // Be careful about pad size for alignment
> +  //
> +  Value = HEADER_ALIGN (Value);
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> (UINTN)TargetAddress)) {
> +      //
> +      // Next variable is in spare block.
> +      //
> +      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> +    }
> +  }
> +
> +  return (VARIABLE_HEADER *)Value;
> +}
> +
> +/**
> +  Compare two variable names, one of them may be inconsecutive.
> +
> +  @param[in] StoreInfo      Pointer to variable store info structure.
> +  @param[in] Name1          Pointer to one variable name.
> +  @param[in] Name2          Pointer to another variable name.
> +  @param[in] NameSize       Variable name size.
> +
> +  @retval TRUE          Name1 and Name2 are identical.
> +  @retval FALSE         Name1 and Name2 are not identical.
> +
> +**/
> +BOOLEAN
> +CompareVariableName (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN CONST CHAR16         *Name1,
> +  IN CONST CHAR16         *Name2,
> +  IN UINTN                NameSize
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 PartialNameSize;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> NameSize) > (UINTN)TargetAddress)) {
> +      //
> +      // Name1 is inconsecutive.
> +      //
> +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) ==
> 0) {
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> +          return TRUE;
> +        }
> +      }
> +
> +      return FALSE;
> +    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> NameSize) > (UINTN)TargetAddress)) {
> +      //
> +      // Name2 is inconsecutive.
> +      //
> +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) ==
> 0) {
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> +          return TRUE;
> +        }
> +      }
> +
> +      return FALSE;
> +    }
> +  }
> +
> +  //
> +  // Both Name1 and Name2 are consecutive.
> +  //
> +  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  This function compares a variable with variable entries in database.
> +
> +  @param[in]   StoreInfo        Pointer to variable store info structure.
> +  @param[in]   Variable         Pointer to the variable in our database
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> +                                consecutive content.
> +  @param[in]   VariableName     Name of the variable to compare to 'Variable'
> +  @param[in]   VendorGuid       GUID of the variable to compare to 'Variable'
> +  @param[out]  PtrTrack         Variable Track Pointer structure that contains
> +                                Variable Information.
> +
> +  @retval EFI_SUCCESS    Found match variable
> +  @retval EFI_NOT_FOUND  Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> +  IN  VARIABLE_HEADER         *Variable,
> +  IN  VARIABLE_HEADER         *VariableHeader,
> +  IN  CONST CHAR16            *VariableName,
> +  IN  CONST EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  )
> +{
> +  VOID      *Point;
> +  EFI_GUID  *TempVendorGuid;
> +
> +  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
> +
> +  if (VariableName[0] == 0) {
> +    PtrTrack->CurrPtr = Variable;
> +    return EFI_SUCCESS;
> +  } else {
> +    //
> +    // Don't use CompareGuid function here for performance reasons.
> +    // Instead we compare the GUID a UINT32 at a time and branch
> +    // on the first failed comparison.
> +    //
> +    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> +        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> +        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> +        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> +        )
> +    {
> +      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> +      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> +      if (CompareVariableName (StoreInfo, VariableName, Point,
> NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> +        PtrTrack->CurrPtr = Variable;
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get variable header that has consecutive content.
> +
> +  @param[in]  StoreInfo       Pointer to variable store info structure.
> +  @param[in]  Variable        Pointer to the Variable Header.
> +  @param[out] VariableHeader  Pointer to Pointer to the Variable Header
> +                              that has consecutive content.
> +
> +  @retval TRUE          Variable header is valid.
> +  @retval FALSE         Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN VARIABLE_HEADER      *Variable,
> +  OUT VARIABLE_HEADER     **VariableHeader
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  EFI_HOB_GUID_TYPE     *GuidHob;
> +  UINTN                 PartialHeaderSize;
> +
> +  if (Variable == NULL) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // First assume variable header pointed by Variable is consecutive.
> +  //
> +  *VariableHeader = Variable;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Variable > (UINTN)SpareAddress) &&
> +        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> +    {
> +      //
> +      // Reach the end of variable store.
> +      //
> +      return FALSE;
> +    }
> +
> +    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> +      //
> +      // Variable header pointed by Variable is inconsecutive,
> +      // create a guid hob to combine the two partial variable header content
> together.
> +      //
> +      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> +      if (GuidHob != NULL) {
> +        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA
> (GuidHob);
> +      } else {
> +        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob
> (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
> +        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> +        //
> +        // Partial content is in NV storage.
> +        //
> +        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> PartialHeaderSize);
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> PartialHeaderSize);
> +      }
> +    }
> +  } else {
> +    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> +      //
> +      // Reach the end of variable store.
> +      //
> +      return FALSE;
> +    }
> +  }
> +
> +  return IsValidVariableHeader (*VariableHeader);
> +}
> +
> +/**
> +  Get variable name or data to output buffer.
> +
> +  @param[in]   StoreInfo     Pointer to variable store info structure.
> +  @param[in]   NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> +  @param[in]   Size          Variable name/data size.
> +  @param[out]  Buffer        Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN UINT8                *NameOrData,
> +  IN UINTN                Size,
> +  OUT UINT8               *Buffer
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 PartialSize;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> +      //
> +      // Variable name/data is inconsecutive.
> +      //
> +      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      CopyMem (Buffer, NameOrData, PartialSize);
> +      //
> +      // Another partial content is in spare block.
> +      //
> +      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> PartialSize);
> +      return;
> +    }
> +  }
> +
> +  //
> +  // Variable name/data is consecutive.
> +  //
> +  CopyMem (Buffer, NameOrData, Size);
> +}
> +
> +/**
> +
> +  Internal function to retrieve variable information.
> +
> +  @param[in,out] VariableInfo     Pointer to variable information.
> +  @param[in]     StoreInfo        Pointer to store copy of variable (optional).
> +  @param[in]     VariablePtr      Pointer to variable buffer.
> +  @param[in]     VariableHeader   Pointer to variable header.
> +
> +  @retval EFI_INVALID_PARAMETER  One ore more required parameters are
> NULL.
> +  @retval EFI_BUFFER_TOO_SMALL   Given buffer is too small to hold data.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfoInternal (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo,
> +  IN      VARIABLE_STORE_INFO      *StoreInfo OPTIONAL,
> +  IN      VARIABLE_HEADER          *VariablePtr,
> +  IN      VARIABLE_HEADER          *VariableHeader
> +  )
> +{
> +  VARIABLE_HEADER                *VariableBuffer;
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariableHeader;
> +  UINTN                          NameSize;
> +  UINTN                          DataSize;
> +  UINTN                          VariableSize;
> +
> +  if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader ==
> NULL)) {
> +    ASSERT (VariableInfo != NULL);
> +    ASSERT (VariablePtr != NULL);
> +    ASSERT (VariableHeader != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  VariableBuffer = VariableInfo->Buffer;
> +
> +  //
> +  // Make a copy of the whole variable if VariableInfo->Buffer is given. But
> +  // don't do this if StoreInfo is not given, because VariableInfo->Buffer
> +  // has already hold a copy of variable in such situation.
> +  //
> +  NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> +  DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> +  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
> +    if (StoreInfo != NULL) {
> +      CopyMem (
> +        VariableBuffer,
> +        VariableHeader,
> +        GetVariableHeaderSize (VariableInfo->Flags.Auth)
> +        );
> +      GetVariableNameOrData (
> +        StoreInfo,
> +        (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> +        NameSize,
> +        (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
> +        );
> +      GetVariableNameOrData (
> +        StoreInfo,
> +        (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo-
> >Flags.Auth),
> +        DataSize,
> +        (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader,
> VariableInfo->Flags.Auth)
> +        );
> +    } else {
> +      //
> +      // Suppose the variable is in consecutive space.
> +      //
> +      VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
> +                     + NameSize + GET_PAD_SIZE (NameSize)
> +                     + DataSize;
> +      CopyMem (VariableBuffer, VariablePtr, VariableSize);
> +    }
> +  }
> +
> +  //
> +  // Generally, if no consecutive buffer passed in, don't return back any data.
> +  //
> +  // If follow pointers are NULL, return back pointers to following data inside
> +  // VariableInfo->Buffer, if it's given.
> +  //
> +  //  VariableInfo->Header.VariableName
> +  //  VariableInfo->Header.Data
> +  //  VariableInfo->Header.VendorGuid
> +  //  VariableInfo->Header.TimeStamp
> +  //
> +  // Otherwise, suppose they're buffers used to hold a copy of corresponding
> +  // data.
> +  //
> +  //
> +
> +  //
> +  // AuthVariable header
> +  //
> +  if (VariableInfo->Flags.Auth) {
> +    AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableHeader;
> +
> +    VariableInfo->Header.State          = AuthVariableHeader->State;
> +    VariableInfo->Header.Attributes     = AuthVariableHeader->Attributes;
> +    VariableInfo->Header.PubKeyIndex    = AuthVariableHeader->PubKeyIndex;
> +    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
> +                                            &(AuthVariableHeader->MonotonicCount)
> +                                            );
> +    if (VariableInfo->Header.TimeStamp != NULL) {
> +      CopyMem (
> +        VariableInfo->Header.TimeStamp,
> +        &AuthVariableHeader->TimeStamp,
> +        sizeof (EFI_TIME)
> +        );
> +    } else if (VariableBuffer != NULL) {
> +      AuthVariableHeader             = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableBuffer;
> +      VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
> +    }
> +  } else {
> +    VariableInfo->Header.State          = VariableHeader->State;
> +    VariableInfo->Header.Attributes     = VariableHeader->Attributes;
> +    VariableInfo->Header.PubKeyIndex    = 0;
> +    VariableInfo->Header.MonotonicCount = 0;
> +    VariableInfo->Header.TimeStamp      = NULL;
> +  }
> +
> +  //
> +  // VendorGuid
> +  //
> +  if (VariableInfo->Header.VendorGuid != NULL) {
> +    CopyGuid (
> +      VariableInfo->Header.VendorGuid,
> +      GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.VendorGuid
> +      = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
> +  }
> +
> +  //
> +  // VariableName
> +  //
> +  if (  (VariableInfo->Header.VariableName != NULL)
> +     && (VariableInfo->Header.NameSize >= NameSize))
> +  {
> +    GetVariableNameOrData (
> +      StoreInfo,
> +      (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> +      NameSize,
> +      (UINT8 *)VariableInfo->Header.VariableName
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.VariableName
> +      = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
> +  } else if (VariableInfo->Header.VariableName != NULL) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  //
> +  // Data
> +  //
> +  if (  (VariableInfo->Header.Data != NULL)
> +     && (VariableInfo->Header.DataSize >= DataSize))
> +  {
> +    GetVariableNameOrData (
> +      StoreInfo,
> +      GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
> +      DataSize,
> +      VariableInfo->Header.Data
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.Data
> +      = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo-
> >Flags.Auth);
> +  } else if (VariableInfo->Header.Data != NULL) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  //
> +  // Update size information about name & data.
> +  //
> +  VariableInfo->Header.NameSize = NameSize;
> +  VariableInfo->Header.DataSize = DataSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Retrieve details about a variable, given by VariableInfo->Buffer or
> +  VariableInfo->Index, and pass the details back in VariableInfo->Header.
> +
> +  This function is used to resolve the variable data structure into
> +  VariableInfo->Header, for easier access later without revisiting the variable
> +  data in variable store. If pointers in the structure of VariableInfo->Header
> +  are not NULL, it's supposed that they are buffers passed in to hold a copy of
> +  data of corresponding data fields in variable data structure. Otherwise, this
> +  function simply returns pointers pointing to address of those data fields.
> +
> +  The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
> +  If VariableInfo->Index is given, this function finds the corresponding variable
> +  first from variable storage according to the Index.
> +
> +  If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
> +  that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
> +  requested variable data to be returned.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Buffer
> +                                 and VariableInfo->Index are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Buffer or Index is out of range of
> +                                 any given or internal storage copies.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  )
> +{
> +  VARIABLE_HEADER      *VariablePtr;
> +  VARIABLE_HEADER      *VariableHeader;
> +  VARIABLE_STORE_TYPE  StoreType;
> +  VARIABLE_STORE_INFO  StoreInfo;
> +  UINTN                Offset;
> +
> +  if ((VariableInfo == NULL) ||
> +      ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex ==
> VAR_INDEX_INVALID)))
> +  {
> +    ASSERT (VariableInfo != NULL);
> +    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo-
> >Buffer != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  StoreInfo.VariableStoreHeader = NULL;
> +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> +    GetVariableStore (StoreType, &StoreInfo);
> +    if (StoreInfo.VariableStoreHeader != NULL) {
> +      break;
> +    }
> +  }
> +
> +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> +  //
> +  // No StoreIndex? Don't retrieve variable information from store but just from
> +  // VariableInfo->Buffer.
> +  //
> +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> +    VariablePtr    = VariableInfo->Buffer;
> +    VariableHeader = VariablePtr;
> +
> +    return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr,
> VariableHeader);
> +  }
> +
> +  Offset = (UINTN)VariableInfo->StoreIndex;
> +  if (  (StoreInfo.FtwLastWriteData != NULL)
> +     && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                    - (UINTN)StoreInfo.VariableStoreHeader)))
> +  {
> +    Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +               - (UINTN)StoreInfo.VariableStoreHeader);
> +    VariablePtr = (VARIABLE_HEADER *)
> +                  ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> +  } else {
> +    VariablePtr = (VARIABLE_HEADER *)
> +                  ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> +  }
> +
> +  //
> +  // Note that variable might be in unconsecutive space. Always get a copy
> +  // of its header in consecutive buffer.
> +  //
> +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within VariableStore.
> +
> +  If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
> +  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
> +  @retval EFI_SUCCESS            The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  )
> +{
> +  VARIABLE_HEADER      *VariablePtr;
> +  VARIABLE_HEADER      *VariableHeader;
> +  VARIABLE_STORE_INFO  StoreInfo;
> +  VARIABLE_STORE_TYPE  StoreType;
> +  UINTN                Offset;
> +
> +  if (VariableInfo == NULL) {
> +    ASSERT (VariableInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  StoreInfo.VariableStoreHeader = NULL;
> +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> +    GetVariableStore (StoreType, &StoreInfo);
> +    if (StoreInfo.VariableStoreHeader != NULL) {
> +      break;
> +    }
> +  }
> +
> +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> +  //
> +  // VariableInfo->StoreIndex is supposed to be the index to variable found
> +  // last time. Use it to get the variable next to it in store. If it's invalid,
> +  // return the first variable available in store.
> +  //
> +  VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
> +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> +    VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
> +  } else {
> +    Offset = (UINTN)VariableInfo->StoreIndex;
> +    if (  (StoreInfo.FtwLastWriteData != NULL)
> +       && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                      - (UINTN)StoreInfo.VariableStoreHeader)))
> +    {
> +      Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                 - (UINTN)StoreInfo.VariableStoreHeader);
> +      VariablePtr = (VARIABLE_HEADER *)
> +                    ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> +    } else {
> +      VariablePtr = (VARIABLE_HEADER *)
> +                    ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> +    }
> +
> +    //
> +    // Note that variable might be in unconsecutive space. Always get a copy
> +    // of its header in consecutive buffer.
> +    //
> +    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
> +  }
> +
> +  //
> +  // Get a copy of variable header in consecutive buffer.
> +  //
> +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Use the offset to the start of variable store as index of the variable.
> +  //
> +  if (  (StoreInfo.FtwLastWriteData == NULL)
> +     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData-
> >TargetAddress))
> +  {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
> +  } else {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                 - (UINTN)StoreInfo.VariableStoreHeader);
> +    VariableInfo->StoreIndex
> +      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData-
> >SpareAddress);
> +  }
> +
> +  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
> +    VariableInfo->Buffer = VariablePtr;
> +  }
> +
> +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> new file mode 100644
> index 000000000000..72bd17a43048
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> @@ -0,0 +1,305 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  )
> +{
> +  if ((CompareGuid (&VarStoreHeader->Signature,
> &gEfiAuthenticatedVariableGuid) ||
> +       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
> +      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
> +      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
> +      )
> +  {
> +    return EfiValid;
> +  }
> +
> +  if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
> +      (VarStoreHeader->Size == 0xffffffff) &&
> +      (VarStoreHeader->Format == 0xff) &&
> +      (VarStoreHeader->State == 0xff)
> +      )
> +  {
> +    return EfiRaw;
> +  } else {
> +    return EfiInvalid;
> +  }
> +}
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +  VOID               *VariableStoreInfoHob;
> +
> +  //
> +  // Discover if Variable Store Info Hob has been published by platform driver.
> +  // It contains information regards to HOB or NV Variable Store availability
> +  //
> +  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
> +  if (GuidHob == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  //
> +  // Check if HOB Variable Store is available
> +  //
> +  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
> +  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {

[JianJW]
What's the scenario in which *(BOOLEAN *)VariableStoreInfoHob equals FALSE?
Which case the VariableStoreInfoHob is generated but HOB variable store available?
Is it possible to simply use VariableStoreDiscoveredPpi notify callback only? Then
you can just check HOB(gEfiAuthenticatedVariableGuid) or HOB(gEfiVariableGuid)
to confirm if the HOB version of variable store is available now.

> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // This might be NV Variable Store
> +  //
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  //
> +  // Make sure there is no more than one Variable HOB.
> +  //
> +  DEBUG_CODE_BEGIN ();
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob != NULL) {
> +    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB
> (GuidHob)) != NULL)) {
> +      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
> +      ASSERT (FALSE);
> +    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
> +      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable
> HOBs\n"));
> +      ASSERT (FALSE);
> +    }
> +  } else {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) !=
> NULL)) {
> +        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
> +        ASSERT (FALSE);
> +      }
> +    }
> +  }
> +
> +  DEBUG_CODE_END ();
> +
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob != NULL) {
> +    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +    StoreInfo->AuthFlag            = TRUE;
> +  } else {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +      StoreInfo->AuthFlag            = FALSE;
> +    }
> +  }
> +}
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableFvHeader      Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  )
> +{
> +  EFI_HOB_GUID_TYPE                     *GuidHob;
> +  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
> +  VARIABLE_STORE_HEADER                 *StoreHeader;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
> +  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
> +  UINT32                                NvStorageSize;
> +  UINT32                                BackUpOffset;
> +
> +  NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> +  NvStorageBase = (EFI_PHYSICAL_ADDRESS)
> +                  (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0)
> +                  ? PcdGet64 (PcdFlashNvStorageVariableBase64)
> +                  : PcdGet32 (PcdFlashNvStorageVariableBase);
> +  ASSERT (NvStorageBase != 0);
> +
> +  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> +
> +  //
> +  // Check the FTW last write data hob.
> +  //
> +  BackUpOffset     = 0;
> +  FtwLastWriteData = NULL;
> +  HobData          = NULL;
> +  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> +
> +  if (GuidHob != NULL) {
> +    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> +    if (HobData->TargetAddress == NvStorageBase) {
> +      //
> +      // Let FvHeader point to spare block.
> +      //
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
> +        (UINTN)HobData->SpareAddress
> +        ));
> +
> +      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData-
> >SpareAddress;
> +      HobData  = NULL;
> +    } else if ((HobData->TargetAddress > NvStorageBase) &&
> +               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
> +    {
> +      //
> +      // Flash NV storage from the offset is backed up in spare block.
> +      //
> +      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: High partial NV storage from offset: %x is backed up in spare
> block: 0x%x\n",
> +        BackUpOffset,
> +        (UINTN)FtwLastWriteData->SpareAddress
> +        ));
> +      //
> +      // At least one block data in flash NV storage is still valid, so still
> +      // leave FvHeader point to NV storage base.
> +      //
> +    }
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->FtwLastWriteData = HobData;
> +  }
> +
> +  if (VariableFvHeader != NULL) {
> +    *VariableFvHeader = FvHeader;
> +  }
> +
> +  //
> +  // Check if the Firmware Volume is not corrupted
> +  //
> +  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
> +      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))

[JianJW] It'd be better also validate the FvHeader->HeaderLength, to make sure
StoreHeader is in the valid area.

> +  {
> +    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader-
> >HeaderLength);
> +  } else {
> +    StoreHeader = NULL;
> +    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->VariableStoreHeader = StoreHeader;
> +    if (StoreHeader != NULL) {
> +      StoreInfo->AuthFlag = CompareGuid (
> +                              &StoreHeader->Signature,
> +                              &gEfiAuthenticatedVariableGuid
> +                              );
> +    }
> +  }
> +}
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  StoreInfo->VariableStoreHeader = NULL;
> +  StoreInfo->IndexTable          = NULL;
> +  StoreInfo->FtwLastWriteData    = NULL;
> +  StoreInfo->AuthFlag            = FALSE;
> +  switch (Type) {
> +    case VariableStoreTypeHob:
> +      GetHobVariableStore (StoreInfo);
> +      break;
> +
> +    case VariableStoreTypeNv:
> +      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> +        //
> +        // Emulated non-volatile variable mode is not enabled.
> +        //
> +        GetNvVariableStore (StoreInfo, NULL);
> +        if (StoreInfo->VariableStoreHeader != NULL) {
> +          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> +          if (GuidHob != NULL) {
> +            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> +          } else {
> +            //
> +            // If it's the first time to access variable region in flash, create a guid hob
> to record
> +            // VAR_ADDED type variable info.
> +            // Note that as the resource of PEI phase is limited, only store the
> limited number of
> +            // VAR_ADDED type variables to reduce access time.
> +            //
> +            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE
> *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> +            StoreInfo->IndexTable->Length      = 0;
> +            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->GoneThrough = 0;
> +          }
> +        }
> +      }
> +
> +      break;
> +
> +    default:
> +      ASSERT (FALSE);
> +      break;
> +  }
> +
> +  return StoreInfo->VariableStoreHeader;
> +}
> --
> 2.35.1.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#89931): https://edk2.groups.io/g/devel/message/89931
Mute This Topic: https://groups.io/mt/90781893/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-