[edk2-devel] [PATCH v4 07/28] MdeModulePkg: Add new Variable functionality

Judah Vang judah.vang at intel.com
Thu Aug 11 06:53:16 UTC 2022


REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594

V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
and SafeUint64ToUint32().

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

Cc: Jian J Wang <jian.j.wang at intel.com>
Cc: Liming Gao <gaoliming at byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu at intel.com>
Cc: Nishant C Mistry <nishant.c.mistry at intel.com>
Signed-off-by: Jian J Wang <jian.j.wang at intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry at intel.com>
Signed-off-by: Judah Vang <judah.vang at intel.com>
Acked-by: Hao A Wu <hao.a.wu at 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        | 890 +++---------------
 MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 ++++++++++++++++++++
 MdeModulePkg/Universal/Variable/Pei/VariableStore.c   | 307 +++++++
 7 files changed, 1893 insertions(+), 760 deletions(-)

diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
index 7264a24bdf71..0945b4dec435 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
@@ -41,6 +45,7 @@ [LibraryClasses]
   PeiServicesLib
   SafeIntLib
   VariableFlashInfoLib
+  ProtectedVariableLib
 
 [Guids]
   ## CONSUMES             ## GUID # Variable store header
@@ -58,7 +63,8 @@ [Guids]
   gEdkiiFaultTolerantWriteGuid
 
 [Ppis]
-  gEfiPeiReadOnlyVariable2PpiGuid   ## PRODUCES
+  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
+  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h
index 51effbf79987..8c79ff850b38 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
 
 **/
@@ -22,11 +22,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Library/PeiServicesLib.h>
 #include <Library/SafeIntLib.h>
 #include <Library/VariableFlashInfoLib.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,
@@ -144,4 +146,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 26a4c73b45a5..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,763 +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_STATUS                            Status;
-  EFI_HOB_GUID_TYPE                     *GuidHob;
-  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
-  VARIABLE_STORE_HEADER                 *VariableStoreHeader;
-  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
-  UINT32                                NvStorageSize;
-  UINT64                                NvStorageSize64;
-  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.
-        //
-
-        Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);
-        ASSERT_EFI_ERROR (Status);
-
-        Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);
-        // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
-        ASSERT_EFI_ERROR (Status);
-
-        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.
 
@@ -1250,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..75edc3fc5051
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
@@ -0,0 +1,307 @@
+/** @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_STATUS                            Status;
+  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;
+  UINT64                                NvStorageSize64;
+
+  Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);
+  // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
+  ASSERT_EFI_ERROR (Status);
+
+  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 (#92351): https://edk2.groups.io/g/devel/message/92351
Mute This Topic: https://groups.io/mt/92953532/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list