public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Judah Vang" <judah.vang@intel.com>
To: devel@edk2.groups.io
Cc: Jian J Wang <jian.j.wang@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Hao A Wu <hao.a.wu@intel.com>,
	Nishant C Mistry <nishant.c.mistry@intel.com>
Subject: [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
Date: Sun,  6 Nov 2022 00:34:57 -0700	[thread overview]
Message-ID: <20221106073509.3071-8-judah.vang@intel.com> (raw)
In-Reply-To: <20221106073509.3071-1-judah.vang@intel.com>

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

V5: Add PEI Variable Protection into a new directory and leave the
existing PEI Variable unchanged.

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Acked-by: Hao A Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf      |  79 ++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h           | 225 +++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h    | 309 +++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h      | 116 +++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c           | 628 +++++++++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c    | 941 ++++++++++++++++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c      | 307 +++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni      |  16 +
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni |  14 +
 9 files changed, 2635 insertions(+)

diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
new file mode 100644
index 000000000000..953a7c6b884f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
@@ -0,0 +1,79 @@
+## @file
+#  Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+#  This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PeiVariable
+  MODULE_UNI_FILE                = PeiVariable.uni
+  FILE_GUID                      = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PeimInitializeVariableServices
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  Variable.c
+  Variable.h
+  VariableStore.c
+  VariableStore.h
+  VariableParsing.c
+  VariableParsing.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  PcdLib
+  HobLib
+  PeimEntryPoint
+  DebugLib
+  PeiServicesTablePointerLib
+  PeiServicesLib
+  SafeIntLib
+  VariableFlashInfoLib
+  ProtectedVariableLib
+
+[Guids]
+  ## CONSUMES             ## GUID # Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiAuthenticatedVariableGuid
+  ## SOMETIMES_CONSUMES   ## GUID # Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiVariableGuid
+  ## SOMETIMES_PRODUCES   ## HOB
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiVariableIndexTableGuid
+  gEfiSystemNvDataFvGuid            ## SOMETIMES_CONSUMES   ## GUID
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## CONSUMES             ## GUID # Dependence
+  gEdkiiFaultTolerantWriteGuid
+
+[Ppis]
+  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
+  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
+
+[Depex]
+  gEdkiiFaultTolerantWriteGuid
+
+# [BootMode]
+# RECOVERY_FULL             ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PeiVariableExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
new file mode 100644
index 000000000000..1bdbdd2b807b
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
@@ -0,0 +1,225 @@
+/** @file
+  The internal header file includes the common header files, defines
+  internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_H_
+#define PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#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,
+  VariableStoreTypeNv,
+  VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+  VARIABLE_STORE_HEADER                   *VariableStoreHeader;
+  VARIABLE_INDEX_TABLE                    *IndexTable;
+  //
+  // If it is not NULL, it means there may be an inconsecutive variable whose
+  // partial content is still in NV storage, but another partial content is backed up
+  // in spare block.
+  //
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;
+  BOOLEAN                                 AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+
+/**
+  Provide the functionality of the variable services.
+
+  @param  FileHandle  Handle of the file being invoked.
+                      Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+  @param  PeiServices  General purpose services available to every PEIM.
+
+  @retval EFI_SUCCESS  If the interface could be successfully installed
+  @retval Others       Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  );
+
+/**
+  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
+PeiGetVariable (
+  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
+PeiGetNextVariableName (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  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/Protected/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
new file mode 100644
index 000000000000..d7af6cb6e8be
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/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/Protected/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
new file mode 100644
index 000000000000..6e2f6f939bab
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/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/Protected/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
new file mode 100644
index 000000000000..ce790946626e
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
@@ -0,0 +1,628 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+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 = {
+  PeiGetVariableEx,
+  PeiGetNextVariableNameEx
+};
+
+EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiPeiReadOnlyVariable2PpiGuid,
+  &mVariablePpi
+};
+
+/**
+  Provide the functionality of the variable services.
+
+  @param  FileHandle   Handle of the file being invoked.
+                       Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+  @param  PeiServices  General purpose services available to every PEIM.
+
+  @retval EFI_SUCCESS  If the interface could be successfully installed
+  @retval Others       Returned from PeiServicesInstallPpi()
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  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);
+}
+
+/**
+  Find the variable in the specified variable store.
+
+  @param  StoreInfo           Pointer to the store info structure.
+  @param  VariableName        Name of the variable to be found
+  @param  VendorGuid          Vendor GUID to be found.
+  @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.
+
+  @retval  EFI_SUCCESS            Variable found successfully
+  @retval  EFI_NOT_FOUND          Variable not found
+  @retval  EFI_INVALID_PARAMETER  Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableEx (
+  IN VARIABLE_STORE_INFO      *StoreInfo,
+  IN CONST CHAR16             *VariableName,
+  IN CONST EFI_GUID           *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  )
+{
+  VARIABLE_HEADER        *Variable;
+  VARIABLE_HEADER        *LastVariable;
+  VARIABLE_HEADER        *MaxIndex;
+  UINTN                  Index;
+  UINTN                  Offset;
+  BOOLEAN                StopRecord;
+  VARIABLE_HEADER        *InDeletedVariable;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader;
+  VARIABLE_INDEX_TABLE   *IndexTable;
+  VARIABLE_HEADER        *VariableHeader;
+
+  VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+  if (VariableStoreHeader == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (~VariableStoreHeader->Size == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  IndexTable         = StoreInfo->IndexTable;
+  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+  PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
+
+  InDeletedVariable = NULL;
+
+  //
+  // No Variable Address equals zero, so 0 as initial value is safe.
+  //
+  MaxIndex       = NULL;
+  VariableHeader = NULL;
+
+  if (IndexTable != NULL) {
+    //
+    // traverse the variable index table to look for varible.
+    // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
+    //
+    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
+      ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
+      Offset  += IndexTable->Index[Index];
+      MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);
+      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+          InDeletedVariable = PtrTrack->CurrPtr;
+        } else {
+          return EFI_SUCCESS;
+        }
+      }
+    }
+
+    if (IndexTable->GoneThrough != 0) {
+      //
+      // If the table has all the existing variables indexed, return.
+      //
+      PtrTrack->CurrPtr = InDeletedVariable;
+      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+    }
+  }
+
+  if (MaxIndex != NULL) {
+    //
+    // HOB exists but the variable cannot be found in HOB
+    // If not found in HOB, then let's start from the MaxIndex we've found.
+    //
+    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
+    LastVariable = MaxIndex;
+  } else {
+    //
+    // Start Pointers for the variable.
+    // Actual Data Pointer where data can be written.
+    //
+    Variable     = PtrTrack->StartPtr;
+    LastVariable = PtrTrack->StartPtr;
+  }
+
+  //
+  // Find the variable by walk through variable store
+  //
+  StopRecord = FALSE;
+  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+      //
+      // Record Variable in VariableIndex HOB
+      //
+      if ((IndexTable != NULL) && !StopRecord) {
+        Offset = (UINTN)Variable - (UINTN)LastVariable;
+        if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
+          //
+          // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
+          // or the record buffer is full.
+          //
+          StopRecord = TRUE;
+        } else {
+          IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
+          LastVariable                            = Variable;
+        }
+      }
+
+      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+          InDeletedVariable = PtrTrack->CurrPtr;
+        } else {
+          return EFI_SUCCESS;
+        }
+      }
+    }
+
+    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+  }
+
+  //
+  // If gone through the VariableStore, that means we never find in Firmware any more.
+  //
+  if ((IndexTable != NULL) && !StopRecord) {
+    IndexTable->GoneThrough = 1;
+  }
+
+  PtrTrack->CurrPtr = InDeletedVariable;
+
+  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+  Find the variable in HOB and Non-Volatile variable storages.
+
+  @param  VariableName  Name of the variable to be found
+  @param  VendorGuid    Vendor GUID to be found.
+  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.
+  @param  StoreInfo     Return the store info.
+
+  @retval  EFI_SUCCESS            Variable found successfully
+  @retval  EFI_NOT_FOUND          Variable not found
+  @retval  EFI_INVALID_PARAMETER  Invalid variable name
+**/
+EFI_STATUS
+FindVariable (
+  IN CONST  CHAR16            *VariableName,
+  IN CONST  EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  OUT VARIABLE_STORE_INFO     *StoreInfo
+  )
+{
+  EFI_STATUS           Status;
+  VARIABLE_STORE_TYPE  Type;
+
+  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+    GetVariableStore (Type, StoreInfo);
+    Status = FindVariableEx (
+               StoreInfo,
+               VariableName,
+               VendorGuid,
+               PtrTrack
+               );
+    if (!EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  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
+PeiGetVariable (
+  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
+  )
+{
+  VARIABLE_POINTER_TRACK  Variable;
+  UINTN                   VarDataSize;
+  EFI_STATUS              Status;
+  VARIABLE_STORE_INFO     StoreInfo;
+  VARIABLE_HEADER         *VariableHeader;
+
+  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableName[0] == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  VariableHeader = NULL;
+
+  //
+  // Find existing variable
+  //
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
+  //
+  // Get data size
+  //
+  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+  if (*DataSize >= VarDataSize) {
+    if (Data == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (Attributes != NULL) {
+    *Attributes = VariableHeader->Attributes;
+  }
+
+  *DataSize = VarDataSize;
+
+  return Status;
+}
+
+/**
+  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
+PeiGetNextVariableName (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  )
+{
+  VARIABLE_STORE_TYPE     Type;
+  VARIABLE_POINTER_TRACK  Variable;
+  VARIABLE_POINTER_TRACK  VariableInHob;
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;
+  UINTN                   VarNameSize;
+  EFI_STATUS              Status;
+  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
+  VARIABLE_HEADER         *VariableHeader;
+  VARIABLE_STORE_INFO     StoreInfo;
+  VARIABLE_STORE_INFO     StoreInfoForNv;
+  VARIABLE_STORE_INFO     StoreInfoForHob;
+
+  if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableHeader = NULL;
+
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+  if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
+    return Status;
+  }
+
+  if (VariableName[0] != 0) {
+    //
+    // If variable name is not NULL, get next variable
+    //
+    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+  }
+
+  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
+
+  while (TRUE) {
+    //
+    // Switch from HOB to Non-Volatile.
+    //
+    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+      //
+      // Find current storage index
+      //
+      for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+          break;
+        }
+      }
+
+      ASSERT (Type < VariableStoreTypeMax);
+      //
+      // Switch to next storage
+      //
+      for (Type++; Type < VariableStoreTypeMax; Type++) {
+        if (VariableStoreHeader[Type] != NULL) {
+          break;
+        }
+      }
+
+      //
+      // Capture the case that
+      // 1. current storage is the last one, or
+      // 2. no further storage
+      //
+      if (Type == VariableStoreTypeMax) {
+        return EFI_NOT_FOUND;
+      }
+
+      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+      Variable.EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
+      Variable.CurrPtr  = Variable.StartPtr;
+      GetVariableStore (Type, &StoreInfo);
+    }
+
+    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+      if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+        //
+        // If it is a IN_DELETED_TRANSITION variable,
+        // and there is also a same ADDED one at the same time,
+        // don't return it.
+        //
+        Status = FindVariableEx (
+                   &StoreInfo,
+                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+                   &VariablePtrTrack
+                   );
+        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) {
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+          continue;
+        }
+      }
+
+      //
+      // Don't return NV variable when HOB overrides it
+      //
+      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
+          (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
+          )
+      {
+        Status = FindVariableEx (
+                   &StoreInfoForHob,
+                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+                   &VariableInHob
+                   );
+        if (!EFI_ERROR (Status)) {
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+          continue;
+        }
+      }
+
+      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+      ASSERT (VarNameSize != 0);
+
+      if (VarNameSize <= *VariableNameSize) {
+        GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
+
+        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+        Status = EFI_SUCCESS;
+      } else {
+        Status = EFI_BUFFER_TOO_SMALL;
+      }
+
+      *VariableNameSize = VarNameSize;
+      //
+      // Variable is found
+      //
+      return Status;
+    } else {
+      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+    }
+  }
+}
+
+/**
+  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/Protected/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
new file mode 100644
index 000000000000..2d605d39cbb6
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/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/Protected/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
new file mode 100644
index 000000000000..75edc3fc5051
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/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;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
new file mode 100644
index 000000000000..106c1dfdc5c0
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI."
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
new file mode 100644
index 000000000000..22dd992be908
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PeiVariable Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Variable Access PEI Module"
+
+
-- 
2.35.1.windows.2


  parent reply	other threads:[~2022-11-06  7:35 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
2022-11-06  7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
2022-11-06  7:34 ` [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
2022-11-06  7:34 ` [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
2022-11-06  7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
2022-11-22  6:31   ` Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-11-06  7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
2022-11-22  6:39   ` Wang, Jian J
2022-11-06  7:34 ` Judah Vang [this message]
2022-11-14  3:43   ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Wang, Jian J
     [not found]   ` <1727569A8ECB6F9D.19699@groups.io>
2022-11-14  4:27     ` [edk2-devel] " Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
2022-11-14  7:14   ` Wang, Jian J
2022-11-14 17:19     ` Judah Vang
2022-11-15  8:49       ` [edk2-devel] " Sami Mujawar
2022-11-22  6:26         ` Wang, Jian J
     [not found]         ` <1729D430BF77E016.5511@groups.io>
2022-11-22  6:42           ` Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
2022-11-22  6:44   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 10/19] SecurityPkg: Add new GUIDs for Judah Vang
2022-11-06  7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
2022-11-22  6:46   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 12/19] SecurityPkg: Add new variable types and functions Judah Vang
2022-11-06  7:35 ` [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index Judah Vang
2022-11-06  7:35 ` [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API Judah Vang
2022-11-06  7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
2022-11-22  6:55   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 16/19] SecurityPkg: Add VariableKey library function Judah Vang
2022-11-06  7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
2022-11-22  7:15   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
2022-11-22  7:59   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
2022-11-22  8:05   ` Wang, Jian J
2022-12-09  8:03 ` [edk2-devel] [PATCH v5 00/19] UEFI variable protection Yao, Jiewen
     [not found] ` <172F11512E3044E7.1612@groups.io>
2022-12-09  9:41   ` Yao, Jiewen

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20221106073509.3071-8-judah.vang@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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