From: "Judah Vang" <judah.vang@intel.com>
To: devel@edk2.groups.io
Cc: Jian J Wang <jian.j.wang@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
Hao A Wu <hao.a.wu@intel.com>,
Nishant C Mistry <nishant.c.mistry@intel.com>
Subject: [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
Date: Sun, 6 Nov 2022 00:34:57 -0700 [thread overview]
Message-ID: <20221106073509.3071-8-judah.vang@intel.com> (raw)
In-Reply-To: <20221106073509.3071-1-judah.vang@intel.com>
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
V5: Add PEI Variable Protection into a new directory and leave the
existing PEI Variable unchanged.
V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
and SafeUint64ToUint32().
V1: Provide new APIs for retrieving variable information.
Add new function stubs for retrieving Protected
variable information.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Acked-by: Hao A Wu <hao.a.wu@intel.com>
---
MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf | 79 ++
MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h | 225 +++++
MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h | 309 +++++++
MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h | 116 +++
MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c | 628 +++++++++++++
MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c | 941 ++++++++++++++++++++
MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c | 307 +++++++
MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni | 16 +
| 14 +
9 files changed, 2635 insertions(+)
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
new file mode 100644
index 000000000000..953a7c6b884f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
@@ -0,0 +1,79 @@
+## @file
+# Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiVariable
+ MODULE_UNI_FILE = PeiVariable.uni
+ FILE_GUID = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimInitializeVariableServices
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Variable.c
+ Variable.h
+ VariableStore.c
+ VariableStore.h
+ VariableParsing.c
+ VariableParsing.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ HobLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ SafeIntLib
+ VariableFlashInfoLib
+ ProtectedVariableLib
+
+[Guids]
+ ## CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiAuthenticatedVariableGuid
+ ## SOMETIMES_CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableGuid
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableIndexTableGuid
+ gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## HOB
+ ## CONSUMES ## GUID # Dependence
+ gEdkiiFaultTolerantWriteGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+ gEfiPeiVariableStoreDiscoveredPpiGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEdkiiFaultTolerantWriteGuid
+
+# [BootMode]
+# RECOVERY_FULL ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiVariableExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
new file mode 100644
index 000000000000..1bdbdd2b807b
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
@@ -0,0 +1,225 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_H_
+#define PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/VariableFlashInfoLib.h>
+#include <Library/ProtectedVariableLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VariableIndexTable.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+#include <Guid/ProtectedVariable.h>
+
+typedef enum {
+ VariableStoreTypeHob,
+ VariableStoreTypeNv,
+ VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ //
+ // If it is not NULL, it means there may be an inconsecutive variable whose
+ // partial content is still in NV storage, but another partial content is backed up
+ // in spare block.
+ //
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ BOOLEAN AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
new file mode 100644
index 000000000000..d7af6cb6e8be
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
@@ -0,0 +1,309 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_PARSING_H_
+#define PEI_VARIABLE_PARSING_H_
+
+#include "Variable.h"
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ );
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the size of data of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ Get variable header that has consecutive content.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ );
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ Get variable name or data to output buffer.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param[in] Size Variable name/data size.
+ @param[out] Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the variable in our database
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] VariableName Name of the variable to compare to 'Variable'
+ @param[in] VendorGuid GUID of the variable to compare to 'Variable'
+ @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ );
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+/**
+
+ Retrieve details about a variable and return them in VariableInfo->Header.
+
+ If VariableInfo->Address is given, this function will calculate its offset
+ relative to given variable storage via VariableStore; Otherwise, it will try
+ other internal variable storages or cached copies. It's assumed that, for all
+ copies of NV variable storage, all variables are stored in the same relative
+ position. If VariableInfo->Address is found in the range of any storage copies,
+ its offset relative to that storage should be the same in other copies.
+
+ If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+ this function will return the variable memory address inside VariableStore,
+ if given, via VariableInfo->Address; Otherwise, the address of other storage
+ copies will be returned, if any.
+
+ For a new variable whose offset has not been determined, a value of -1 as
+ VariableInfo->Offset should be passed to skip the offset calculation.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+/**
+
+ Find variable specified with input parameters.
+
+ @param[in] StoreInfo Pointer to variable information.
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable GUID.
+ @param[in] PtrTrack Pointer to variable track.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+FindVariableEx (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
new file mode 100644
index 000000000000..6e2f6f939bab
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
@@ -0,0 +1,116 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_STORE_H_
+#define PEI_VARIABLE_STORE_H_
+
+/**
+ Get variable store status.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ Reports HOB variable store is available or not.
+
+ @retval EFI_NOT_READY HOB variable store info not available.
+ @retval EFI_NOT_FOUND HOB variable store is NOT available.
+ @retval EFI_SUCCESS HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+ VOID
+ );
+
+/**
+ Get HOB variable store.
+
+ @param[out] StoreInfo Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ );
+
+/**
+ Get NV variable store.
+
+ @param[out] StoreInfo Return the store info.
+ @param[out] VariableStoreHeader Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
+ );
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param[in] Type The type of the variable store.
+ @param[out] StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ );
+
+/**
+ Make a cached copy of NV variable storage.
+
+ To save memory in PEI phase, only valid variables are copied into cache.
+ An IndexTable could be used to store the offset (relative to NV storage
+ base) of each copied variable, in case we need to restore the storage
+ as the same (valid) variables layout as in original one.
+
+ Variables with valid format and following state can be taken as valid:
+ - with state VAR_ADDED;
+ - with state VAR_IN_DELETED_TRANSITION but without the same variable
+ with state VAR_ADDED;
+ - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
+ MetaDataHmacVar.
+
+ @param[out] StoreCacheBase Base address of variable storage cache.
+ @param[in,out] StoreCacheSize Size of space in StoreCacheBase.
+ @param[out] IndexTable Buffer of index (offset) table with entries of
+ VariableNumber.
+ @param[out] VariableNumber Number of valid variables.
+ @param[out] AuthFlag Aut-variable indicator.
+
+ @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or StoreCacheBase.
+ @return EFI_VOLUME_CORRUPTED Invalid or no NV variable storage found.
+ @return EFI_BUFFER_TOO_SMALL StoreCacheSize is smaller than needed.
+ @return EFI_SUCCESS NV variable storage is cached successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitNvVariableStore (
+ OUT EFI_PHYSICAL_ADDRESS StoreCacheBase OPTIONAL,
+ IN OUT UINT32 *StoreCacheSize,
+ OUT UINT32 *IndexTable OPTIONAL,
+ OUT UINT32 *VariableNumber OPTIONAL,
+ OUT BOOLEAN *AuthFlag OPTIONAL
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
new file mode 100644
index 000000000000..ce790946626e
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
@@ -0,0 +1,628 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+//
+// Module globals
+//
+EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
+ PeiGetVariableEx,
+ PeiGetNextVariableNameEx
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ &mVariablePpi
+};
+
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // If protected variable services are not supported, EFI_UNSUPPORTED should
+ // be always returned. Check it here.
+ //
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+ ContextIn.StructSize = sizeof (ContextIn);
+
+ ContextIn.MaxVariableSize = 0;
+ ContextIn.VariableServiceUser = FromPeiModule;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.UpdateVariableStore = NULL;
+ ContextIn.UpdateVariable = NULL;
+ ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
+
+ return PeiServicesInstallPpi (&mPpiListVariable);
+}
+
+/**
+ Find the variable in the specified variable store.
+
+ @param StoreInfo Pointer to the store info structure.
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableEx (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *LastVariable;
+ VARIABLE_HEADER *MaxIndex;
+ UINTN Index;
+ UINTN Offset;
+ BOOLEAN StopRecord;
+ VARIABLE_HEADER *InDeletedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ VARIABLE_HEADER *VariableHeader;
+
+ VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+ if (VariableStoreHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (~VariableStoreHeader->Size == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ IndexTable = StoreInfo->IndexTable;
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
+
+ InDeletedVariable = NULL;
+
+ //
+ // No Variable Address equals zero, so 0 as initial value is safe.
+ //
+ MaxIndex = NULL;
+ VariableHeader = NULL;
+
+ if (IndexTable != NULL) {
+ //
+ // traverse the variable index table to look for varible.
+ // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
+ //
+ for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
+ ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
+ Offset += IndexTable->Index[Index];
+ MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);
+ GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+ if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (IndexTable->GoneThrough != 0) {
+ //
+ // If the table has all the existing variables indexed, return.
+ //
+ PtrTrack->CurrPtr = InDeletedVariable;
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+ }
+ }
+
+ if (MaxIndex != NULL) {
+ //
+ // HOB exists but the variable cannot be found in HOB
+ // If not found in HOB, then let's start from the MaxIndex we've found.
+ //
+ Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
+ LastVariable = MaxIndex;
+ } else {
+ //
+ // Start Pointers for the variable.
+ // Actual Data Pointer where data can be written.
+ //
+ Variable = PtrTrack->StartPtr;
+ LastVariable = PtrTrack->StartPtr;
+ }
+
+ //
+ // Find the variable by walk through variable store
+ //
+ StopRecord = FALSE;
+ while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+ if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+ //
+ // Record Variable in VariableIndex HOB
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ Offset = (UINTN)Variable - (UINTN)LastVariable;
+ if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
+ //
+ // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
+ // or the record buffer is full.
+ //
+ StopRecord = TRUE;
+ } else {
+ IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
+ LastVariable = Variable;
+ }
+ }
+
+ if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+ }
+
+ //
+ // If gone through the VariableStore, that means we never find in Firmware any more.
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ IndexTable->GoneThrough = 1;
+ }
+
+ PtrTrack->CurrPtr = InDeletedVariable;
+
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+ Find the variable in HOB and Non-Volatile variable storages.
+
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param StoreInfo Return the store info.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+**/
+EFI_STATUS
+FindVariable (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_TYPE Type;
+
+ if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+ GetVariableStore (Type, StoreInfo);
+ Status = FindVariableEx (
+ StoreInfo,
+ VariableName,
+ VendorGuid,
+ PtrTrack
+ );
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_HEADER *VariableHeader;
+
+ if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableName[0] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableHeader = NULL;
+
+ //
+ // Find existing variable
+ //
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
+ //
+ // Get data size
+ //
+ VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Attributes != NULL) {
+ *Attributes = VariableHeader->Attributes;
+ }
+
+ *DataSize = VarDataSize;
+
+ return Status;
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_STORE_TYPE Type;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariableInHob;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ UINTN VarNameSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_INFO StoreInfoForNv;
+ VARIABLE_STORE_INFO StoreInfoForHob;
+
+ if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableHeader = NULL;
+
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
+ return Status;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable
+ //
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+
+ VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+ VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
+
+ while (TRUE) {
+ //
+ // Switch from HOB to Non-Volatile.
+ //
+ while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+ //
+ // Find current storage index
+ //
+ for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+ if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+ break;
+ }
+ }
+
+ ASSERT (Type < VariableStoreTypeMax);
+ //
+ // Switch to next storage
+ //
+ for (Type++; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] != NULL) {
+ break;
+ }
+ }
+
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (Type == VariableStoreTypeMax) {
+ return EFI_NOT_FOUND;
+ }
+
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.CurrPtr = Variable.StartPtr;
+ GetVariableStore (Type, &StoreInfo);
+ }
+
+ if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ Status = FindVariableEx (
+ &StoreInfo,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ //
+ // Don't return NV variable when HOB overrides it
+ //
+ if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
+ (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
+ )
+ {
+ Status = FindVariableEx (
+ &StoreInfoForHob,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariableInHob
+ );
+ if (!EFI_ERROR (Status)) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ ASSERT (VarNameSize != 0);
+
+ if (VarNameSize <= *VariableNameSize) {
+ GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
+
+ CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ //
+ // Variable is found
+ //
+ return Status;
+ } else {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+ }
+}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If variable protection is employed, always get variable data through
+ // ProtectedVariableLib.
+ //
+ Status = ProtectedVariableLibGetByName (VariableName, VariableGuid, Attributes, DataSize, Data);
+ if (Status != EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize, Data);
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If variable protection is employed, always get next variable through
+ // ProtectedVariableLib.
+ //
+ Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName, VariableGuid);
+ if (Status != EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return PeiGetNextVariableName (This, VariableNameSize, VariableName, VariableGuid);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
new file mode 100644
index 000000000000..2d605d39cbb6
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
@@ -0,0 +1,941 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableStore.h"
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The start of variable store
+ //
+ return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
+}
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ if (AuthFlag) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ if ((AuthVariable->State == (UINT8)(-1)) ||
+ (AuthVariable->DataSize == (UINT32)(-1)) ||
+ (AuthVariable->NameSize == (UINT32)(-1)) ||
+ (AuthVariable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)AuthVariable->NameSize;
+ } else {
+ if ((Variable->State == (UINT8)(-1)) ||
+ (Variable->DataSize == (UINT32)(-1)) ||
+ (Variable->NameSize == (UINT32)(-1)) ||
+ (Variable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)Variable->NameSize;
+ }
+}
+
+/**
+ This code gets the size of data of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ if ((AuthVariable->State == (UINT8)(-1)) ||
+ (AuthVariable->DataSize == (UINT32)(-1)) ||
+ (AuthVariable->NameSize == (UINT32)(-1)) ||
+ (AuthVariable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)AuthVariable->DataSize;
+ } else {
+ if ((Variable->State == (UINT8)(-1)) ||
+ (Variable->DataSize == (UINT32)(-1)) ||
+ (Variable->NameSize == (UINT32)(-1)) ||
+ (Variable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)Variable->DataSize;
+ }
+}
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);
+ Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+ return (UINT8 *)Value;
+}
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN Value;
+
+ Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+ Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = HEADER_ALIGN (Value);
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
+ //
+ // Next variable is in spare block.
+ //
+ Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
+ }
+ }
+
+ return (VARIABLE_HEADER *)Value;
+}
+
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Name1 Pointer to one variable name.
+ @param[in] Name2 Pointer to another variable name.
+ @param[in] NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialNameSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
+ //
+ // Name1 is inconsecutive.
+ //
+ PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
+ //
+ // Name2 is inconsecutive.
+ //
+ PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the variable in our database
+ @param[in] VariableHeader Pointer to the Variable Header that has
+ consecutive content.
+ @param[in] VariableName Name of the variable to compare to 'Variable'
+ @param[in] VendorGuid GUID of the variable to compare to 'Variable'
+ @param[out] PtrTrack Variable Track Pointer structure that contains
+ Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VOID *Point;
+ EFI_GUID *TempVendorGuid;
+
+ TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+ if (VariableName[0] == 0) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID a UINT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
+ (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
+ (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
+ (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
+ )
+ {
+ ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+ Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get variable header that has consecutive content.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] VariableHeader Pointer to Pointer to the Variable Header
+ that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PartialHeaderSize;
+
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Variable > (UINTN)SpareAddress) &&
+ (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
+ {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+
+ if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
+ //
+ // Variable header pointed by Variable is inconsecutive,
+ // create a guid hob to combine the two partial variable header content together.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+ PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+ }
+ }
+ } else {
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+ Get variable name or data to output buffer.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param[in] Size Variable name/data size.
+ @param[out] Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
+ //
+ // Variable name/data is inconsecutive.
+ //
+ PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem (Buffer, NameOrData, PartialSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
+ return;
+ }
+ }
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+
+ Internal function to retrieve variable information.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+ @param[in] StoreInfo Pointer to store copy of variable (optional).
+ @param[in] VariablePtr Pointer to variable buffer.
+ @param[in] VariableHeader Pointer to variable header.
+
+ @retval EFI_INVALID_PARAMETER One ore more required parameters are NULL.
+ @retval EFI_BUFFER_TOO_SMALL Given buffer is too small to hold data.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfoInternal (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN VARIABLE_STORE_INFO *StoreInfo OPTIONAL,
+ IN VARIABLE_HEADER *VariablePtr,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ VARIABLE_HEADER *VariableBuffer;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariableHeader;
+ UINTN NameSize;
+ UINTN DataSize;
+ UINTN VariableSize;
+
+ if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader == NULL)) {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariablePtr != NULL);
+ ASSERT (VariableHeader != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableBuffer = VariableInfo->Buffer;
+
+ //
+ // Make a copy of the whole variable if VariableInfo->Buffer is given. But
+ // don't do this if StoreInfo is not given, because VariableInfo->Buffer
+ // has already hold a copy of variable in such situation.
+ //
+ NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+ DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+ if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+ if (StoreInfo != NULL) {
+ CopyMem (
+ VariableBuffer,
+ VariableHeader,
+ GetVariableHeaderSize (VariableInfo->Flags.Auth)
+ );
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+ NameSize,
+ (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
+ );
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo->Flags.Auth),
+ DataSize,
+ (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader, VariableInfo->Flags.Auth)
+ );
+ } else {
+ //
+ // Suppose the variable is in consecutive space.
+ //
+ VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
+ + NameSize + GET_PAD_SIZE (NameSize)
+ + DataSize;
+ CopyMem (VariableBuffer, VariablePtr, VariableSize);
+ }
+ }
+
+ //
+ // Generally, if no consecutive buffer passed in, don't return back any data.
+ //
+ // If follow pointers are NULL, return back pointers to following data inside
+ // VariableInfo->Buffer, if it's given.
+ //
+ // VariableInfo->Header.VariableName
+ // VariableInfo->Header.Data
+ // VariableInfo->Header.VendorGuid
+ // VariableInfo->Header.TimeStamp
+ //
+ // Otherwise, suppose they're buffers used to hold a copy of corresponding
+ // data.
+ //
+ //
+
+ //
+ // AuthVariable header
+ //
+ if (VariableInfo->Flags.Auth) {
+ AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableHeader;
+
+ VariableInfo->Header.State = AuthVariableHeader->State;
+ VariableInfo->Header.Attributes = AuthVariableHeader->Attributes;
+ VariableInfo->Header.PubKeyIndex = AuthVariableHeader->PubKeyIndex;
+ VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+ &(AuthVariableHeader->MonotonicCount)
+ );
+ if (VariableInfo->Header.TimeStamp != NULL) {
+ CopyMem (
+ VariableInfo->Header.TimeStamp,
+ &AuthVariableHeader->TimeStamp,
+ sizeof (EFI_TIME)
+ );
+ } else if (VariableBuffer != NULL) {
+ AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+ VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
+ }
+ } else {
+ VariableInfo->Header.State = VariableHeader->State;
+ VariableInfo->Header.Attributes = VariableHeader->Attributes;
+ VariableInfo->Header.PubKeyIndex = 0;
+ VariableInfo->Header.MonotonicCount = 0;
+ VariableInfo->Header.TimeStamp = NULL;
+ }
+
+ //
+ // VendorGuid
+ //
+ if (VariableInfo->Header.VendorGuid != NULL) {
+ CopyGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.VendorGuid
+ = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
+ }
+
+ //
+ // VariableName
+ //
+ if ( (VariableInfo->Header.VariableName != NULL)
+ && (VariableInfo->Header.NameSize >= NameSize))
+ {
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+ NameSize,
+ (UINT8 *)VariableInfo->Header.VariableName
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.VariableName
+ = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
+ } else if (VariableInfo->Header.VariableName != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Data
+ //
+ if ( (VariableInfo->Header.Data != NULL)
+ && (VariableInfo->Header.DataSize >= DataSize))
+ {
+ GetVariableNameOrData (
+ StoreInfo,
+ GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
+ DataSize,
+ VariableInfo->Header.Data
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.Data
+ = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo->Flags.Auth);
+ } else if (VariableInfo->Header.Data != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Update size information about name & data.
+ //
+ VariableInfo->Header.NameSize = NameSize;
+ VariableInfo->Header.DataSize = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Retrieve details about a variable, given by VariableInfo->Buffer or
+ VariableInfo->Index, and pass the details back in VariableInfo->Header.
+
+ This function is used to resolve the variable data structure into
+ VariableInfo->Header, for easier access later without revisiting the variable
+ data in variable store. If pointers in the structure of VariableInfo->Header
+ are not NULL, it's supposed that they are buffers passed in to hold a copy of
+ data of corresponding data fields in variable data structure. Otherwise, this
+ function simply returns pointers pointing to address of those data fields.
+
+ The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
+ If VariableInfo->Index is given, this function finds the corresponding variable
+ first from variable storage according to the Index.
+
+ If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
+ that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
+ requested variable data to be returned.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Buffer
+ and VariableInfo->Index are NULL (0).
+ @retval EFI_NOT_FOUND If given Buffer or Index is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_TYPE StoreType;
+ VARIABLE_STORE_INFO StoreInfo;
+ UINTN Offset;
+
+ if ((VariableInfo == NULL) ||
+ ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo->Buffer != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StoreInfo.VariableStoreHeader = NULL;
+ for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+ GetVariableStore (StoreType, &StoreInfo);
+ if (StoreInfo.VariableStoreHeader != NULL) {
+ break;
+ }
+ }
+
+ ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+ //
+ // No StoreIndex? Don't retrieve variable information from store but just from
+ // VariableInfo->Buffer.
+ //
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = VariableInfo->Buffer;
+ VariableHeader = VariablePtr;
+
+ return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr, VariableHeader);
+ }
+
+ Offset = (UINTN)VariableInfo->StoreIndex;
+ if ( (StoreInfo.FtwLastWriteData != NULL)
+ && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader)))
+ {
+ Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+ }
+
+ //
+ // Note that variable might be in unconsecutive space. Always get a copy
+ // of its header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_TYPE StoreType;
+ UINTN Offset;
+
+ if (VariableInfo == NULL) {
+ ASSERT (VariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StoreInfo.VariableStoreHeader = NULL;
+ for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+ GetVariableStore (StoreType, &StoreInfo);
+ if (StoreInfo.VariableStoreHeader != NULL) {
+ break;
+ }
+ }
+
+ ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+ //
+ // VariableInfo->StoreIndex is supposed to be the index to variable found
+ // last time. Use it to get the variable next to it in store. If it's invalid,
+ // return the first variable available in store.
+ //
+ VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
+ } else {
+ Offset = (UINTN)VariableInfo->StoreIndex;
+ if ( (StoreInfo.FtwLastWriteData != NULL)
+ && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader)))
+ {
+ Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+ }
+
+ //
+ // Note that variable might be in unconsecutive space. Always get a copy
+ // of its header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
+ }
+
+ //
+ // Get a copy of variable header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Use the offset to the start of variable store as index of the variable.
+ //
+ if ( (StoreInfo.FtwLastWriteData == NULL)
+ || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData->TargetAddress))
+ {
+ VariableInfo->StoreIndex
+ = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
+ } else {
+ VariableInfo->StoreIndex
+ = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariableInfo->StoreIndex
+ += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData->SpareAddress);
+ }
+
+ if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
+ VariableInfo->Buffer = VariablePtr;
+ }
+
+ return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
new file mode 100644
index 000000000000..75edc3fc5051
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
@@ -0,0 +1,307 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+/**
+ Get variable store status.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
+ (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
+ )
+ {
+ return EfiValid;
+ }
+
+ if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
+ (VarStoreHeader->Size == 0xffffffff) &&
+ (VarStoreHeader->Format == 0xff) &&
+ (VarStoreHeader->State == 0xff)
+ )
+ {
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ Reports HOB variable store is available or not.
+
+ @retval EFI_NOT_READY HOB variable store info not available.
+ @retval EFI_NOT_FOUND HOB variable store is NOT available.
+ @retval EFI_SUCCESS HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *VariableStoreInfoHob;
+
+ //
+ // Discover if Variable Store Info Hob has been published by platform driver.
+ // It contains information regards to HOB or NV Variable Store availability
+ //
+ GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
+ if (GuidHob == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Check if HOB Variable Store is available
+ //
+ VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
+ if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This might be NV Variable Store
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get HOB variable store.
+
+ @param[out] StoreInfo Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Make sure there is no more than one Variable HOB.
+ //
+ DEBUG_CODE_BEGIN ();
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+ ASSERT (FALSE);
+ } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ }
+ }
+
+ DEBUG_CODE_END ();
+
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = TRUE;
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = FALSE;
+ }
+ }
+}
+
+/**
+ Get NV variable store.
+
+ @param[out] StoreInfo Return the store info.
+ @param[out] VariableFvHeader Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *StoreHeader;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *HobData;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT32 NvStorageSize;
+ UINT32 BackUpOffset;
+ UINT64 NvStorageSize64;
+
+ Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);
+ // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
+ ASSERT_EFI_ERROR (Status);
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
+
+ //
+ // Check the FTW last write data hob.
+ //
+ BackUpOffset = 0;
+ FtwLastWriteData = NULL;
+ HobData = NULL;
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+
+ if (GuidHob != NULL) {
+ HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
+ if (HobData->TargetAddress == NvStorageBase) {
+ //
+ // Let FvHeader point to spare block.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
+ (UINTN)HobData->SpareAddress
+ ));
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData->SpareAddress;
+ HobData = NULL;
+ } else if ((HobData->TargetAddress > NvStorageBase) &&
+ (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
+ {
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
+ DEBUG ((
+ EFI_D_INFO,
+ "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n",
+ BackUpOffset,
+ (UINTN)FtwLastWriteData->SpareAddress
+ ));
+ //
+ // At least one block data in flash NV storage is still valid, so still
+ // leave FvHeader point to NV storage base.
+ //
+ }
+ }
+
+ if (StoreInfo != NULL) {
+ StoreInfo->FtwLastWriteData = HobData;
+ }
+
+ if (VariableFvHeader != NULL) {
+ *VariableFvHeader = FvHeader;
+ }
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
+ CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
+ {
+ StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+ } else {
+ StoreHeader = NULL;
+ DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ }
+
+ if (StoreInfo != NULL) {
+ StoreInfo->VariableStoreHeader = StoreHeader;
+ if (StoreHeader != NULL) {
+ StoreInfo->AuthFlag = CompareGuid (
+ &StoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid
+ );
+ }
+ }
+}
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param[in] Type The type of the variable store.
+ @param[out] StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ StoreInfo->VariableStoreHeader = NULL;
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->FtwLastWriteData = NULL;
+ StoreInfo->AuthFlag = FALSE;
+ switch (Type) {
+ case VariableStoreTypeHob:
+ GetHobVariableStore (StoreInfo);
+ break;
+
+ case VariableStoreTypeNv:
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ //
+ // Emulated non-volatile variable mode is not enabled.
+ //
+ GetNvVariableStore (StoreInfo, NULL);
+ if (StoreInfo->VariableStoreHeader != NULL) {
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // If it's the first time to access variable region in flash, create a guid hob to record
+ // VAR_ADDED type variable info.
+ // Note that as the resource of PEI phase is limited, only store the limited number of
+ // VAR_ADDED type variables to reduce access time.
+ //
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+ StoreInfo->IndexTable->Length = 0;
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (StoreInfo->VariableStoreHeader);
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (StoreInfo->VariableStoreHeader);
+ StoreInfo->IndexTable->GoneThrough = 0;
+ }
+ }
+ }
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return StoreInfo->VariableStoreHeader;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
new file mode 100644
index 000000000000..106c1dfdc5c0
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI."
+
--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
next prev parent reply other threads:[~2022-11-06 7:35 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-06 7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
2022-11-06 7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
2022-11-06 7:34 ` [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
2022-11-06 7:34 ` [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
2022-11-06 7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
2022-11-22 6:31 ` Wang, Jian J
2022-11-06 7:34 ` [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-11-06 7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
2022-11-22 6:39 ` Wang, Jian J
2022-11-06 7:34 ` Judah Vang [this message]
2022-11-14 3:43 ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Wang, Jian J
[not found] ` <1727569A8ECB6F9D.19699@groups.io>
2022-11-14 4:27 ` [edk2-devel] " Wang, Jian J
2022-11-06 7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
2022-11-14 7:14 ` Wang, Jian J
2022-11-14 17:19 ` Judah Vang
2022-11-15 8:49 ` [edk2-devel] " Sami Mujawar
2022-11-22 6:26 ` Wang, Jian J
[not found] ` <1729D430BF77E016.5511@groups.io>
2022-11-22 6:42 ` Wang, Jian J
2022-11-06 7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
2022-11-22 6:44 ` Wang, Jian J
2022-11-06 7:35 ` [PATCH v5 10/19] SecurityPkg: Add new GUIDs for Judah Vang
2022-11-06 7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
2022-11-22 6:46 ` Wang, Jian J
2022-11-06 7:35 ` [PATCH v5 12/19] SecurityPkg: Add new variable types and functions Judah Vang
2022-11-06 7:35 ` [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index Judah Vang
2022-11-06 7:35 ` [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API Judah Vang
2022-11-06 7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
2022-11-22 6:55 ` Wang, Jian J
2022-11-06 7:35 ` [PATCH v5 16/19] SecurityPkg: Add VariableKey library function Judah Vang
2022-11-06 7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
2022-11-22 7:15 ` Wang, Jian J
2022-11-06 7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
2022-11-22 7:59 ` Wang, Jian J
2022-11-06 7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
2022-11-22 8:05 ` Wang, Jian J
2022-12-09 8:03 ` [edk2-devel] [PATCH v5 00/19] UEFI variable protection Yao, Jiewen
[not found] ` <172F11512E3044E7.1612@groups.io>
2022-12-09 9:41 ` Yao, Jiewen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221106073509.3071-8-judah.vang@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox