Hi Judah,

See my comments (starting with [JianJW]) inline below.


> -----Original Message-----
> From: Vang, Judah <judah.v...@intel.com>
> Sent: Sunday, November 06, 2022 3:35 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 v5 07/19] MdeModulePkg: Add new Variable functionality
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V5: Add PEI Variable Protection into a new directory and leave the
> existing PEI Variable unchanged.
> 
> V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
> and SafeUint64ToUint32().
> 
> V1: Provide new APIs for retrieving variable information.
> Add new function stubs for retrieving Protected
> variable information.
> 
> Cc: Jian J Wang <jian.j.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>
> Acked-by: Hao A Wu <hao.a...@intel.com>
> ---
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf      |  79 ++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h           | 225 
> +++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h    | 309
> +++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h      | 116 +++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c           | 628
> +++++++++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c    | 941
> ++++++++++++++++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c      | 307
> +++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni      |  16 +
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni |  14 +
>  9 files changed, 2635 insertions(+)
> 
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> new file mode 100644
> index 000000000000..953a7c6b884f
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> @@ -0,0 +1,79 @@
> +## @file
> +#  Implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +#
> +#  This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +#
> +#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiVariable
> +  MODULE_UNI_FILE                = PeiVariable.uni
> +  FILE_GUID                      = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = PeimInitializeVariableServices
> +
> +#
> +# The following information is for reference only and not required by the 
> build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 EBC
> +#
> +
> +[Sources]
> +  Variable.c
> +  Variable.h
> +  VariableStore.c
> +  VariableStore.h
> +  VariableParsing.c
> +  VariableParsing.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  PcdLib
> +  HobLib
> +  PeimEntryPoint
> +  DebugLib
> +  PeiServicesTablePointerLib
> +  PeiServicesLib
> +  SafeIntLib
> +  VariableFlashInfoLib
> +  ProtectedVariableLib
> +
> +[Guids]
> +  ## CONSUMES             ## GUID # Variable store header
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiAuthenticatedVariableGuid
> +  ## SOMETIMES_CONSUMES   ## GUID # Variable store header
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiVariableGuid
> +  ## SOMETIMES_PRODUCES   ## HOB
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiVariableIndexTableGuid
> +  gEfiSystemNvDataFvGuid            ## SOMETIMES_CONSUMES   ## GUID
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  ## CONSUMES             ## GUID # Dependence
> +  gEdkiiFaultTolerantWriteGuid
> +
> +[Ppis]
> +  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
> +  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ##
> SOMETIMES_CONSUMES
> +
> +[Depex]
> +  gEdkiiFaultTolerantWriteGuid
> +
> +# [BootMode]
> +# RECOVERY_FULL             ## SOMETIMES_CONSUMES
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  PeiVariableExtra.uni
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> new file mode 100644
> index 000000000000..1bdbdd2b807b
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> @@ -0,0 +1,225 @@
> +/** @file
> +  The internal header file includes the common header files, defines
> +  internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_H_
> +#define PEI_VARIABLE_H_
> +
> +#include <PiPei.h>
> +#include <Ppi/ReadOnlyVariable2.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/HobLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PeiServicesTablePointerLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/SafeIntLib.h>
> +#include <Library/VariableFlashInfoLib.h>
> +#include <Library/ProtectedVariableLib.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Guid/VariableIndexTable.h>
> +#include <Guid/SystemNvDataGuid.h>
> +#include <Guid/FaultTolerantWrite.h>
> +#include <Guid/ProtectedVariable.h>
> +
> +typedef enum {
> +  VariableStoreTypeHob,
> +  VariableStoreTypeNv,
> +  VariableStoreTypeMax
> +} VARIABLE_STORE_TYPE;
> +
> +typedef struct {
> +  VARIABLE_STORE_HEADER                   *VariableStoreHeader;
> +  VARIABLE_INDEX_TABLE                    *IndexTable;
> +  //
> +  // If it is not NULL, it means there may be an inconsecutive variable whose
> +  // partial content is still in NV storage, but another partial content is 
> backed
> up
> +  // in spare block.
> +  //
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;
> +  BOOLEAN                                 AuthFlag;
> +} VARIABLE_STORE_INFO;
> +
> +//
> +// Functions
> +//
> +
> +/**
> +  Provide the functionality of the variable services.
> +
> +  @param  FileHandle  Handle of the file being invoked.
> +                      Type EFI_PEI_FILE_HANDLE is defined in 
> FfsFindNextFile().
> +  @param  PeiServices  General purpose services available to every PEIM.
> +
> +  @retval EFI_SUCCESS  If the interface could be successfully installed
> +  @retval Others       Returned from PeiServicesInstallPpi()
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeimInitializeVariableServices (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  );
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that 
> is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the 
> variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the 
> variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the 
> Data
> buffer.
> +                                On return, points to the size of the data 
> returned in Data.
> +  @param  Data                  Points to the buffer which will hold the 
> returned
> variable value.
> +                                May be NULL with a zero DataSize in order to 
> determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required 
> for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariable (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer 
> pointed
> to by VariableName.
> +  @param  VariableName      On entry, a pointer to a null-terminated string 
> that
> is the variable's name.
> +                            On return, points to the next variable's 
> null-terminated name
> string.
> +
> +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the 
> size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableName (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  );
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that 
> is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the 
> variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the 
> variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the 
> Data
> buffer.
> +                                On return, points to the size of the data 
> returned in Data.
> +  @param  Data                  Points to the buffer which will hold the 
> returned
> variable value.
> +                                May be NULL with a zero DataSize in order to 
> determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required 
> for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer 
> pointed
> to by VariableName.
> +  @param  VariableName      On entry, a pointer to a null-terminated string 
> that
> is the variable's name.
> +                            On return, points to the next variable's 
> null-terminated name
> string.
> +
> +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the 
> size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  );
> +
> +#endif

[JianJW] 
a. The function header comments for PeiGetVariableEx/PeiGetNextVariableNameEx
    are the same as non-ex version of PeiGetVariable/PeiGetNextVariableName. 
This
    doesn't do any help to users to get know about what're the differences 
between
    these two version of functions. Please update the Ex version function 
header to
    give more accurate descriptions.
b. Please update the function header in Variable.c as well.

> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> new file mode 100644
> index 000000000000..d7af6cb6e8be
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> @@ -0,0 +1,309 @@
> +/** @file
> +  The internal header file includes the common header files, defines
> +  internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_PARSING_H_
> +#define PEI_VARIABLE_PARSING_H_
> +
> +#include "Variable.h"
> +
> +/**
> +
> +  Gets the pointer to the first variable header in given variable store area.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the first variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetStartPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +
> +  Gets the pointer to the end of the variable storage area.
> +
> +  This function gets pointer to the end of the variable storage
> +  area, according to the input variable store header.
> +
> +  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @return Pointer to the end of the variable storage area.
> +
> +**/
> +VARIABLE_HEADER *
> +GetEndPointer (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +  This code checks if variable header is valid or not.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +
> +  @retval TRUE      Variable header is valid.
> +  @retval FALSE     Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> +  IN  VARIABLE_HEADER  *Variable
> +  );
> +
> +/**
> +  This code gets the pointer to the next variable header.
> +
> +  @param[in]  StoreInfo         Pointer to variable store info structure.
> +  @param[in]  Variable          Pointer to the Variable Header.
> +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> +
> +  @return  A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> +  IN  VARIABLE_HEADER      *Variable,
> +  IN  VARIABLE_HEADER      *VariableHeader
> +  );
> +
> +/**
> +  This code gets the pointer to the variable guid.
> +
> +  @param[in]  Variable   Pointer to the Variable Header.
> +  @param[in]  AuthFlag   Authenticated variable flag.
> +
> +  @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable name.
> +
> +  @param[in]   Variable  Pointer to the Variable Header.
> +  @param[in]   AuthFlag  Authenticated variable flag.
> +
> +  @return  A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of name of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of data of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable data.
> +
> +  @param[in]   Variable         Pointer to the Variable Header.
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]   AuthFlag         Authenticated variable flag.
> +
> +  @return  A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  VARIABLE_HEADER  *VariableHeader,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  Get variable header that has consecutive content.
> +
> +  @param[in]  StoreInfo      Pointer to variable store info structure.
> +  @param[in]  Variable       Pointer to the Variable Header.
> +  @param[out] VariableHeader Pointer to Pointer to the Variable Header that
> has consecutive content.
> +
> +  @retval TRUE          Variable header is valid.
> +  @retval FALSE         Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN VARIABLE_HEADER      *Variable,
> +  OUT VARIABLE_HEADER     **VariableHeader
> +  );
> +
> +/**
> +  This code gets the size of variable header.
> +
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> +  IN  BOOLEAN  AuthFlag
> +  );
> +
> +/**
> +  Get variable name or data to output buffer.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> +  @param[in]  Size          Variable name/data size.
> +  @param[out] Buffer        Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN UINT8                *NameOrData,
> +  IN UINTN                Size,
> +  OUT UINT8               *Buffer
> +  );
> +
> +/**
> +  This function compares a variable with variable entries in database.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  Variable      Pointer to the variable in our database
> +  @param[in]  VariableHeader Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]  VariableName  Name of the variable to compare to 'Variable'
> +  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
> +  @param[out] PtrTrack      Variable Track Pointer structure that contains
> Variable Information.
> +
> +  @retval EFI_SUCCESS    Found match variable
> +  @retval EFI_NOT_FOUND  Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> +  IN  VARIABLE_HEADER         *Variable,
> +  IN  VARIABLE_HEADER         *VariableHeader,
> +  IN  CONST CHAR16            *VariableName,
> +  IN  CONST EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within 
> VariableStore.
> +
> +  If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.

[JianJW] This part doesn't match the function implementation any more.
It can be removed.

> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
> +  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
> +  @retval EFI_SUCCESS            The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  );
> +
> +/**
> +
> +  Retrieve details about a variable and return them in VariableInfo->Header.
> +
> +  If VariableInfo->Address is given, this function will calculate its offset
> +  relative to given variable storage via VariableStore; Otherwise, it will 
> try
> +  other internal variable storages or cached copies. It's assumed that, for 
> all
> +  copies of NV variable storage, all variables are stored in the same 
> relative
> +  position. If VariableInfo->Address is found in the range of any storage 
> copies,
> +  its offset relative to that storage should be the same in other copies.
> +
> +  If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> +  this function will return the variable memory address inside VariableStore,
> +  if given, via VariableInfo->Address; Otherwise, the address of other 
> storage
> +  copies will be returned, if any.
> +
> +  For a new variable whose offset has not been determined, a value of -1 as
> +  VariableInfo->Offset should be passed to skip the offset calculation.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Address
> +                                 and VariableInfo->Offset are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Address or Offset is out of range 
> of
> +                                 any given or internal storage copies.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo
> +  );
> +
> +/**
> +
> +  Find variable specified with input parameters.
> +
> +  @param[in] StoreInfo             Pointer to variable information.
> +  @param[in] VariableName          Pointer to variable name.
> +  @param[in] VendorGuid            Pointer to variable GUID.
> +  @param[in] PtrTrack              Pointer to variable track.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Address
> +                                 and VariableInfo->Offset are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Address or Offset is out of range 
> of
> +                                 any given or internal storage copies.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +FindVariableEx (
> +  IN VARIABLE_STORE_INFO      *StoreInfo,
> +  IN CONST CHAR16             *VariableName,
> +  IN CONST EFI_GUID           *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> new file mode 100644
> index 000000000000..6e2f6f939bab
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> @@ -0,0 +1,116 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile 
> storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_STORE_H_
> +#define PEI_VARIABLE_STORE_H_
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  );
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableStoreHeader   Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  );
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Make a cached copy of NV variable storage.
> +
> +  To save memory in PEI phase, only valid variables are copied into cache.
> +  An IndexTable could be used to store the offset (relative to NV storage
> +  base) of each copied variable, in case we need to restore the storage
> +  as the same (valid) variables layout as in original one.
> +
> +  Variables with valid format and following state can be taken as valid:
> +    - with state VAR_ADDED;
> +    - with state VAR_IN_DELETED_TRANSITION but without the same variable
> +      with state VAR_ADDED;
> +    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
> +      MetaDataHmacVar.
> +
> +  @param[out]     StoreCacheBase    Base address of variable storage cache.
> +  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
> +  @param[out]     IndexTable        Buffer of index (offset) table with 
> entries of
> +                                    VariableNumber.
> +  @param[out]     VariableNumber    Number of valid variables.
> +  @param[out]     AuthFlag          Aut-variable indicator.
> +
> +  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or
> StoreCacheBase.
> +  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
> +  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
> +  @return EFI_SUCCESS           NV variable storage is cached successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitNvVariableStore (
> +  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
> +  IN OUT  UINT32             *StoreCacheSize,
> +  OUT  UINT32                *IndexTable OPTIONAL,
> +  OUT  UINT32                *VariableNumber OPTIONAL,
> +  OUT  BOOLEAN               *AuthFlag OPTIONAL
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> new file mode 100644
> index 000000000000..ce790946626e
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> @@ -0,0 +1,628 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile 
> storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) Microsoft Corporation.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Variable.h"
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +//
> +// Module globals
> +//
> +EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
> +  PeiGetVariableEx,
> +  PeiGetNextVariableNameEx
> +};
> +
> +EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
> +  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +  &gEfiPeiReadOnlyVariable2PpiGuid,
> +  &mVariablePpi
> +};
> +
> +/**
> +  Provide the functionality of the variable services.
> +
> +  @param  FileHandle   Handle of the file being invoked.
> +                       Type EFI_PEI_FILE_HANDLE is defined in 
> FfsFindNextFile().
> +  @param  PeiServices  General purpose services available to every PEIM.
> +
> +  @retval EFI_SUCCESS  If the interface could be successfully installed
> +  @retval Others       Returned from PeiServicesInstallPpi()
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeimInitializeVariableServices (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
> +
> +  //
> +  // If protected variable services are not supported, EFI_UNSUPPORTED should
> +  // be always returned. Check it here.
> +  //
> +  ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +  ContextIn.StructSize    = sizeof (ContextIn);
> +
> +  ContextIn.MaxVariableSize             = 0;
> +  ContextIn.VariableServiceUser         = FromPeiModule;
> +  ContextIn.GetVariableInfo             = GetVariableInfo;
> +  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
> +  ContextIn.FindVariableSmm             = NULL;
> +  ContextIn.UpdateVariableStore         = NULL;
> +  ContextIn.UpdateVariable              = NULL;
> +  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
> +
> +  Status = ProtectedVariableLibInitialize (&ContextIn);
> +  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> +    return Status;
> +  }
> +
> +  return PeiServicesInstallPpi (&mPpiListVariable);
> +}
> +
> +/**
> +  Find the variable in the specified variable store.
> +
> +  @param  StoreInfo           Pointer to the store info structure.
> +  @param  VariableName        Name of the variable to be found
> +  @param  VendorGuid          Vendor GUID to be found.
> +  @param  PtrTrack            Variable Track Pointer structure that contains
> Variable Information.
> +
> +  @retval  EFI_SUCCESS            Variable found successfully
> +  @retval  EFI_NOT_FOUND          Variable not found
> +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> +
> +**/
> +EFI_STATUS
> +FindVariableEx (
> +  IN VARIABLE_STORE_INFO      *StoreInfo,
> +  IN CONST CHAR16             *VariableName,
> +  IN CONST EFI_GUID           *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  )
> +{
> +  VARIABLE_HEADER        *Variable;
> +  VARIABLE_HEADER        *LastVariable;
> +  VARIABLE_HEADER        *MaxIndex;
> +  UINTN                  Index;
> +  UINTN                  Offset;
> +  BOOLEAN                StopRecord;
> +  VARIABLE_HEADER        *InDeletedVariable;
> +  VARIABLE_STORE_HEADER  *VariableStoreHeader;
> +  VARIABLE_INDEX_TABLE   *IndexTable;
> +  VARIABLE_HEADER        *VariableHeader;
> +
> +  VariableStoreHeader = StoreInfo->VariableStoreHeader;
> +
> +  if (VariableStoreHeader == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (~VariableStoreHeader->Size == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  IndexTable         = StoreInfo->IndexTable;
> +  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
> +  PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
> +
> +  InDeletedVariable = NULL;
> +
> +  //
> +  // No Variable Address equals zero, so 0 as initial value is safe.
> +  //
> +  MaxIndex       = NULL;
> +  VariableHeader = NULL;
> +
> +  if (IndexTable != NULL) {
> +    //
> +    // traverse the variable index table to look for varible.
> +    // The IndexTable->Index[Index] records the distance of two neighbouring
> VAR_ADDED type variables.
> +    //
> +    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
> +      ASSERT (Index < sizeof (IndexTable->Index) / sizeof 
> (IndexTable->Index[0]));
> +      Offset  += IndexTable->Index[Index];
> +      MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);
> +      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
> +      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader,
> VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> VAR_ADDED)) {
> +          InDeletedVariable = PtrTrack->CurrPtr;
> +        } else {
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +
> +    if (IndexTable->GoneThrough != 0) {
> +      //
> +      // If the table has all the existing variables indexed, return.
> +      //
> +      PtrTrack->CurrPtr = InDeletedVariable;
> +      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> +    }
> +  }
> +
> +  if (MaxIndex != NULL) {
> +    //
> +    // HOB exists but the variable cannot be found in HOB
> +    // If not found in HOB, then let's start from the MaxIndex we've found.
> +    //
> +    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
> +    LastVariable = MaxIndex;
> +  } else {
> +    //
> +    // Start Pointers for the variable.
> +    // Actual Data Pointer where data can be written.
> +    //
> +    Variable     = PtrTrack->StartPtr;
> +    LastVariable = PtrTrack->StartPtr;
> +  }
> +
> +  //
> +  // Find the variable by walk through variable store
> +  //
> +  StopRecord = FALSE;
> +  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
> +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> +      //
> +      // Record Variable in VariableIndex HOB
> +      //
> +      if ((IndexTable != NULL) && !StopRecord) {
> +        Offset = (UINTN)Variable - (UINTN)LastVariable;
> +        if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof 
> (IndexTable->Index)
> / sizeof (IndexTable->Index[0]))) {
> +          //
> +          // Stop to record if the distance of two neighbouring VAR_ADDED
> variable is larger than the allowable scope(UINT16),
> +          // or the record buffer is full.
> +          //
> +          StopRecord = TRUE;
> +        } else {
> +          IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
> +          LastVariable                            = Variable;
> +        }
> +      }
> +
> +      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader,
> VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> VAR_ADDED)) {
> +          InDeletedVariable = PtrTrack->CurrPtr;
> +        } else {
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +
> +    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
> +  }
> +
> +  //
> +  // If gone through the VariableStore, that means we never find in Firmware
> any more.
> +  //
> +  if ((IndexTable != NULL) && !StopRecord) {
> +    IndexTable->GoneThrough = 1;
> +  }
> +
> +  PtrTrack->CurrPtr = InDeletedVariable;
> +
> +  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> +}
> +
> +/**
> +  Find the variable in HOB and Non-Volatile variable storages.
> +
> +  @param  VariableName  Name of the variable to be found
> +  @param  VendorGuid    Vendor GUID to be found.
> +  @param  PtrTrack      Variable Track Pointer structure that contains 
> Variable
> Information.
> +  @param  StoreInfo     Return the store info.
> +
> +  @retval  EFI_SUCCESS            Variable found successfully
> +  @retval  EFI_NOT_FOUND          Variable not found
> +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> +**/
> +EFI_STATUS
> +FindVariable (
> +  IN CONST  CHAR16            *VariableName,
> +  IN CONST  EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
> +  OUT VARIABLE_STORE_INFO     *StoreInfo
> +  )
> +{
> +  EFI_STATUS           Status;
> +  VARIABLE_STORE_TYPE  Type;
> +
> +  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++)
> {
> +    GetVariableStore (Type, StoreInfo);
> +    Status = FindVariableEx (
> +               StoreInfo,
> +               VariableName,
> +               VendorGuid,
> +               PtrTrack
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that 
> is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the 
> variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the 
> variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the 
> Data
> buffer.
> +                                On return, points to the size of the data 
> returned in Data.
> +  @param  Data                  Points to the buffer which will hold the 
> returned
> variable value.
> +                                May be NULL with a zero DataSize in order to 
> determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required 
> for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariable (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  )
> +{
> +  VARIABLE_POINTER_TRACK  Variable;
> +  UINTN                   VarDataSize;
> +  EFI_STATUS              Status;
> +  VARIABLE_STORE_INFO     StoreInfo;
> +  VARIABLE_HEADER         *VariableHeader;
> +
> +  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == 
> NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (VariableName[0] == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  VariableHeader = NULL;
> +
> +  //
> +  // Find existing variable
> +  //
> +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> +
> +  //
> +  // Get data size
> +  //
> +  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> +  if (*DataSize >= VarDataSize) {
> +    if (Data == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr,
> VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
> +    Status = EFI_SUCCESS;
> +  } else {
> +    Status = EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  if (Attributes != NULL) {
> +    *Attributes = VariableHeader->Attributes;
> +  }
> +
> +  *DataSize = VarDataSize;
> +
> +  return Status;
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer 
> pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string 
> that
> is the variable's name.
> +                            On return, points to the next variable's 
> null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the 
> size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableName (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  )
> +{
> +  VARIABLE_STORE_TYPE     Type;
> +  VARIABLE_POINTER_TRACK  Variable;
> +  VARIABLE_POINTER_TRACK  VariableInHob;
> +  VARIABLE_POINTER_TRACK  VariablePtrTrack;
> +  UINTN                   VarNameSize;
> +  EFI_STATUS              Status;
> +  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
> +  VARIABLE_HEADER         *VariableHeader;
> +  VARIABLE_STORE_INFO     StoreInfo;
> +  VARIABLE_STORE_INFO     StoreInfoForNv;
> +  VARIABLE_STORE_INFO     StoreInfoForHob;
> +
> +  if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize
> == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  VariableHeader = NULL;
> +
> +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> +  if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
> +    return Status;
> +  }
> +
> +  if (VariableName[0] != 0) {
> +    //
> +    // If variable name is not NULL, get next variable
> +    //
> +    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> +    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +  }
> +
> +  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore
> (VariableStoreTypeHob, &StoreInfoForHob);
> +  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore
> (VariableStoreTypeNv, &StoreInfoForNv);
> +
> +  while (TRUE) {
> +    //
> +    // Switch from HOB to Non-Volatile.
> +    //
> +    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, 
> &VariableHeader)) {
> +      //
> +      // Find current storage index
> +      //
> +      for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax;
> Type++) {
> +        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr ==
> GetStartPointer (VariableStoreHeader[Type]))) {
> +          break;
> +        }
> +      }
> +
> +      ASSERT (Type < VariableStoreTypeMax);
> +      //
> +      // Switch to next storage
> +      //
> +      for (Type++; Type < VariableStoreTypeMax; Type++) {
> +        if (VariableStoreHeader[Type] != NULL) {
> +          break;
> +        }
> +      }
> +
> +      //
> +      // Capture the case that
> +      // 1. current storage is the last one, or
> +      // 2. no further storage
> +      //
> +      if (Type == VariableStoreTypeMax) {
> +        return EFI_NOT_FOUND;
> +      }
> +
> +      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
> +      Variable.EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
> +      Variable.CurrPtr  = Variable.StartPtr;
> +      GetVariableStore (Type, &StoreInfo);
> +    }
> +
> +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> +      if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> VAR_ADDED)) {
> +        //
> +        // If it is a IN_DELETED_TRANSITION variable,
> +        // and there is also a same ADDED one at the same time,
> +        // don't return it.
> +        //
> +        Status = FindVariableEx (
> +                   &StoreInfo,
> +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> +                   &VariablePtrTrack
> +                   );
> +        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != 
> Variable.CurrPtr)) {
> +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, 
> Variable.CurrPtr,
> VariableHeader);
> +          continue;
> +        }
> +      }
> +
> +      //
> +      // Don't return NV variable when HOB overrides it
> +      //
> +      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) &&
> (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
> +          (Variable.StartPtr == GetStartPointer
> (VariableStoreHeader[VariableStoreTypeNv]))
> +          )
> +      {
> +        Status = FindVariableEx (
> +                   &StoreInfoForHob,
> +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> +                   &VariableInHob
> +                   );
> +        if (!EFI_ERROR (Status)) {
> +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, 
> Variable.CurrPtr,
> VariableHeader);
> +          continue;
> +        }
> +      }
> +
> +      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> +      ASSERT (VarNameSize != 0);
> +
> +      if (VarNameSize <= *VariableNameSize) {
> +        GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr
> (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
> +
> +        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader,
> StoreInfo.AuthFlag), sizeof (EFI_GUID));
> +
> +        Status = EFI_SUCCESS;
> +      } else {
> +        Status = EFI_BUFFER_TOO_SMALL;
> +      }
> +
> +      *VariableNameSize = VarNameSize;
> +      //
> +      // Variable is found
> +      //
> +      return Status;
> +    } else {
> +      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +    }
> +  }
> +}
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that 
> is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the 
> variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the 
> variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the 
> Data
> buffer.
> +                                On return, points to the size of the data 
> returned in Data.
> +  @param  Data                  Points to the buffer which will hold the 
> returned
> variable value.
> +                                May be NULL with a zero DataSize in order to 
> determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required 
> for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get variable data through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid,
> Attributes, DataSize, Data);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetVariable (This, VariableName, VariableGuid, Attributes, 
> DataSize,
> Data);
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer 
> pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string 
> that
> is the variable's name.
> +                            On return, points to the next variable's 
> null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the 
> size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because 
> of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get next variable through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName,
> VariableGuid);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetNextVariableName (This, VariableNameSize, VariableName,
> VariableGuid);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> new file mode 100644
> index 000000000000..2d605d39cbb6
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> @@ -0,0 +1,941 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile 
> storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +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

[JianJW] typo: "unconsecutive" -> "inconsecutive"

> +  // 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

[JianJW] typo: "unconsecutive" -> "inconsecutive"

> +    // of its header in consecutive buffer.
> +    //
> +    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, 
> VariableHeader);
> +  }
> +
> +  //
> +  // Get a copy of variable header in consecutive buffer.
> +  //
> +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Use the offset to the start of variable store as index of the variable.
> +  //
> +  if (  (StoreInfo.FtwLastWriteData == NULL)
> +     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData-
> >TargetAddress))
> +  {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
> +  } else {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                 - (UINTN)StoreInfo.VariableStoreHeader);
> +    VariableInfo->StoreIndex
> +      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData-
> >SpareAddress);
> +  }
> +
> +  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) 
> {
> +    VariableInfo->Buffer = VariablePtr;
> +  }
> +
> +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> new file mode 100644
> index 000000000000..75edc3fc5051
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> @@ -0,0 +1,307 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile 
> storage
> space.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  )
> +{
> +  if ((CompareGuid (&VarStoreHeader->Signature,
> &gEfiAuthenticatedVariableGuid) ||
> +       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
> +      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
> +      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
> +      )
> +  {
> +    return EfiValid;
> +  }
> +
> +  if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
> +      (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
> +      (VarStoreHeader->Size == 0xffffffff) &&
> +      (VarStoreHeader->Format == 0xff) &&
> +      (VarStoreHeader->State == 0xff)
> +      )
> +  {
> +    return EfiRaw;
> +  } else {
> +    return EfiInvalid;
> +  }
> +}
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +  VOID               *VariableStoreInfoHob;
> +
> +  //
> +  // Discover if Variable Store Info Hob has been published by platform 
> driver.
> +  // It contains information regards to HOB or NV Variable Store availability
> +  //
> +  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
> +  if (GuidHob == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  //
> +  // Check if HOB Variable Store is available
> +  //
> +  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
> +  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // This might be NV Variable Store
> +  //
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  //
> +  // Make sure there is no more than one Variable HOB.
> +  //
> +  DEBUG_CODE_BEGIN ();
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob != NULL) {
> +    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB
> (GuidHob)) != NULL)) {
> +      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
> +      ASSERT (FALSE);
> +    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
> +      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable
> HOBs\n"));
> +      ASSERT (FALSE);
> +    }
> +  } else {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) !=
> NULL)) {
> +        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
> +        ASSERT (FALSE);
> +      }
> +    }
> +  }
> +
> +  DEBUG_CODE_END ();
> +
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob != NULL) {
> +    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +    StoreInfo->AuthFlag            = TRUE;
> +  } else {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +      StoreInfo->AuthFlag            = FALSE;
> +    }
> +  }
> +}
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableFvHeader      Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_HOB_GUID_TYPE                     *GuidHob;
> +  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
> +  VARIABLE_STORE_HEADER                 *StoreHeader;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
> +  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
> +  UINT32                                NvStorageSize;
> +  UINT32                                BackUpOffset;
> +  UINT64                                NvStorageSize64;
> +
> +  Status = GetVariableFlashNvStorageInfo (&NvStorageBase,
> &NvStorageSize64);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);
> +  // This driver currently assumes the size will be UINT32 so assert the 
> value is
> safe for now.
> +  ASSERT_EFI_ERROR (Status);
> +
> +  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> +
> +  //
> +  // Check the FTW last write data hob.
> +  //
> +  BackUpOffset     = 0;
> +  FtwLastWriteData = NULL;
> +  HobData          = NULL;
> +  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> +
> +  if (GuidHob != NULL) {
> +    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> +    if (HobData->TargetAddress == NvStorageBase) {
> +      //
> +      // Let FvHeader point to spare block.
> +      //
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
> +        (UINTN)HobData->SpareAddress
> +        ));
> +
> +      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData-
> >SpareAddress;
> +      HobData  = NULL;
> +    } else if ((HobData->TargetAddress > NvStorageBase) &&
> +               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
> +    {
> +      //
> +      // Flash NV storage from the offset is backed up in spare block.
> +      //
> +      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: High partial NV storage from offset: %x is backed up 
> in spare
> block: 0x%x\n",
> +        BackUpOffset,
> +        (UINTN)FtwLastWriteData->SpareAddress
> +        ));
> +      //
> +      // At least one block data in flash NV storage is still valid, so still
> +      // leave FvHeader point to NV storage base.
> +      //
> +    }
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->FtwLastWriteData = HobData;
> +  }
> +
> +  if (VariableFvHeader != NULL) {
> +    *VariableFvHeader = FvHeader;
> +  }
> +
> +  //
> +  // Check if the Firmware Volume is not corrupted
> +  //
> +  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
> +      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
> +  {
> +    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader-
> >HeaderLength);
> +  } else {
> +    StoreHeader = NULL;
> +    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->VariableStoreHeader = StoreHeader;
> +    if (StoreHeader != NULL) {
> +      StoreInfo->AuthFlag = CompareGuid (
> +                              &StoreHeader->Signature,
> +                              &gEfiAuthenticatedVariableGuid
> +                              );
> +    }
> +  }
> +}
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  StoreInfo->VariableStoreHeader = NULL;
> +  StoreInfo->IndexTable          = NULL;
> +  StoreInfo->FtwLastWriteData    = NULL;
> +  StoreInfo->AuthFlag            = FALSE;
> +  switch (Type) {
> +    case VariableStoreTypeHob:
> +      GetHobVariableStore (StoreInfo);
> +      break;
> +
> +    case VariableStoreTypeNv:
> +      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> +        //
> +        // Emulated non-volatile variable mode is not enabled.
> +        //
> +        GetNvVariableStore (StoreInfo, NULL);
> +        if (StoreInfo->VariableStoreHeader != NULL) {
> +          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> +          if (GuidHob != NULL) {
> +            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> +          } else {
> +            //
> +            // If it's the first time to access variable region in flash, 
> create a guid hob
> to record
> +            // VAR_ADDED type variable info.
> +            // Note that as the resource of PEI phase is limited, only store 
> the
> limited number of
> +            // VAR_ADDED type variables to reduce access time.
> +            //
> +            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE
> *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> +            StoreInfo->IndexTable->Length      = 0;
> +            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->GoneThrough = 0;
> +          }
> +        }
> +      }
> +
> +      break;
> +
> +    default:
> +      ASSERT (FALSE);
> +      break;
> +  }
> +
> +  return StoreInfo->VariableStoreHeader;
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> new file mode 100644
> index 000000000000..106c1dfdc5c0
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> @@ -0,0 +1,16 @@
> +// /** @file
> +// Implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +//
> +// This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +//
> +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "Implements
> ReadOnly Variable Services required by PEIM and installs PEI ReadOnly
> Varaiable2 PPI"

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This module
> implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI."

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> diff --git
> a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> new file mode 100644
> index 000000000000..22dd992be908
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// PeiVariable Localized Strings and Content
> +//
> +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"Variable Access PEI Module"
> +
> +
> --
> 2.35.1.windows.2



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


Reply via email to