For function GetNvVariableStore(), I think local variable 'FtwLastWriteData' is 
not used and will incur NULL pointer reference in this patch.
Please help to check.
With this addressed:
Acked-by: Hao A Wu <hao.a...@intel.com>

Best Regards,
Hao Wu

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



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


Reply via email to