[Patch v2 09/28] MdeModulePkg: Add support for Protected Variables


Judah Vang
 

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

Add support for Protected Variables.
Add new API to retrieve Variable Infomation and data.
Add new API to update variable in non-volatile storage or
cached copy.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Liming Gao <gaoliming@...>
Cc: Nishant C Mistry <nishant.c.mistry@...>
Signed-off-by: Jian J Wang <jian.j.wang@...>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@...>
Signed-off-by: Judah Vang <judah.vang@...>
---
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf | 4 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139 +++++++++++---------
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320 ++-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c | 2 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c | 41 +-
15 files changed, 2454 insertions(+), 1053 deletions(-)

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index c9434df631ee..c0b90e6ca066 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -9,7 +9,7 @@
# This external input must be validated carefully to avoid security issues such as
# buffer overflow or integer overflow.
#
-# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -73,6 +73,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
index eaa97a01c6e5..6f9f027fbb0f 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -82,6 +82,7 @@ [LibraryClasses]
UefiBootServicesTableLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
index a0d8b2267e92..5d2fc78ea917 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -13,7 +13,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -61,6 +61,8 @@ [LibraryClasses]
SafeIntLib
PcdLib
MmUnblockMemoryLib
+ ProtectedVariableLib
+ IoLib

[Protocols]
gEfiVariableWriteArchProtocolGuid ## PRODUCES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
index d8c4f77e7f1f..6ea7b8d4293e 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -78,6 +78,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index 31e408976a35..97b4f9c906ff 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -2,7 +2,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by Variable modules.

-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/MemoryAllocationLib.h>
#include <Library/AuthVariableLib.h>
#include <Library/VarCheckLib.h>
+#include <Library/ProtectedVariableLib.h>
#include <Guid/GlobalVariable.h>
#include <Guid/EventGroup.h>
#include <Guid/VariableFormat.h>
@@ -823,4 +824,127 @@ VariableExLibAtRuntime (
VOID
);

+/**
+ Is user variable?
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ );
+
+/**
+
+ This function writes data to the FWH at the correct LBA even if the LBAs
+ are fragmented.
+
+ @param Global Pointer to VARIABLE_GLOBAL structure.
+ @param Volatile Point out the Variable is Volatile or Non-Volatile.
+ @param SetByIndex TRUE if target pointer is given as index.
+ FALSE if target pointer is absolute.
+ @param Fvb Pointer to the writable FVB protocol.
+ @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
+ structure.
+ @param DataSize Size of data to be written.
+ @param Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Parameters not valid.
+ @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
+ @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN SetByIndex,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN UINTN DataPtrIndex,
+ IN UINT32 DataSize,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Finds the given variable in a variable store in SMM.
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInSmm (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
index 951e8a089e34..3a4e8019aaf9 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
@@ -2,7 +2,7 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat Auth-variable indicator.

@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -27,7 +28,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
);

/**
@@ -192,6 +194,28 @@ GetVariableDataOffset (
IN BOOLEAN AuthFormat
);

+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] Data Pointer to buffer used to store the variable data.
+ @param[in] DataSize Size of buffer passed by Data.
+ @param[out] DataSize Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ );
+
/**

This code gets the pointer to the next variable header.
@@ -344,4 +368,67 @@ UpdateVariableInfo (
IN OUT VARIABLE_INFO_ENTRY **VariableInfo
);

+/**
+
+ 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 VariableStore Pointer to a variable storage. It's optional.
+ @param VariableStart Start point of valid range in VariableStore.
+ @param VariableEnd End point of valid range in VariableStore.
+ @param 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 *VarInfo
+ );
+
+/**
+
+ 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 VariableStore Pointer to a variable storage. It's optional.
+ @param 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 *VarInfo
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
index fe64d0a2b3dd..a5b7f8a1fbe2 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
@@ -2,12 +2,15 @@
Handles non-volatile variable store garbage collection, using FTW
(Fault Tolerant Write) protocol.

-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"

/**
Gets LBA of block and offset by given address.
@@ -155,3 +158,347 @@ FtwVariableSpace (

return Status;
}
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *AddedVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *NextAddedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ VOID *Point0;
+ VOID *Point1;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ EFI_STATUS DoneStatus;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_HEADER *UpdatingVariable;
+ VARIABLE_HEADER *UpdatingInDeletedTransition;
+ BOOLEAN AuthFormat;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ UpdatingVariable = NULL;
+ UpdatingInDeletedTransition = NULL;
+ if (UpdatingPtrTrack != NULL) {
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
+
+ CommonVariableTotalSize = 0;
+ CommonUserVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // Start Pointers for the variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
+ (Variable != UpdatingVariable) &&
+ (Variable != UpdatingInDeletedTransition)
+ )
+ {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ if (NewVariable != NULL) {
+ //
+ // Add the new variable size.
+ //
+ MaximumBufferSize += NewVariableSize;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
+ // as the buffer to reduce SMRAM consumption for SMM variable driver.
+ //
+ MaximumBufferSize = mNvVariableCache->Size;
+ ValidBuffer = (UINT8 *)mNvVariableCache;
+ }
+
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header.
+ //
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Reinstall all in delete transition variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+ (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFormat)) == FALSE))
+ {
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
+ NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
+ if (CompareGuid (
+ GetVendorGuidPtr (AddedVariable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat)
+ ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
+ {
+ Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
+ Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
+ if (CompareMem (Point0, Point1, NameSize) == 0) {
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+
+ AddedVariable = NextAddedVariable;
+ }
+
+ if (!FoundAdded) {
+ //
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+ //
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Install the new variable if it is not NULL.
+ //
+ if (NewVariable != NULL) {
+ if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
+ //
+ // No enough space to store the new variable.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (!IsVolatile) {
+ if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += NewVariableSize;
+ } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize += NewVariableSize;
+ if (IsUserVariable (NewVariable)) {
+ CommonUserVariableTotalSize += NewVariableSize;
+ }
+ }
+
+ if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ //
+ // No enough space to store the new variable by NV or NV+HR attribute.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (UpdatingVariable != NULL) {
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+ }
+
+ CurrPtr += NewVariableSize;
+ }
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.
+ //
+ SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
+ CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ if (!IsVolatile) {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ }
+
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, perform FTW here.
+ //
+ Status = FtwVariableSpace (
+ VariableBase,
+ (VARIABLE_STORE_HEADER *)ValidBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ } else {
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
+ Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
+ while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
+ }
+ }
+
+Done:
+ DoneStatus = EFI_SUCCESS;
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ FreePool (ValidBuffer);
+ } else {
+ //
+ // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
+ //
+ CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ }
+
+ if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
+ Status = DoneStatus;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
index 6c1a3440ac8c..6e86099eb72b 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -16,7 +16,7 @@
VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
integer overflow. It should also check attribute to avoid authentication bypass.

-Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.<BR>
Copyright (c) 2022, ARM Limited. All rights reserved.<BR>
@@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "VariableParsing.h"
#include "VariableRuntimeCache.h"

-VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;

///
/// Define a memory cache that improves the search performance for a variable.
@@ -458,7 +458,7 @@ CalculateCommonUserVariableTotalSize (
//
if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache), mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
@@ -497,330 +497,6 @@ InitializeVariableQuota (
CalculateCommonUserVariableTotalSize ();
}

-/**
-
- Variable store garbage collection and reclaim operation.
-
- @param[in] VariableBase Base address of variable store.
- @param[out] LastVariableOffset Offset of last variable.
- @param[in] IsVolatile The variable store is volatile or not;
- if it is non-volatile, need FTW.
- @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
- @param[in] NewVariable Pointer to new variable.
- @param[in] NewVariableSize New variable size.
-
- @return EFI_SUCCESS Reclaim operation has finished successfully.
- @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
- @return Others Unexpect error happened during reclaim operation.
-
-**/
-EFI_STATUS
-Reclaim (
- IN EFI_PHYSICAL_ADDRESS VariableBase,
- OUT UINTN *LastVariableOffset,
- IN BOOLEAN IsVolatile,
- IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
- IN VARIABLE_HEADER *NewVariable,
- IN UINTN NewVariableSize
- )
-{
- VARIABLE_HEADER *Variable;
- VARIABLE_HEADER *AddedVariable;
- VARIABLE_HEADER *NextVariable;
- VARIABLE_HEADER *NextAddedVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- UINT8 *ValidBuffer;
- UINTN MaximumBufferSize;
- UINTN VariableSize;
- UINTN NameSize;
- UINT8 *CurrPtr;
- VOID *Point0;
- VOID *Point1;
- BOOLEAN FoundAdded;
- EFI_STATUS Status;
- EFI_STATUS DoneStatus;
- UINTN CommonVariableTotalSize;
- UINTN CommonUserVariableTotalSize;
- UINTN HwErrVariableTotalSize;
- VARIABLE_HEADER *UpdatingVariable;
- VARIABLE_HEADER *UpdatingInDeletedTransition;
- BOOLEAN AuthFormat;
-
- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
- UpdatingVariable = NULL;
- UpdatingInDeletedTransition = NULL;
- if (UpdatingPtrTrack != NULL) {
- UpdatingVariable = UpdatingPtrTrack->CurrPtr;
- UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
- }
-
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
-
- CommonVariableTotalSize = 0;
- CommonUserVariableTotalSize = 0;
- HwErrVariableTotalSize = 0;
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Start Pointers for the variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
-
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
- (Variable != UpdatingVariable) &&
- (Variable != UpdatingInDeletedTransition)
- )
- {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- MaximumBufferSize += VariableSize;
- }
-
- Variable = NextVariable;
- }
-
- if (NewVariable != NULL) {
- //
- // Add the new variable size.
- //
- MaximumBufferSize += NewVariableSize;
- }
-
- //
- // Reserve the 1 Bytes with Oxff to identify the
- // end of the variable buffer.
- //
- MaximumBufferSize += 1;
- ValidBuffer = AllocatePool (MaximumBufferSize);
- if (ValidBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- } else {
- //
- // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
- // as the buffer to reduce SMRAM consumption for SMM variable driver.
- //
- MaximumBufferSize = mNvVariableCache->Size;
- ValidBuffer = (UINT8 *)mNvVariableCache;
- }
-
- SetMem (ValidBuffer, MaximumBufferSize, 0xff);
-
- //
- // Copy variable store header.
- //
- CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
- CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
-
- //
- // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Reinstall all in delete transition variables.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
- //
- // Buffer has cached all ADDED variable.
- // Per IN_DELETED variable, we have to guarantee that
- // no ADDED one in previous buffer.
- //
-
- FoundAdded = FALSE;
- AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
- while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer))) {
- NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
- NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
- if (CompareGuid (
- GetVendorGuidPtr (AddedVariable, AuthFormat),
- GetVendorGuidPtr (Variable, AuthFormat)
- ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
- {
- Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
- Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
- if (CompareMem (Point0, Point1, NameSize) == 0) {
- FoundAdded = TRUE;
- break;
- }
- }
-
- AddedVariable = NextAddedVariable;
- }
-
- if (!FoundAdded) {
- //
- // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
- //
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Install the new variable if it is not NULL.
- //
- if (NewVariable != NULL) {
- if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
- //
- // No enough space to store the new variable.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- if (!IsVolatile) {
- if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- HwErrVariableTotalSize += NewVariableSize;
- } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- CommonVariableTotalSize += NewVariableSize;
- if (IsUserVariable (NewVariable)) {
- CommonUserVariableTotalSize += NewVariableSize;
- }
- }
-
- if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
- (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
- (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
- {
- //
- // No enough space to store the new variable by NV or NV+HR attribute.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
-
- CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- if (UpdatingVariable != NULL) {
- UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
- UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
- }
-
- CurrPtr += NewVariableSize;
- }
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // If volatile/emulated non-volatile variable store, just copy valid buffer.
- //
- SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
- CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- if (!IsVolatile) {
- //
- // Emulated non-volatile variable mode.
- //
- mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
- }
-
- Status = EFI_SUCCESS;
- } else {
- //
- // If non-volatile variable store, perform FTW here.
- //
- Status = FtwVariableSpace (
- VariableBase,
- (VARIABLE_STORE_HEADER *)ValidBuffer
- );
- if (!EFI_ERROR (Status)) {
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
- } else {
- mVariableModuleGlobal->HwErrVariableTotalSize = 0;
- mVariableModuleGlobal->CommonVariableTotalSize = 0;
- mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
- Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
- while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
- } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
- }
- }
-
- Variable = NextVariable;
- }
-
- *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
- }
- }
-
-Done:
- DoneStatus = EFI_SUCCESS;
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- FreePool (ValidBuffer);
- } else {
- //
- // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
- //
- CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- }
-
- if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
- Status = DoneStatus;
- }
-
- return Status;
-}
-
/**
Finds variable in storage blocks of volatile and non-volatile storage areas.

@@ -1657,9 +1333,665 @@ AutoUpdateLangVariable (
}

/**
- Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
- index of associated public key is needed.
+ Check if there's enough free space in storage to write the new variable.

+ @param[in] NewVariable Pointer to buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] VolatileFlag Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Enough free space on variable storage.
+ @retval EFI_BUFFER_TOO_SMALL There's not enough continuous free space.
+ @retval EFI_OUT_OF_RESOURCES There's not enough free space in total.
+**/
+EFI_STATUS
+CheckVariableStoreSpace (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ if ((NewVariable == NULL) || (VariableSize == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ if (VolatileFlag) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ if ((UINT32)(VariableSize + mVariableModuleGlobal->VolatileLastVariableOffset)
+ > VarStore->Size)
+ {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+ IsCommonVariable = TRUE;
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ } else {
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ }
+
+ CommonVariableTotalSize = mVariableModuleGlobal->CommonVariableTotalSize + VariableSize;
+ CommonUserVariableTotalSize = mVariableModuleGlobal->CommonUserVariableTotalSize + VariableSize;
+ HwErrVariableTotalSize = mVariableModuleGlobal->HwErrVariableTotalSize + VariableSize;
+
+ if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) &&
+ (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)))
+ || (IsCommonVariable && (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace))
+ || (IsCommonVariable &&
+ AtRuntime () &&
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ || (IsCommonUserVariable &&
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)))
+ {
+ if (AtRuntime ()) {
+ if (IsCommonUserVariable &&
+ ((VariableSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill specific data of auth-variable in buffer.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+**/
+VOID
+SetVariableAuthData (
+ IN OUT AUTHENTICATED_VARIABLE_HEADER *NewVariable,
+ IN AUTHENTICATED_VARIABLE_HEADER *OldVariable,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ NewVariable->PubKeyIndex = KeyIndex;
+ NewVariable->MonotonicCount = MonotonicCount;
+
+ if ((TimeStamp != NULL) &&
+ ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0))
+ {
+ //
+ // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+ // when the new TimeStamp value is later than the current timestamp associated
+ // with the variable, we need associate the new timestamp with the updated value.
+ //
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ !VariableCompareTimeStampInternal (&OldVariable->TimeStamp, TimeStamp))
+ {
+ TimeStamp = &OldVariable->TimeStamp;
+ }
+
+ CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME));
+ }
+}
+
+/**
+ Fill the variable data buffer according to variable format on storage.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval Size of the new variable.
+
+**/
+UINTN
+SetVariableData (
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN VARIABLE_HEADER *OldVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ UINT8 *DataPtr;
+ UINTN NameSize;
+ UINTN OldDataSize;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if (AuthFormat) {
+ SetVariableAuthData (
+ (AUTHENTICATED_VARIABLE_HEADER *)NewVariable,
+ (AUTHENTICATED_VARIABLE_HEADER *)OldVariable,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ }
+
+ NewVariable->StartId = VARIABLE_DATA;
+ NewVariable->State = VAR_ADDED;
+ NewVariable->Reserved = 0;
+ NewVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+ CopyMem (
+ GetVendorGuidPtr (NewVariable, AuthFormat),
+ VendorGuid,
+ sizeof (EFI_GUID)
+ );
+
+ NameSize = StrSize (VariableName);
+ SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat);
+ CopyMem (
+ (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat),
+ VariableName,
+ NameSize
+ );
+
+ //
+ // Set data size first otherwise we can't get correct data pointer in the
+ // buffer of new variable.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat);
+ DataPtr = GetVariableDataPtr (NewVariable, AuthFormat);
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ ((OldVariable->State == VAR_ADDED) ||
+ (OldVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+ {
+ //
+ // Get old data, which might be encrypted.
+ //
+ OldDataSize = mVariableModuleGlobal->ScratchBufferSize
+ - ((UINTN)DataPtr - (UINTN)NewVariable);
+ Status = ProtectedVariableLibGetByBuffer (
+ OldVariable,
+ DataPtr,
+ (UINT32 *)&OldDataSize,
+ AuthFormat
+ );
+ if (Status == EFI_UNSUPPORTED) {
+ OldDataSize = DataSizeOfVariable (OldVariable, AuthFormat);
+ CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat), OldDataSize);
+ } else if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ DataPtr += OldDataSize;
+ //
+ // Update data size.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat);
+ }
+
+ CopyMem (DataPtr, Data, DataSize);
+
+ //
+ // The actual size of the variable stored in storage should include padding.
+ //
+ return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) - (UINTN)NewVariable);
+}
+
+/**
+ Update state of given variable as well as its cached copy.
+
+ @param[in,out] Variable Pointer to the buffer of the variable.
+ @param[in,out] CacheVariable Cache copy of the variable.
+ @param[in] NewState New state value.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Variable state was updated successfully.
+ @retval Others Failed to update the variable state.
+
+**/
+EFI_STATUS
+UpdateVariableState (
+ IN OUT VARIABLE_HEADER *Variable,
+ IN OUT VARIABLE_HEADER *CacheVariable,
+ IN UINT8 NewState,
+ IN BOOLEAN Volatile
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)&Variable->State,
+ sizeof (NewState),
+ &NewState
+ );
+ if (!EFI_ERROR (Status) && (CacheVariable != NULL)) {
+ CacheVariable->State = NewState;
+ }
+
+ return Status;
+}
+
+/**
+ Flush variable data to variable storage.
+
+ @param[in] VarStoreBase Base address of variable storage.
+ @param[in,out] Offset Offset to write the variable from.
+ Offset from where next variable can be written.
+ @param[in,out] NewVariable Pointer to the buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+ @param[in] AuthFormat Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were written successfully.
+ @retval Others Failed to write the variable data.
+
+**/
+EFI_STATUS
+WriteVariable (
+ IN EFI_PHYSICAL_ADDRESS VarStoreBase,
+ IN OUT UINTN *Offset,
+ IN OUT VARIABLE_HEADER **NewVariable,
+ IN UINT32 VariableSize,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN AuthFormat
+ )
+{
+ EFI_STATUS Status;
+
+ struct {
+ UINTN Offset;
+ UINT8 *Buffer;
+ UINT32 Size;
+ UINT8 State;
+ } WriteSteps[4];
+ UINTN Index;
+ UINTN Steps;
+ VARIABLE_HEADER *Variable;
+
+ Variable = *NewVariable;
+ if (Volatile) {
+ //
+ // For non-volatile variable, one step only :
+ //
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = VariableSize;
+
+ Steps = 1;
+ } else {
+ //
+ // Four steps for non-volatile variable:
+ //
+ // 1. Write variable header
+ // 2. Set variable state to header valid
+ // 3. Write variable name and data
+ // 4. Set variable state to valid
+ //
+ Variable->State = 0xff;
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = (UINT32)GetVariableHeaderSize (AuthFormat);
+
+ WriteSteps[1].State = VAR_HEADER_VALID_ONLY;
+ WriteSteps[1].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[1].Buffer = &WriteSteps[1].State;
+ WriteSteps[1].Size = sizeof (Variable->State);
+
+ WriteSteps[2].Offset = *Offset + GetVariableHeaderSize (AuthFormat);
+ WriteSteps[2].Buffer = (UINT8 *)Variable + GetVariableHeaderSize (AuthFormat);
+ WriteSteps[2].Size = VariableSize - (UINT32)GetVariableHeaderSize (AuthFormat);
+
+ WriteSteps[3].State = VAR_ADDED;
+ WriteSteps[3].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[3].Buffer = &WriteSteps[3].State;
+ WriteSteps[3].Size = sizeof (Variable->State);
+
+ Steps = ARRAY_SIZE (WriteSteps);
+ }
+
+ for (Index = 0; Index < Steps; ++Index) {
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ TRUE,
+ mVariableModuleGlobal->FvbInstance,
+ WriteSteps[Index].Offset,
+ WriteSteps[Index].Size,
+ WriteSteps[Index].Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ Variable->State = VAR_ADDED;
+ if (!Volatile) {
+ CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize);
+ }
+
+ *NewVariable = (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset);
+ *Offset += HEADER_ALIGN (VariableSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Rebase the given variable pointer(s) to the equivalent one in given variable
+ storage via VarStore.
+
+ @param[in] InVarTrackPtr Pointer to current variable in cache.
+ @param[out] OutVarTrackPtr Pointer to rebased variable against VarStore.
+ @param[in] VarStore Start of variable storage to rebase against.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] ByOffset If TRUE, don't do variable search in VarStore.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameters passed.
+ @retval EFI_NOT_FOUND Given variable (VariableName & VendorGuid) was
+ not found in VarStore, if ByOffset is FALSE.
+
+**/
+EFI_STATUS
+RebaseVariablePtr (
+ IN VARIABLE_POINTER_TRACK *InVarTrackPtr,
+ OUT VARIABLE_POINTER_TRACK *OutVarTrackPtr,
+ IN VARIABLE_STORE_HEADER *VarStore,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN ByOffset
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ VARIABLE_HEADER *NewStart;
+
+ if ((InVarTrackPtr == NULL) || (OutVarTrackPtr == NULL) || (VarStore == NULL)) {
+ ASSERT (InVarTrackPtr != NULL);
+ ASSERT (OutVarTrackPtr != NULL);
+ ASSERT (VarStore != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ( (InVarTrackPtr->CurrPtr == NULL)
+ || (InVarTrackPtr->StartPtr == GetStartPointer (VarStore)))
+ {
+ CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof (VARIABLE_POINTER_TRACK));
+ return EFI_SUCCESS;
+ }
+
+ NewStart = GetStartPointer (VarStore);
+ if (ByOffset) {
+ OutVarTrackPtr->CurrPtr = (VARIABLE_HEADER *)
+ ((UINTN)NewStart + ((UINTN)InVarTrackPtr->CurrPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+
+ if (InVarTrackPtr->InDeletedTransitionPtr != NULL) {
+ OutVarTrackPtr->InDeletedTransitionPtr =
+ (VARIABLE_HEADER *)((UINTN)NewStart +
+ ((UINTN)InVarTrackPtr->InDeletedTransitionPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+ } else {
+ OutVarTrackPtr->InDeletedTransitionPtr = NULL;
+ }
+
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+ } else {
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrackPtr, AuthFormat);
+ if ((OutVarTrackPtr->CurrPtr == NULL) || EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ( (VarStore == mNvVariableCache)
+ || ((UINTN)VarStore == (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))
+ {
+ OutVarTrackPtr->Volatile = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the given variable is from HOB.
+
+ @param[in] CacheVariable Pointer to current variable in cache.
+
+ @retval TRUE The variable is from HOB.
+ @retval FALSE The variable is NOT from HOB.
+
+**/
+BOOLEAN
+IsHobVariable (
+ IN VARIABLE_POINTER_TRACK *CacheVariable
+ )
+{
+ VARIABLE_STORE_HEADER *HobVarStore;
+
+ HobVarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ return (CacheVariable->CurrPtr != NULL &&
+ HobVarStore != NULL &&
+ CacheVariable->StartPtr == GetStartPointer (HobVarStore));
+}
+
+/**
+ Get temporary buffer for a new variable data.
+
+ @retval Pointer to the buffer address.
+
+**/
+VARIABLE_HEADER *
+GetNewVariableBuffer (
+ VOID
+ )
+{
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ NewVariable = GetEndPointer (VarStore);
+
+ SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff);
+
+ return NewVariable;
+}
+
+/**
+ Delete old copies of variable completely.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in,out] CacheVariable Pointer to current variable in cache.
+ @param[in] VolatileFlag Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval Others Failed to update variable state.
+
+**/
+EFI_STATUS
+DeleteVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ EFI_STATUS Status;
+
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+ //
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ Status = UpdateVariableState (
+ Variable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ ASSERT (CacheVariable->CurrPtr != NULL);
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ FALSE,
+ TRUE,
+ FALSE,
+ &gVariableInfo
+ );
+ if (!Variable->Volatile) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check if it's the right time to update a variable.
+
+ @param[in] Attributes Attributes of a variable.
+
+ @retval TRUE It's ready for variable update.
+ @retval FALSE It's NOT ready for variable update.
+
+**/
+BOOLEAN
+ReadyForUpdate (
+ IN UINT32 Attributes
+ )
+{
+ if ((mVariableModuleGlobal->FvbInstance == NULL) &&
+ !mVariableModuleGlobal->VariableGlobal.EmuNvMode)
+ {
+ //
+ // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ // is not installed.
+ //
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Trying to update NV variable prior to the installation of
+ // EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ //
+ // Trying to update volatile authenticated variable prior to the
+ // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The authenticated
+ // variable perhaps is not initialized, just return here.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check parameters associated with the variable to update.
+
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in] CacheVariable Pointer to current variable in cache.
@param[in] VariableName Name of variable.
@param[in] VendorGuid Guid of variable.
@param[in] Data Variable data.
@@ -1667,9 +1999,130 @@ AutoUpdateLangVariable (
@param[in] Attributes Attributes of the variable.
@param[in] KeyIndex Index of associated public key.
@param[in] MonotonicCount Value of associated monotonic count.
- @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
@param[in] TimeStamp Value of associated TimeStamp.

+ @retval EFI_SUCCESS The variable is ok to be updated.
+ @retval EFI_ALREADY_STARTED No need to update the variable.
+ @retval EFI_WRITE_PROTECTED The variable cannot be updated.
+ @retval EFI_INVALID_PARAMETER The variable attributes are not valid.
+ @retval EFI_NOT_FOUND Trying to delete non-existing variable.
+
+**/
+EFI_STATUS
+ValidateVariableParameters (
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN VARIABLE_POINTER_TRACK *CacheVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ BOOLEAN AuthFlag;
+
+ AuthFlag = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (Variable->CurrPtr != NULL) {
+ //
+ // Update/Delete existing variable.
+ //
+ if (AtRuntime ()) {
+ //
+ // If AtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Only variable that have NV attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only variable that have RT attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Variable content unchanged and no need to update timestamp, just return.
+ //
+ if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)
+ && (TimeStamp == NULL)
+ && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) == DataSize)
+ && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFlag), DataSize) == 0))
+ {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ //
+ // Create a new variable.
+ //
+
+ //
+ // Make sure we are trying to create a new variable. You cannot delete a new
+ // variable.
+ //
+ if ((DataSize == 0) ||
+ ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime.
+ //
+ if ( AtRuntime ()
+ && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)
+ || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in,out] CacheVariable The variable information which is used
+ to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
@retval EFI_SUCCESS The update operation is success.
@retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.

@@ -1687,710 +2140,381 @@ UpdateVariable (
IN EFI_TIME *TimeStamp OPTIONAL
)
{
- EFI_STATUS Status;
- VARIABLE_HEADER *NextVariable;
- UINTN ScratchSize;
- UINTN MaxDataSize;
- UINTN VarNameOffset;
- UINTN VarDataOffset;
- UINTN VarNameSize;
- UINTN VarSize;
- BOOLEAN Volatile;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- UINT8 State;
- VARIABLE_POINTER_TRACK *Variable;
- VARIABLE_POINTER_TRACK NvVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
- UINT8 *BufferForMerge;
- UINTN MergedBufSize;
- BOOLEAN DataReady;
- UINTN DataOffset;
- BOOLEAN IsCommonVariable;
- BOOLEAN IsCommonUserVariable;
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
- BOOLEAN AuthFormat;
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *VarGlobal;
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *UpdatingVariable;
+ UINTN VarSize;
+ UINTN UpdateSize;
+ UINTN Offset;
+ VARIABLE_POINTER_TRACK *Variable;
+ VARIABLE_POINTER_TRACK NvVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ BOOLEAN DeleteFlag;
+ BOOLEAN VolatileFlag;
+ BOOLEAN HobVarOnlyFlag;
+ EFI_PHYSICAL_ADDRESS VarStoreBase;
+ UINTN *LastVariableOffset;

- if ((mVariableModuleGlobal->FvbInstance == NULL) && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
- //
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- //
- DEBUG ((DEBUG_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- //
- // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- // The authenticated variable perhaps is not initialized, just return here.
- //
- DEBUG ((DEBUG_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- }
+ if (!ReadyForUpdate (Attributes)) {
+ return EFI_NOT_AVAILABLE_YET;
}

- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ VarGlobal = &mVariableModuleGlobal->VariableGlobal;
+
+ if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
+ || (Attributes == 0)
+ || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS
+ |EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)))
+ {
+ DeleteFlag = TRUE;
+ } else {
+ DeleteFlag = FALSE;
+ }
+
+ if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)
+ || ((CacheVariable->CurrPtr != NULL) &&
+ ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)))
+ {
+ VolatileFlag = FALSE;
+ } else {
+ VolatileFlag = TRUE;
+ }

//
// Check if CacheVariable points to the variable in variable HOB.
// If yes, let CacheVariable points to the variable in NV variable cache.
//
- if ((CacheVariable->CurrPtr != NULL) &&
- (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
- (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))
- )
- {
- CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
- CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
- CacheVariable->Volatile = FALSE;
- Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat);
+ HobVarOnlyFlag = FALSE;
+ if (IsHobVariable (CacheVariable)) {
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ CacheVariable,
+ mNvVariableCache,
+ VariableName,
+ VendorGuid,
+ FALSE
+ );
if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
//
// There is no matched variable in NV variable cache.
//
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ if (DeleteFlag) {
//
- // It is to delete variable,
- // go to delete this variable in variable HOB and
- // try to flush other variables from HOB to flash.
+ // Leave the deletion to FlushHobVariableToFlash() before return.
//
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- return EFI_SUCCESS;
+ HobVarOnlyFlag = TRUE;
+ Status = EFI_SUCCESS;
+ goto Done;
}
}
}

+ //
+ // Determine the physical position of variable store to update, due to cache
+ // mechanims of variable service.
+ //
if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
+ //
+ // - Add new variable (volatile or non-volatile); Or
+ // - Update/delete volatile variable in place.
+ //
Variable = CacheVariable;
} else {
//
- // Update/Delete existing NV variable.
- // CacheVariable points to the variable in the memory copy of Flash area
- // Now let Variable points to the same variable in Flash area.
+ // - Update/Delete existing NV variable.
+ // CacheVariable points to the variable in the memory copy of Flash area.
+ // Now let Variable points to the same variable in Flash area.
//
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
- Variable = &NvVariable;
- Variable->StartPtr = GetStartPointer (VariableStoreHeader);
- Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
-
- Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
- if (CacheVariable->InDeletedTransitionPtr != NULL) {
- Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
- } else {
- Variable->InDeletedTransitionPtr = NULL;
- }
-
- Variable->Volatile = FALSE;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)
+ VarGlobal->NonVolatileVariableBase;
+ Variable = &NvVariable;
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ Variable,
+ VariableStoreHeader,
+ VariableName,
+ VendorGuid,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
}

- Fvb = mVariableModuleGlobal->FvbInstance;
-
//
- // Tricky part: Use scratch data area at the end of volatile variable store
- // as a temporary storage.
+ // Validate variable parameters.
//
- NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
- ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
- SetMem (NextVariable, ScratchSize, 0xff);
- DataReady = FALSE;
-
- if (Variable->CurrPtr != NULL) {
- //
- // Update/Delete existing variable.
- //
- if (AtRuntime ()) {
- //
- // If AtRuntime and the variable is Volatile and Runtime Access,
- // the volatile is ReadOnly, and SetVariable should be aborted and
- // return EFI_WRITE_PROTECTED.
- //
- if (Variable->Volatile) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
-
- //
- // Only variable that have NV attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Only variable that have RT attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Setting a data variable with no access, or zero DataSize attributes
- // causes it to be deleted.
- // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
- // not delete the variable.
- //
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- FlushHobVariableToFlash (VariableName, VendorGuid);
- }
- }
+ Status = ValidateVariableParameters (
+ Variable,
+ CacheVariable,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }

- goto Done;
- }
+ //
+ // Add or update a variable. Allocate a buffer to hold it temporarily.
+ //
+ NewVariable = GetNewVariableBuffer ();

+ //
+ // Fill-up variable data first, if necessary.
+ //
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ if (DeleteFlag) {
//
- // If the variable is marked valid, and the same data has been passed in,
- // then return to the caller immediately.
+ // No need to fill up variable buffer when deleting a variable. But the
+ // buffer is still needed if variable protection is employed.
//
- if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize) &&
- (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) &&
- ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
- (TimeStamp == NULL))
- {
- //
- // Variable content unchanged and no need to update timestamp, just return.
- //
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- Status = EFI_SUCCESS;
- goto Done;
- } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
- (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
- {
- //
- // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
- //
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
- //
- // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
- // From DataOffset of NextVariable is to save the existing variable data.
- //
- DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat);
- BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);
- CopyMem (
- BufferForMerge,
- (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),
- DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
- );
-
- //
- // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
- //
- if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
- } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
- } else {
- MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
- }
-
- //
- // Append the new data to the end of existing data.
- // Max Harware error record variable data size is different from common/auth variable.
- //
- if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
- }
-
- if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) {
- //
- // Existing data size + new data size exceed maximum variable size limitation.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (
- (UINT8 *)(
- (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
- ),
- Data,
- DataSize
- );
- MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) +
- DataSize;
-
- //
- // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
- //
- Data = BufferForMerge;
- DataSize = MergedBufSize;
- DataReady = TRUE;
- }
-
- //
- // Mark the old variable as in delete transition.
- //
- State = CacheVariable->CurrPtr->State;
- State &= VAR_IN_DELETED_TRANSITION;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ VarSize = 0;
} else {
- //
- // Not found existing variable. Create a new variable.
- //
+ VarSize = SetVariableData (
+ NewVariable,
+ CacheVariable->CurrPtr,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );

- if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Make sure we are trying to create a new variable.
- // Setting a data variable with zero DataSize or no access attributes means to delete it.
- //
- if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Only variable have NV|RT attribute can be created in Runtime.
- //
- if (AtRuntime () &&
- (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
- {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Function part - create a new variable and copy the data.
- // Both update a variable and create a variable will come here.
- //
- NextVariable->StartId = VARIABLE_DATA;
- //
- // NextVariable->State = VAR_ADDED;
- //
- NextVariable->Reserved = 0;
- if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)NextVariable;
- AuthVariable->PubKeyIndex = KeyIndex;
- AuthVariable->MonotonicCount = MonotonicCount;
- ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
-
- if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
- (TimeStamp != NULL))
- {
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- //
- // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
- // when the new TimeStamp value is later than the current timestamp associated
- // with the variable, we need associate the new timestamp with the updated value.
- //
- if (Variable->CurrPtr != NULL) {
- if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
- }
- }
- }
- }
- }
-
- //
- // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
- // Attributes bitmask parameter of a GetVariable() call.
- //
- NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
-
- VarNameOffset = GetVariableHeaderSize (AuthFormat);
- VarNameSize = StrSize (VariableName);
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarNameOffset),
- VariableName,
- VarNameSize
- );
- VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
-
- //
- // If DataReady is TRUE, it means the variable data has been saved into
- // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
- //
- if (!DataReady) {
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarDataOffset),
- Data,
- DataSize
- );
- }
-
- CopyMem (
- GetVendorGuidPtr (NextVariable, AuthFormat),
- VendorGuid,
- sizeof (EFI_GUID)
- );
- //
- // There will be pad bytes after Data, the NextVariable->NameSize and
- // NextVariable->DataSize should not include pad size so that variable
- // service can get actual size in GetVariable.
- //
- SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
- SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
-
- //
- // The actual size of the variable that stores in storage should
- // include pad size.
- //
- VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Create a nonvolatile variable.
- //
- Volatile = FALSE;
-
- IsCommonVariable = FALSE;
- IsCommonUserVariable = FALSE;
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
IsCommonVariable = TRUE;
- IsCommonUserVariable = IsUserVariable (NextVariable);
+ IsCommonUserVariable = IsUserVariable (NewVariable);
}
+ }

- if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
- && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
- || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
- || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
- || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)))
- {
- if (AtRuntime ()) {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
-
- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
-
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
- &mVariableModuleGlobal->NonVolatileLastVariableOffset,
- FALSE,
- Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
- );
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- } else {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
+ //
+ // We might need to do protection for non-volatile variable before flushing
+ // the data to storage. A null version (meaning no protection) of following
+ // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any
+ // changes to original data.
+ //
+ if (!VolatileFlag) {
+ Status = ProtectedVariableLibUpdate (
+ Variable->CurrPtr,
+ Variable->InDeletedTransitionPtr,
+ NewVariable,
+ &VarSize
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }

- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
- }
+ Status = EFI_SUCCESS;
+ }

+ //
+ // Mark the old variable as in delete transition first. There's no such need
+ // for deleting a variable, even if variable protection is employed.
+ //
+ if ( !DeleteFlag
+ && (CacheVariable->CurrPtr != NULL)
+ && ( (CacheVariable->CurrPtr->State == VAR_ADDED)
+ || (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+ {
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION,
+ Variable->Volatile
+ );
+ if (EFI_ERROR (Status)) {
goto Done;
}
-
- if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Four steps
- // 1. Write variable header
- // 2. Set variable state to header valid
- // 3. Write variable data
- // 4. Set variable state to valid
- //
- //
- // Step 1:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)GetVariableHeaderSize (AuthFormat),
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 2:
- //
- NextVariable->State = VAR_HEADER_VALID_ONLY;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 3:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (AuthFormat),
- (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),
- (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)
+ }
+
+ //
+ // Have enough space to store the variable?
+ //
+ Status = CheckVariableStoreSpace (
+ NewVariable,
+ VarSize,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VolatileFlag
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ //
+ // Not a chance.
+ //
+ goto Done;
+ }
+
+ //
+ // Maybe not...
+ //
+ VarStoreBase = (VolatileFlag) ? VarGlobal->VolatileVariableBase
+ : VarGlobal->NonVolatileVariableBase;
+ LastVariableOffset = (VolatileFlag)
+ ? &mVariableModuleGlobal->VolatileLastVariableOffset
+ : &mVariableModuleGlobal->NonVolatileLastVariableOffset;
+ if (!EFI_ERROR (Status)) {
+ //
+ // There's enough free space at the tail of variable storage.
+ //
+
+ //
+ // If non-volatile variable is protected, a separate variable (MetaDataHmacVar)
+ // is always updated along with current updating variable. The buffer pointed
+ // by NewVariable must have two variables. They should be written at this
+ // time orderly.
+ //
+ NextVariable = NewVariable;
+ UpdatingVariable = NULL;
+ UpdateSize = 0;
+ while ( !EFI_ERROR (Status)
+ && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize)
+ {
+ UpdatingVariable = NextVariable;
+ NextVariable = GetNextVariablePtr (UpdatingVariable, VarGlobal->AuthFormat);
+ UpdateSize = (UINTN)NextVariable - (UINTN)UpdatingVariable;
+
+ Status = WriteVariable (
+ VarStoreBase,
+ LastVariableOffset,
+ &UpdatingVariable,
+ (UINT32)UpdateSize,
+ VolatileFlag,
+ VarGlobal->AuthFormat
);
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 4:
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Update the memory copy of Flash region.
- //
- CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
- } else {
- //
- // Emulated non-volatile variable mode.
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
}

- mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
-
+ //
+ // UpdatingVariable must point to the last written variable. Restore it to
+ // the first one so that we can calculate the offset in variable storage.
+ //
+ UpdatingVariable = (VARIABLE_HEADER *)((UINTN)UpdatingVariable + UpdateSize
+ - VarSize);
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
} else {
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
if (IsCommonUserVariable) {
- mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VarSize;
}
}
- } else {
- //
- // Create a volatile variable.
- //
- Volatile = TRUE;

- if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
- ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size)
- {
- //
- // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
- &mVariableModuleGlobal->VolatileLastVariableOffset,
- TRUE,
+ //
+ // Mark the old variable(s) as deleted.
+ //
+ if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
+ Status = DeleteVariable (
+ VariableName,
+ VendorGuid,
Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
+ CacheVariable,
+ VolatileFlag
);
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- }
-
- goto Done;
}
-
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- TRUE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->VolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
- }
-
- //
- // Mark the old variable as deleted.
- //
- if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION old variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
+ } else {
+ //
+ // There's not enough space at the tail of variable storage but there's
+ // enough free space holes in the whole storage. Perform garbage collection
+ // & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ VarStoreBase,
+ LastVariableOffset,
+ VolatileFlag,
+ Variable,
+ NewVariable,
+ VarSize
);
- if (!EFI_ERROR (Status) && !Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ UpdatingVariable = Variable->CurrPtr;

- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- if (!Volatile) {
- FlushHobVariableToFlash (VariableName, VendorGuid);
+ if (EFI_ERROR (Status) &&
+ ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0))
+ {
+ //
+ // Out of space.
+ //
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ IsCommonVariable = TRUE;
+
+ if (IsCommonUserVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
}
}

Done:
if (!EFI_ERROR (Status)) {
- if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
- VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);
+ if (!VolatileFlag) {
+ Offset = (UpdatingVariable != NULL) ? (UINTN)UpdatingVariable - (UINTN)VarStoreBase
+ : 0;
+ Status = ProtectedVariableLibWriteFinal (
+ NewVariable,
+ VarSize,
+ Offset
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ VolatileFlag,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ //
+ // HOB copy of the same variable is no longer needed, no matter it has
+ // been deleted, updated or added from/to real variable storage.
+ //
+ if (HobVarOnlyFlag || !VolatileFlag) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+
+ if (!VolatileFlag) {
+ VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeNvCache);
} else {
- VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
+ VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
}

if (VolatileCacheInstance->Store != NULL) {
@@ -2401,6 +2525,11 @@ Done:
);
ASSERT_EFI_ERROR (Status);
}
+ } else if (Status == EFI_ALREADY_STARTED) {
+ //
+ // Meaning nothing needs to be done. Just return success.
+ //
+ Status = EFI_SUCCESS;
}

return Status;
@@ -2440,7 +2569,6 @@ VariableServiceGetVariable (
{
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
- UINTN VarDataSize;

if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -2458,28 +2586,26 @@ VariableServiceGetVariable (
}

//
- // Get data size
+ // Get data and its size
//
- VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- ASSERT (VarDataSize != 0);
+ if (!Variable.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (
+ Variable.CurrPtr,
+ Data,
+ (UINT32 *)DataSize,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ }

- if (*DataSize >= VarDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
+ if (Variable.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }

- CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);
-
- *DataSize = VarDataSize;
+ if (!EFI_ERROR (Status)) {
UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = VarDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
}

Done:
@@ -2860,7 +2986,7 @@ VariableServiceSetVariable (
// Parse non-volatile variable data and get last variable offset.
//
NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
- while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
+ while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) {
NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
}

@@ -3022,7 +3148,12 @@ VariableServiceQueryVariableInfoInternal (
//
// Now walk through the related variable store.
//
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (VariableStoreHeader),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;

@@ -3315,7 +3446,7 @@ FlushHobVariableToFlash (
//
mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
for ( Variable = GetStartPointer (VariableStoreHeader)
- ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
+ ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)
; Variable = GetNextVariablePtr (Variable, AuthFormat)
)
{
@@ -3525,11 +3656,11 @@ ConvertNormalVarStorageToAuthVarStorage (
VARIABLE_HEADER *StartPtr;
UINT8 *NextPtr;
VARIABLE_HEADER *EndPtr;
- UINTN AuthVarStroageSize;
+ UINTN AuthVarStorageSize;
AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
VARIABLE_STORE_HEADER *AuthVarStorage;

- AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
+ AuthVarStorageSize = sizeof (VARIABLE_STORE_HEADER);
//
// Set AuthFormat as FALSE for normal variable storage
//
@@ -3542,10 +3673,10 @@ ConvertNormalVarStorageToAuthVarStorage (
EndPtr = GetEndPointer (NormalVarStorage);
while (StartPtr < EndPtr) {
if (StartPtr->State == VAR_ADDED) {
- AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
- AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
- AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
- AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
+ AuthVarStorageSize = HEADER_ALIGN (AuthVarStorageSize);
+ AuthVarStorageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ AuthVarStorageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
+ AuthVarStorageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
}

StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
@@ -3554,7 +3685,7 @@ ConvertNormalVarStorageToAuthVarStorage (
//
// Allocate Runtime memory for Auth Variable Storage
//
- AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
+ AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStorageSize);
ASSERT (AuthVarStorage != NULL);
if (AuthVarStorage == NULL) {
return NULL;
@@ -3608,7 +3739,7 @@ ConvertNormalVarStorageToAuthVarStorage (
AuthVarStorage->State = NormalVarStorage->State;
AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
- ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
+ ASSERT (AuthVarStorage->Size <= AuthVarStorageSize);

//
// Restore AuthFormat
@@ -3774,7 +3905,7 @@ VariableCommonInitialize (
//
// Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
//
- ScratchSize = GetMaxVariableSize ();
+ ScratchSize = GetMaxVariableSize () * 2;
mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
if (VolatileVariableStore == NULL) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index 03fec3048dc4..52bf29ec4c5c 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -3,7 +3,7 @@
and volatile storage space and install variable architecture protocol.

Copyright (C) 2013, Red Hat, Inc.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <Protocol/VariablePolicy.h>
#include <Library/VariablePolicyLib.h>
+#include "VariableParsing.h"

EFI_STATUS
EFIAPI
@@ -534,6 +535,29 @@ VariableServiceInitialize (
EFI_EVENT ReadyToBootEvent;
EFI_EVENT EndOfDxeEvent;

+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialze protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
index 62cde0335512..5904bcbff78a 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
@@ -1,13 +1,14 @@
/** @file
Provides variable driver extended services.

-Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "Variable.h"
#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"

/**
Finds variable in storage blocks of volatile and non-volatile storage areas.
@@ -38,6 +39,7 @@ VariableExLibFindVariable (
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ PROTECTED_VARIABLE_INFO VarInfo;

Status = FindVariable (
VariableName,
@@ -56,9 +58,12 @@ VariableExLibFindVariable (
return Status;
}

- AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
+ AuthVariableInfo->NameSize = NameSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VariableName = GetVariableNamePtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VendorGuid = GetVendorGuidPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable.CurrPtr;
AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
@@ -66,6 +71,24 @@ VariableExLibFindVariable (
AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
}

+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = Variable.CurrPtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+ VarInfo.Flags.Auth = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // In case the variable is encrypted.
+ //
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}

@@ -99,6 +122,7 @@ VariableExLibFindNextVariable (
VARIABLE_HEADER *VariablePtr;
AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ PROTECTED_VARIABLE_INFO VarInfo;

VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
@@ -123,6 +147,7 @@ VariableExLibFindNextVariable (
return Status;
}

+ AuthVariableInfo->NameSize = NameSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
@@ -135,6 +160,20 @@ VariableExLibFindNextVariable (
AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
}

+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = VariablePtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}

@@ -256,3 +295,123 @@ VariableExLibAtRuntime (
{
return AtRuntime ();
}
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *Global;
+ VARIABLE_RUNTIME_CACHE *CacheInstance;
+ VARIABLE_HEADER *VariableCache;
+
+ if ((mVariableModuleGlobal == NULL) || (mNvVariableCache == NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Flush the cache to store.
+ //
+ if (Size == (UINT32)-1) {
+ Status = FtwVariableSpace (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ mNvVariableCache
+ );
+ if ( !EFI_ERROR (Status)
+ && (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0))
+ {
+ FlushHobVariableToFlash (NULL, NULL);
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ }
+ }
+
+ return Status;
+ }
+
+ if ( (VariableInfo == NULL)
+ || (VariableInfo->StoreIndex == VAR_INDEX_INVALID)
+ || (Buffer == NULL)
+ || (Size == 0))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+ ASSERT (Buffer != NULL);
+ ASSERT (Size != 0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Global = &mVariableModuleGlobal->VariableGlobal;
+
+ VariableCache = (VARIABLE_HEADER *)((UINTN)mNvVariableCache + (UINTN)VariableInfo->StoreIndex);
+
+ ASSERT (
+ StrCmp (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariableCache, Global->AuthFormat)
+ ) == 0
+ );
+ ASSERT (
+ CompareGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariableCache, Global->AuthFormat)
+ )
+ );
+
+ //
+ // Forcibly update part data of flash copy of the variable ...
+ //
+ Status = UpdateVariableStore (
+ Global,
+ FALSE,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)(Global->NonVolatileVariableBase + VariableInfo->StoreIndex + Offset),
+ Size,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // ... as well as the local cached copy.
+ //
+ CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size);
+
+ //
+ // Sync remote cached copy.
+ //
+ CacheInstance = &Global->VariableRuntimeCacheContext.VariableRuntimeNvCache;
+ if (CacheInstance->Store != NULL) {
+ Status = SynchronizeRuntimeVariableCache (
+ CacheInstance,
+ (UINTN)VariableInfo->StoreIndex + Offset,
+ Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
index 5e9d40b67ac2..e8b8f0b7f705 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
@@ -1,7 +1,7 @@
/** @file
Common variable non-volatile store routines.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -120,6 +120,181 @@ InitEmuNonVolatileVariableStore (
return EFI_SUCCESS;
}

+/**
+
+ Create a dummy variable used to fill the gap in NV variable storage caused by
+ the invalid variables found in HMAC verification phase.
+
+ @param[out] Variable Variable buffer.
+ @param[in] Name Variable Name.
+ @param[in] Guid Vendor GUID of the variable.
+ @param[in] Size Whole size of the variable requested.
+ @param[in] AuthFlag Variable format flag.
+
+**/
+STATIC
+VOID
+CreateDummyVariable (
+ OUT VARIABLE_HEADER *Variable,
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN UINT32 Size,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ ASSERT (Variable != NULL);
+
+ if (Name == NULL) {
+ Name = L"Dummy";
+ }
+
+ if (AuthFlag) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+ AuthVariable->StartId = VARIABLE_DATA;
+ AuthVariable->State = VAR_ADDED & VAR_DELETED;
+ AuthVariable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ AuthVariable->NameSize = (UINT32)StrSize (Name);
+ AuthVariable->DataSize = Size - sizeof (AUTHENTICATED_VARIABLE_HEADER)
+ - AuthVariable->NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, AuthVariable->NameSize);
+ } else {
+ Variable->StartId = VARIABLE_DATA;
+ Variable->State = VAR_ADDED & VAR_DELETED;
+ Variable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ Variable->NameSize = (UINT32)StrSize (Name);
+ Variable->DataSize = Size - sizeof (VARIABLE_HEADER) - Variable->NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, Variable->NameSize);
+ }
+}
+
+/**
+
+ Init protected variable store.
+
+ @param[in, out] VariableStore Pointer to real protected variable store base.
+
+**/
+EFI_STATUS
+InitProtectedVariableStore (
+ IN OUT VARIABLE_STORE_HEADER *VariableStore
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ UINTN Size;
+ UINTN Index;
+ BOOLEAN AuthFlag;
+ EFI_PHYSICAL_ADDRESS NextVariableStore;
+ EFI_PHYSICAL_ADDRESS *VarList;
+ UINTN NumVars;
+ UINTN CurrVar;
+
+ SetMem (
+ (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER),
+ VariableStore->Size - sizeof (VARIABLE_STORE_HEADER),
+ 0xFF
+ );
+ Index = sizeof (VARIABLE_STORE_HEADER);
+
+ VarList = NULL;
+ NumVars = 0;
+ ProtectedVariableLibGetSortedList (&VarList, &NumVars);
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+
+ for (CurrVar = 0; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ break;
+ }
+
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ continue;
+ } else {
+ ASSERT (VarInfo.StoreIndex == HEADER_ALIGN (VarInfo.StoreIndex));
+ ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof (VARIABLE_STORE_HEADER)));
+ ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHeaderSize (AuthFlag));
+ }
+
+ //
+ // Fill gap caused by invalid variable.
+ //
+ if (VarInfo.StoreIndex > Index) {
+ Size = (UINTN)VarInfo.StoreIndex - Index;
+ CreateDummyVariable (
+ (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index),
+ NULL,
+ NULL,
+ (UINT32)Size,
+ AuthFlag
+ );
+ Index += Size;
+ }
+
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer, Size);
+
+ Index += Size;
+ Index = HEADER_ALIGN (Index);
+
+ NextVariableStore = (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore + VarInfo.StoreIndex + Size);
+ }
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ for ( ; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)&NextVariableStore, VarInfo.Buffer, Size);
+ Status = ProtectedVariableLibRefresh (VarInfo.Buffer, 0, NextVariableStore - (UINTN)VariableStore, FALSE);
+ NextVariableStore = NextVariableStore + Size;
+ }
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
/**
Init real non-volatile variable store.

@@ -230,6 +405,16 @@ InitRealNonVolatileVariableStore (
return EFI_VOLUME_CORRUPTED;
}

+ //
+ // Overwrite the store with verified copy of protected variables, if enabled.
+ //
+ Status = InitProtectedVariableStore (VariableStore);
+ if ((Status != EFI_SUCCESS) && (Status != EFI_UNSUPPORTED)) {
+ FreePool (NvStorageData);
+ DEBUG ((DEBUG_ERROR, "Variable integrity might have been compromised\n"));
+ return Status;
+ }
+
mNvFvHeaderCache = FvHeader;

*VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
@@ -323,7 +508,12 @@ InitNonVolatileVariableStore (
// Parse non-volatile variable data and get last variable offset.
//
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (mNvVariableCache),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
index 39060ed405b8..000e4b546888 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
@@ -2,11 +2,12 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

+#include "Variable.h"
#include "VariableParsing.h"

/**
@@ -15,6 +16,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.

@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -23,10 +26,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
)
{
- if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
+ if ( (Variable == NULL)
+ || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >= (UINTN)VariableStoreEnd)
+ || (Variable->StartId != VARIABLE_DATA))
+ {
//
// Variable is NULL or has reached the end of variable store,
// or the StartId is not correct.
@@ -341,6 +348,52 @@ GetVariableDataOffset (
return Value;
}

+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in,out] Data Pointer to buffer used to store the variable data.
+ @param[in,out] DataSize Size of buffer passed by Data.
+ Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINT32 Size;
+
+ if (DataSize == NULL) {
+ ASSERT (DataSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size = (UINT32)DataSizeOfVariable (Variable, AuthFlag);
+ if (*DataSize < Size) {
+ *DataSize = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Data == NULL) {
+ ASSERT (Data != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size);
+ *DataSize = Size;
+
+ return EFI_SUCCESS;
+}
+
/**

This code gets the pointer to the next variable header.
@@ -479,7 +532,7 @@ FindVariableEx (
InDeletedVariable = NULL;

for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
- ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
+ ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, AuthFormat)
; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
)
{
@@ -608,7 +661,7 @@ VariableServiceGetNextVariableInternal (
//
// Switch to the next variable store if needed
//
- while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
+ while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr, AuthFormat)) {
//
// Find current storage index
//
@@ -804,3 +857,260 @@ UpdateVariableInfo (
}
}
}
+
+/**
+
+ 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
+ )
+{
+ VARIABLE_STORE_HEADER *Stores[2];
+ UINTN Index;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableBuffer;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
+ BOOLEAN AuthFlag;
+ UINTN NameSize;
+ UINTN DataSize;
+ UINTN VariableSize;
+
+ if ((VariableInfo == NULL) || ( (VariableInfo->Buffer == NULL)
+ && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->Buffer != NULL || VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Stores[0] = mNvVariableCache;
+ Stores[1] = (mVariableModuleGlobal != NULL)
+ ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
+ : NULL;
+
+ VariableBuffer = VariableInfo->Buffer;
+ VariablePtr = NULL;
+ if (VariableInfo->StoreIndex != VAR_INDEX_INVALID) {
+ for (Index = 0; Index < ARRAY_SIZE (Stores); ++Index) {
+ if (Stores[Index] == NULL) {
+ continue;
+ }
+
+ if ((UINTN)VariableInfo->StoreIndex
+ < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]))
+ {
+ VariablePtr = (VARIABLE_HEADER *)((UINTN)Stores[Index] + (UINTN)VariableInfo->StoreIndex);
+ VariableInfo->Buffer = VariablePtr;
+ break;
+ }
+ }
+ } else {
+ VariablePtr = VariableInfo->Buffer;
+ }
+
+ if (VariablePtr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+ ASSERT (AuthFlag == TRUE || AuthFlag == FALSE);
+
+ //
+ // Make a copy of the whole variable if a buffer is passed in.
+ //
+ if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+ VariableSize = (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag)
+ - (UINTN)VariablePtr;
+ CopyMem (VariableBuffer, VariablePtr, VariableSize);
+ }
+
+ //
+ // AuthVariable header
+ //
+ if (AuthFlag) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
+
+ VariableInfo->Header.State = AuthVariablePtr->State;
+ VariableInfo->Header.Attributes = AuthVariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = AuthVariablePtr->PubKeyIndex;
+ VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+ &(AuthVariablePtr->MonotonicCount)
+ );
+ if (VariableInfo->Header.TimeStamp != NULL) {
+ CopyMem (
+ VariableInfo->Header.TimeStamp,
+ &AuthVariablePtr->TimeStamp,
+ sizeof (EFI_TIME)
+ );
+ } else if (VariableBuffer != NULL) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+ VariableInfo->Header.TimeStamp = &AuthVariablePtr->TimeStamp;
+ }
+ } else {
+ VariableInfo->Header.State = VariablePtr->State;
+ VariableInfo->Header.Attributes = VariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = 0;
+ VariableInfo->Header.MonotonicCount = 0;
+ VariableInfo->Header.TimeStamp = NULL;
+ }
+
+ //
+ // VendorGuid
+ //
+ if (VariableInfo->Header.VendorGuid != NULL) {
+ CopyGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariablePtr, AuthFlag)
+ );
+ } else {
+ VariableInfo->Header.VendorGuid = GetVendorGuidPtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // VariableName
+ //
+ NameSize = NameSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.VariableName != NULL)
+ && (VariableInfo->Header.NameSize >= NameSize))
+ {
+ CopyMem (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.VariableName != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.VariableName = GetVariableNamePtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // Data
+ //
+ DataSize = DataSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.Data != NULL)
+ && (VariableInfo->Header.DataSize >= DataSize))
+ {
+ CopyMem (
+ VariableInfo->Header.Data,
+ GetVariableDataPtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.Data != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.Data = GetVariableDataPtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // Update size information about name & data.
+ //
+ VariableInfo->Header.NameSize = NameSize;
+ VariableInfo->Header.DataSize = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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
+ )
+{
+ VARIABLE_STORE_HEADER *VarStore;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableStart;
+ VARIABLE_HEADER *VariableEnd;
+ BOOLEAN AuthFlag;
+
+ if (VariableInfo == NULL) {
+ ASSERT (VariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mNvVariableCache != NULL) {
+ VarStore = mNvVariableCache;
+ } else if (mVariableModuleGlobal != NULL) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStart = GetStartPointer (VarStore);
+ VariableEnd = GetEndPointer (VarStore);
+
+ if ((VariableInfo->Flags.Auth != TRUE) && (VariableInfo->Flags.Auth != FALSE)) {
+ VariableInfo->Flags.Auth = CompareGuid (
+ &VarStore->Signature,
+ &gEfiAuthenticatedVariableGuid
+ );
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = VariableStart;
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex);
+ if (VariablePtr >= VariableEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariablePtr = GetNextVariablePtr (VariablePtr, AuthFlag);
+ }
+
+ if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableInfo->StoreIndex = (UINTN)VariablePtr - (UINTN)VarStore;
+ return GetVariableInfo (VariableInfo);
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
index 9bb30bc1e804..dc319feee727 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
@@ -7,7 +7,7 @@
This external input must be validated carefully to avoid security issue like
buffer overflow, integer overflow.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
index 517cae7b00f8..c2b689f6202d 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -14,7 +14,7 @@
VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
SmmVariableGetStatistics() should also do validation based on its own knowledge.

-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -1045,6 +1045,13 @@ VariableWriteServiceInitializeSmm (
{
EFI_STATUS Status;

+ Status = ProtectedVariableLibWriteInit ();
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
Status = VariableWriteServiceInitialize ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
@@ -1143,10 +1150,32 @@ MmVariableServiceInitialize (
VOID
)
{
- EFI_STATUS Status;
- EFI_HANDLE VariableHandle;
- VOID *SmmFtwRegistration;
- VOID *SmmEndOfDxeRegistration;
+ EFI_STATUS Status;
+ EFI_HANDLE VariableHandle;
+ VOID *SmmFtwRegistration;
+ VOID *SmmEndOfDxeRegistration;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialize protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }

//
// Variable initialize.
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
index 4aaeb5ba8806..8fb8679671ad 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -13,7 +13,7 @@

InitCommunicateBuffer() is really function to check the variable data size.

-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -36,11 +36,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/MmUnblockMemoryLib.h>
+#include <Library/IoLib.h>

#include <Guid/EventGroup.h>
#include <Guid/SmmVariableCommon.h>

#include "PrivilegePolymorphic.h"
+#include "Variable.h"
#include "VariableParsing.h"

EFI_HANDLE mHandle = NULL;
@@ -53,6 +55,8 @@ VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
UINTN mVariableBufferSize;
UINTN mVariableRuntimeHobCacheBufferSize;
UINTN mVariableRuntimeNvCacheBufferSize;
@@ -616,7 +620,6 @@ FindVariableInRuntimeCache (
)
{
EFI_STATUS Status;
- UINTN TempDataSize;
VARIABLE_POINTER_TRACK RtPtrTrack;
VARIABLE_STORE_TYPE StoreType;
VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
@@ -669,31 +672,23 @@ FindVariableInRuntimeCache (
//
// Get data size
//
- TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
- ASSERT (TempDataSize != 0);
-
- if (*DataSize >= TempDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
- *DataSize = TempDataSize;
-
- UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = TempDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
+ if (!RtPtrTrack.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+ }
+
+ if (RtPtrTrack.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, FALSE, &mVariableInfo);
}
}
}

-Done:
if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {
*Attributes = RtPtrTrack.CurrPtr->Attributes;
--
2.35.1.windows.2


Wang, Jian J
 

Judah,

See my inline comments below.

Regards,
Jian

-----Original Message-----
From: Vang, Judah <judah.vang@...>
Sent: Saturday, April 30, 2022 2:04 AM
To: devel@edk2.groups.io
Cc: Wang, Jian J <jian.j.wang@...>; Gao, Liming
<gaoliming@...>; Mistry, Nishant C <nishant.c.mistry@...>
Subject: [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables

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

Add support for Protected Variables.
Add new API to retrieve Variable Infomation and data.
Add new API to update variable in non-volatile storage or
cached copy.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Liming Gao <gaoliming@...>
Cc: Nishant C Mistry <nishant.c.mistry@...>
Signed-off-by: Jian J Wang <jian.j.wang@...>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@...>
Signed-off-by: Judah Vang <judah.vang@...>
---
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3
+-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf |
4 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf |
3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139
+++++++++++---------
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194
+-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320
++-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c |
2 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c |
41 +-
15 files changed, 2454 insertions(+), 1053 deletions(-)

diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index c9434df631ee..c0b90e6ca066 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -9,7 +9,7 @@
# This external input must be validated carefully to avoid security issues such as
# buffer overflow or integer overflow.
#
-# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -73,6 +73,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
index eaa97a01c6e5..6f9f027fbb0f 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these
resources,
# the authentication service provided in this driver will be broken, and the
behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -82,6 +82,7 @@ [LibraryClasses]
UefiBootServicesTableLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
index a0d8b2267e92..5d2fc78ea917 100644
---
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+++
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -13,7 +13,7 @@
# may not be modified without authorization. If platform fails to protect these
resources,
# the authentication service provided in this driver will be broken, and the
behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -61,6 +61,8 @@ [LibraryClasses]
SafeIntLib
PcdLib
MmUnblockMemoryLib
+ ProtectedVariableLib
+ IoLib
[JianJW]
Why's IoLib needed here? I didn't find any of its interfaces used in this patch.


[Protocols]
gEfiVariableWriteArchProtocolGuid ## PRODUCES
diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
index d8c4f77e7f1f..6ea7b8d4293e 100644
---
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+++
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these
resources,
# the authentication service provided in this driver will be broken, and the
behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -78,6 +78,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib

[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index 31e408976a35..97b4f9c906ff 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -2,7 +2,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by Variable modules.

-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/MemoryAllocationLib.h>
#include <Library/AuthVariableLib.h>
#include <Library/VarCheckLib.h>
+#include <Library/ProtectedVariableLib.h>
#include <Guid/GlobalVariable.h>
#include <Guid/EventGroup.h>
#include <Guid/VariableFormat.h>
@@ -823,4 +824,127 @@ VariableExLibAtRuntime (
VOID
);

+/**
+ Is user variable?
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or
variable space.
+ @return Others Unexpect error happened during reclaim
operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ );
+
+/**
+
+ This function writes data to the FWH at the correct LBA even if the LBAs
+ are fragmented.
+
+ @param Global Pointer to VARIABLE_GLOBAL structure.
+ @param Volatile Point out the Variable is Volatile or Non-Volatile.
+ @param SetByIndex TRUE if target pointer is given as index.
+ FALSE if target pointer is absolute.
+ @param Fvb Pointer to the writable FVB protocol.
+ @param DataPtrIndex Pointer to the Data from the end of
VARIABLE_STORE_HEADER
+ structure.
+ @param DataSize Size of data to be written.
+ @param Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Parameters not valid.
+ @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable
update.
+ @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN SetByIndex,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN UINTN DataPtrIndex,
+ IN UINT32 DataSize,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not
valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Finds the given variable in a variable store in SMM.
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to
avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInSmm (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
index 951e8a089e34..3a4e8019aaf9 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
@@ -2,7 +2,7 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat Auth-variable indicator.

@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -27,7 +28,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
);

/**
@@ -192,6 +194,28 @@ GetVariableDataOffset (
IN BOOLEAN AuthFormat
);

+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] Data Pointer to buffer used to store the variable data.
+ @param[in] DataSize Size of buffer passed by Data.
+ @param[out] DataSize Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable
data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ );
+
/**

This code gets the pointer to the next variable header.
@@ -344,4 +368,67 @@ UpdateVariableInfo (
IN OUT VARIABLE_INFO_ENTRY **VariableInfo
);

+/**
+
+ 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 VariableStore Pointer to a variable storage. It's optional.
+ @param VariableStart Start point of valid range in VariableStore.
+ @param VariableEnd End point of valid range in VariableStore.
+ @param VariableInfo Pointer to variable information.
[JianJW]
The parameters don't match the prototype below

+
+ @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 *VarInfo
+ );
+
+/**
+
+ 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 VariableStore Pointer to a variable storage. It's optional.
+ @param VariableInfo Pointer to variable information.
[JianJW]
The parameters doesn't match the prototype below

+
+ @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 *VarInfo
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
index fe64d0a2b3dd..a5b7f8a1fbe2 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
@@ -2,12 +2,15 @@
Handles non-volatile variable store garbage collection, using FTW
(Fault Tolerant Write) protocol.

-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"

/**
Gets LBA of block and offset by given address.
@@ -155,3 +158,347 @@ FtwVariableSpace (

return Status;
}
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or
variable space.
+ @return Others Unexpect error happened during reclaim
operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *AddedVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *NextAddedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ VOID *Point0;
+ VOID *Point1;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ EFI_STATUS DoneStatus;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_HEADER *UpdatingVariable;
+ VARIABLE_HEADER *UpdatingInDeletedTransition;
+ BOOLEAN AuthFormat;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ UpdatingVariable = NULL;
+ UpdatingInDeletedTransition = NULL;
+ if (UpdatingPtrTrack != NULL) {
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
+
+ CommonVariableTotalSize = 0;
+ CommonUserVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // Start Pointers for the variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if (((Variable->State == VAR_ADDED) || (Variable->State ==
(VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
+ (Variable != UpdatingVariable) &&
+ (Variable != UpdatingInDeletedTransition)
+ )
+ {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ if (NewVariable != NULL) {
+ //
+ // Add the new variable size.
+ //
+ MaximumBufferSize += NewVariableSize;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // For NV variable reclaim, don't allocate pool here and just use
mNvVariableCache
+ // as the buffer to reduce SMRAM consumption for SMM variable driver.
+ //
+ MaximumBufferSize = mNvVariableCache->Size;
+ ValidBuffer = (UINT8 *)mNvVariableCache;
+ }
+
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header.
+ //
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof
(VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables as long as they are not identical to Updating
Variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Reinstall all in delete transition variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable !=
UpdatingInDeletedTransition) && (Variable->State ==
(VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+ (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFormat))
== FALSE))
+ {
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, GetEndPointer
((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
+ NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
+ if (CompareGuid (
+ GetVendorGuidPtr (AddedVariable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat)
+ ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
+ {
+ Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
+ Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
+ if (CompareMem (Point0, Point1, NameSize) == 0) {
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+
+ AddedVariable = NextAddedVariable;
+ }
+
+ if (!FoundAdded) {
+ //
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+ //
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Install the new variable if it is not NULL.
+ //
+ if (NewVariable != NULL) {
+ if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize >
VariableStoreHeader->Size) {
+ //
+ // No enough space to store the new variable.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (!IsVolatile) {
+ if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
== EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += NewVariableSize;
+ } else if ((NewVariable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize += NewVariableSize;
+ if (IsUserVariable (NewVariable)) {
+ CommonUserVariableTotalSize += NewVariableSize;
+ }
+ }
+
+ if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+ (CommonVariableTotalSize > mVariableModuleGlobal-
CommonVariableSpace) ||
+ (CommonUserVariableTotalSize > mVariableModuleGlobal-
CommonMaxUserVariableSpace))
+ {
+ //
+ // No enough space to store the new variable by NV or NV+HR attribute.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (UpdatingVariable != NULL) {
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER
*)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr -
(UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+ }
+
+ CurrPtr += NewVariableSize;
+ }
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.
+ //
+ SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
+ CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr -
(UINTN)ValidBuffer);
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ if (!IsVolatile) {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ mVariableModuleGlobal->HwErrVariableTotalSize =
HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize =
CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize =
CommonUserVariableTotalSize;
+ }
+
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, perform FTW here.
+ //
+ Status = FtwVariableSpace (
+ VariableBase,
+ (VARIABLE_STORE_HEADER *)ValidBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ mVariableModuleGlobal->HwErrVariableTotalSize =
HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize =
CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize =
CommonUserVariableTotalSize;
+ } else {
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
+ Variable = GetStartPointer
((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
+ while (IsValidVariableHeader (Variable, GetEndPointer
((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
== EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else if ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize +=
VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
+ }
+ }
+
+Done:
+ DoneStatus = EFI_SUCCESS;
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ FreePool (ValidBuffer);
+ } else {
+ //
+ // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy
the data back.
+ //
+ CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase,
VariableStoreHeader->Size);
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ }
+
+ if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
+ Status = DoneStatus;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
index 6c1a3440ac8c..6e86099eb72b 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -16,7 +16,7 @@
VariableServiceSetVariable() should also check authenticate data to avoid
buffer overflow,
integer overflow. It should also check attribute to avoid authentication bypass.

-Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.<BR>
Copyright (c) 2022, ARM Limited. All rights reserved.<BR>
@@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "VariableParsing.h"
#include "VariableRuntimeCache.h"

-VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;

///
/// Define a memory cache that improves the search performance for a variable.
@@ -458,7 +458,7 @@ CalculateCommonUserVariableTotalSize (
//
if (mEndOfDxe && (mVariableModuleGlobal-
CommonMaxUserVariableSpace != mVariableModuleGlobal-
CommonVariableSpace)) {
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache),
mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
@@ -497,330 +497,6 @@ InitializeVariableQuota (
CalculateCommonUserVariableTotalSize ();
}

-/**
-
- Variable store garbage collection and reclaim operation.
-
- @param[in] VariableBase Base address of variable store.
- @param[out] LastVariableOffset Offset of last variable.
- @param[in] IsVolatile The variable store is volatile or not;
- if it is non-volatile, need FTW.
- @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
track structure.
- @param[in] NewVariable Pointer to new variable.
- @param[in] NewVariableSize New variable size.
-
- @return EFI_SUCCESS Reclaim operation has finished successfully.
- @return EFI_OUT_OF_RESOURCES No enough memory resources or
variable space.
- @return Others Unexpect error happened during reclaim
operation.
-
-**/
-EFI_STATUS
-Reclaim (
- IN EFI_PHYSICAL_ADDRESS VariableBase,
- OUT UINTN *LastVariableOffset,
- IN BOOLEAN IsVolatile,
- IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
- IN VARIABLE_HEADER *NewVariable,
- IN UINTN NewVariableSize
- )
-{
- VARIABLE_HEADER *Variable;
- VARIABLE_HEADER *AddedVariable;
- VARIABLE_HEADER *NextVariable;
- VARIABLE_HEADER *NextAddedVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- UINT8 *ValidBuffer;
- UINTN MaximumBufferSize;
- UINTN VariableSize;
- UINTN NameSize;
- UINT8 *CurrPtr;
- VOID *Point0;
- VOID *Point1;
- BOOLEAN FoundAdded;
- EFI_STATUS Status;
- EFI_STATUS DoneStatus;
- UINTN CommonVariableTotalSize;
- UINTN CommonUserVariableTotalSize;
- UINTN HwErrVariableTotalSize;
- VARIABLE_HEADER *UpdatingVariable;
- VARIABLE_HEADER *UpdatingInDeletedTransition;
- BOOLEAN AuthFormat;
-
- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
- UpdatingVariable = NULL;
- UpdatingInDeletedTransition = NULL;
- if (UpdatingPtrTrack != NULL) {
- UpdatingVariable = UpdatingPtrTrack->CurrPtr;
- UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
- }
-
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
-
- CommonVariableTotalSize = 0;
- CommonUserVariableTotalSize = 0;
- HwErrVariableTotalSize = 0;
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Start Pointers for the variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
-
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
{
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if (((Variable->State == VAR_ADDED) || (Variable->State ==
(VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
- (Variable != UpdatingVariable) &&
- (Variable != UpdatingInDeletedTransition)
- )
- {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- MaximumBufferSize += VariableSize;
- }
-
- Variable = NextVariable;
- }
-
- if (NewVariable != NULL) {
- //
- // Add the new variable size.
- //
- MaximumBufferSize += NewVariableSize;
- }
-
- //
- // Reserve the 1 Bytes with Oxff to identify the
- // end of the variable buffer.
- //
- MaximumBufferSize += 1;
- ValidBuffer = AllocatePool (MaximumBufferSize);
- if (ValidBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- } else {
- //
- // For NV variable reclaim, don't allocate pool here and just use
mNvVariableCache
- // as the buffer to reduce SMRAM consumption for SMM variable driver.
- //
- MaximumBufferSize = mNvVariableCache->Size;
- ValidBuffer = (UINT8 *)mNvVariableCache;
- }
-
- SetMem (ValidBuffer, MaximumBufferSize, 0xff);
-
- //
- // Copy variable store header.
- //
- CopyMem (ValidBuffer, VariableStoreHeader, sizeof
(VARIABLE_STORE_HEADER));
- CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
-
- //
- // Reinstall all ADDED variables as long as they are not identical to Updating
Variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
{
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Reinstall all in delete transition variables.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
{
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable !=
UpdatingInDeletedTransition) && (Variable->State ==
(VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
- //
- // Buffer has cached all ADDED variable.
- // Per IN_DELETED variable, we have to guarantee that
- // no ADDED one in previous buffer.
- //
-
- FoundAdded = FALSE;
- AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
- while (IsValidVariableHeader (AddedVariable, GetEndPointer
((VARIABLE_STORE_HEADER *)ValidBuffer))) {
- NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
- NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
- if (CompareGuid (
- GetVendorGuidPtr (AddedVariable, AuthFormat),
- GetVendorGuidPtr (Variable, AuthFormat)
- ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
- {
- Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
- Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
- if (CompareMem (Point0, Point1, NameSize) == 0) {
- FoundAdded = TRUE;
- break;
- }
- }
-
- AddedVariable = NextAddedVariable;
- }
-
- if (!FoundAdded) {
- //
- // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
- //
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Install the new variable if it is not NULL.
- //
- if (NewVariable != NULL) {
- if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize >
VariableStoreHeader->Size) {
- //
- // No enough space to store the new variable.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- if (!IsVolatile) {
- if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
== EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- HwErrVariableTotalSize += NewVariableSize;
- } else if ((NewVariable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- CommonVariableTotalSize += NewVariableSize;
- if (IsUserVariable (NewVariable)) {
- CommonUserVariableTotalSize += NewVariableSize;
- }
- }
-
- if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
- (CommonVariableTotalSize > mVariableModuleGlobal-
CommonVariableSpace) ||
- (CommonUserVariableTotalSize > mVariableModuleGlobal-
CommonMaxUserVariableSpace))
- {
- //
- // No enough space to store the new variable by NV or NV+HR attribute.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
-
- CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- if (UpdatingVariable != NULL) {
- UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER
*)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr -
(UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
- UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
- }
-
- CurrPtr += NewVariableSize;
- }
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // If volatile/emulated non-volatile variable store, just copy valid buffer.
- //
- SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
- CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr -
(UINTN)ValidBuffer);
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- if (!IsVolatile) {
- //
- // Emulated non-volatile variable mode.
- //
- mVariableModuleGlobal->HwErrVariableTotalSize =
HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize =
CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize =
CommonUserVariableTotalSize;
- }
-
- Status = EFI_SUCCESS;
- } else {
- //
- // If non-volatile variable store, perform FTW here.
- //
- Status = FtwVariableSpace (
- VariableBase,
- (VARIABLE_STORE_HEADER *)ValidBuffer
- );
- if (!EFI_ERROR (Status)) {
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- mVariableModuleGlobal->HwErrVariableTotalSize =
HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize =
CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize =
CommonUserVariableTotalSize;
- } else {
- mVariableModuleGlobal->HwErrVariableTotalSize = 0;
- mVariableModuleGlobal->CommonVariableTotalSize = 0;
- mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
- Variable = GetStartPointer
((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
- while (IsValidVariableHeader (Variable, GetEndPointer
((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
- } else if ((Variable->Attributes &
EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
- }
- }
-
- Variable = NextVariable;
- }
-
- *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
- }
- }
-
-Done:
- DoneStatus = EFI_SUCCESS;
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- FreePool (ValidBuffer);
- } else {
- //
- // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy
the data back.
- //
- CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase,
VariableStoreHeader->Size);
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- }
-
- if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
- Status = DoneStatus;
- }
-
- return Status;
-}
-
/**
Finds variable in storage blocks of volatile and non-volatile storage areas.

@@ -1657,9 +1333,665 @@ AutoUpdateLangVariable (
}

/**
- Update the variable region with Variable information. If
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
- index of associated public key is needed.
+ Check if there's enough free space in storage to write the new variable.

+ @param[in] NewVariable Pointer to buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] VolatileFlag Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Enough free space on variable storage.
+ @retval EFI_BUFFER_TOO_SMALL There's not enough continuous free space.
+ @retval EFI_OUT_OF_RESOURCES There's not enough free space in total.
+**/
+EFI_STATUS
+CheckVariableStoreSpace (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ if ((NewVariable == NULL) || (VariableSize == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ if (VolatileFlag) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ if ((UINT32)(VariableSize + mVariableModuleGlobal-
VolatileLastVariableOffset)
+ > VarStore->Size)
+ {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+ IsCommonVariable = TRUE;
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ } else {
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ }
+
+ CommonVariableTotalSize = mVariableModuleGlobal-
CommonVariableTotalSize + VariableSize;
+ CommonUserVariableTotalSize = mVariableModuleGlobal-
CommonUserVariableTotalSize + VariableSize;
+ HwErrVariableTotalSize = mVariableModuleGlobal-
HwErrVariableTotalSize + VariableSize;
+
+ if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) &&
+ (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)))
+ || (IsCommonVariable && (CommonVariableTotalSize >
mVariableModuleGlobal->CommonVariableSpace))
+ || (IsCommonVariable &&
+ AtRuntime () &&
+ (CommonVariableTotalSize > mVariableModuleGlobal-
CommonRuntimeVariableSpace))
+ || (IsCommonUserVariable &&
+ (CommonUserVariableTotalSize > mVariableModuleGlobal-
CommonMaxUserVariableSpace)))
+ {
+ if (AtRuntime ()) {
+ if (IsCommonUserVariable &&
+ ((VariableSize + mVariableModuleGlobal-
CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill specific data of auth-variable in buffer.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+**/
+VOID
+SetVariableAuthData (
+ IN OUT AUTHENTICATED_VARIABLE_HEADER *NewVariable,
+ IN AUTHENTICATED_VARIABLE_HEADER *OldVariable,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ NewVariable->PubKeyIndex = KeyIndex;
+ NewVariable->MonotonicCount = MonotonicCount;
+
+ if ((TimeStamp != NULL) &&
+ ((Attributes &
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0))
+ {
+ //
+ // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+ // when the new TimeStamp value is later than the current timestamp
associated
+ // with the variable, we need associate the new timestamp with the updated
value.
+ //
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ !VariableCompareTimeStampInternal (&OldVariable->TimeStamp,
TimeStamp))
+ {
+ TimeStamp = &OldVariable->TimeStamp;
+ }
+
+ CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME));
+ }
+}
+
+/**
+ Fill the variable data buffer according to variable format on storage.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval Size of the new variable.
+
+**/
+UINTN
+SetVariableData (
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN VARIABLE_HEADER *OldVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ UINT8 *DataPtr;
+ UINTN NameSize;
+ UINTN OldDataSize;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if (AuthFormat) {
+ SetVariableAuthData (
+ (AUTHENTICATED_VARIABLE_HEADER *)NewVariable,
+ (AUTHENTICATED_VARIABLE_HEADER *)OldVariable,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ }
+
+ NewVariable->StartId = VARIABLE_DATA;
+ NewVariable->State = VAR_ADDED;
+ NewVariable->Reserved = 0;
+ NewVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+ CopyMem (
+ GetVendorGuidPtr (NewVariable, AuthFormat),
+ VendorGuid,
+ sizeof (EFI_GUID)
+ );
+
+ NameSize = StrSize (VariableName);
+ SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat);
+ CopyMem (
+ (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat),
+ VariableName,
+ NameSize
+ );
+
+ //
+ // Set data size first otherwise we can't get correct data pointer in the
+ // buffer of new variable.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat);
+ DataPtr = GetVariableDataPtr (NewVariable, AuthFormat);
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ ((OldVariable->State == VAR_ADDED) ||
+ (OldVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+ {
+ //
+ // Get old data, which might be encrypted.
+ //
+ OldDataSize = mVariableModuleGlobal->ScratchBufferSize
+ - ((UINTN)DataPtr - (UINTN)NewVariable);
+ Status = ProtectedVariableLibGetByBuffer (
+ OldVariable,
+ DataPtr,
+ (UINT32 *)&OldDataSize,
+ AuthFormat
+ );
+ if (Status == EFI_UNSUPPORTED) {
+ OldDataSize = DataSizeOfVariable (OldVariable, AuthFormat);
+ CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat),
OldDataSize);
+ } else if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ DataPtr += OldDataSize;
+ //
+ // Update data size.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat);
+ }
+
+ CopyMem (DataPtr, Data, DataSize);
+
+ //
+ // The actual size of the variable stored in storage should include padding.
+ //
+ return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) -
(UINTN)NewVariable);
+}
+
+/**
+ Update state of given variable as well as its cached copy.
+
+ @param[in,out] Variable Pointer to the buffer of the variable.
+ @param[in,out] CacheVariable Cache copy of the variable.
+ @param[in] NewState New state value.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Variable state was updated successfully.
+ @retval Others Failed to update the variable state.
+
+**/
+EFI_STATUS
+UpdateVariableState (
+ IN OUT VARIABLE_HEADER *Variable,
+ IN OUT VARIABLE_HEADER *CacheVariable,
+ IN UINT8 NewState,
+ IN BOOLEAN Volatile
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)&Variable->State,
+ sizeof (NewState),
+ &NewState
+ );
+ if (!EFI_ERROR (Status) && (CacheVariable != NULL)) {
+ CacheVariable->State = NewState;
+ }
+
+ return Status;
+}
+
+/**
+ Flush variable data to variable storage.
+
+ @param[in] VarStoreBase Base address of variable storage.
+ @param[in,out] Offset Offset to write the variable from.
+ Offset from where next variable can be written.
+ @param[in,out] NewVariable Pointer to the buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+ @param[in] AuthFormat Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were written successfully.
+ @retval Others Failed to write the variable data.
+
+**/
+EFI_STATUS
+WriteVariable (
+ IN EFI_PHYSICAL_ADDRESS VarStoreBase,
+ IN OUT UINTN *Offset,
+ IN OUT VARIABLE_HEADER **NewVariable,
+ IN UINT32 VariableSize,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN AuthFormat
+ )
+{
+ EFI_STATUS Status;
+
+ struct {
+ UINTN Offset;
+ UINT8 *Buffer;
+ UINT32 Size;
+ UINT8 State;
+ } WriteSteps[4];
+ UINTN Index;
+ UINTN Steps;
+ VARIABLE_HEADER *Variable;
+
+ Variable = *NewVariable;
+ if (Volatile) {
+ //
+ // For non-volatile variable, one step only :
+ //
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = VariableSize;
+
+ Steps = 1;
+ } else {
+ //
+ // Four steps for non-volatile variable:
+ //
+ // 1. Write variable header
+ // 2. Set variable state to header valid
+ // 3. Write variable name and data
+ // 4. Set variable state to valid
+ //
+ Variable->State = 0xff;
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = (UINT32)GetVariableHeaderSize (AuthFormat);
+
+ WriteSteps[1].State = VAR_HEADER_VALID_ONLY;
+ WriteSteps[1].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[1].Buffer = &WriteSteps[1].State;
+ WriteSteps[1].Size = sizeof (Variable->State);
+
+ WriteSteps[2].Offset = *Offset + GetVariableHeaderSize (AuthFormat);
+ WriteSteps[2].Buffer = (UINT8 *)Variable + GetVariableHeaderSize
(AuthFormat);
+ WriteSteps[2].Size = VariableSize - (UINT32)GetVariableHeaderSize
(AuthFormat);
+
+ WriteSteps[3].State = VAR_ADDED;
+ WriteSteps[3].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[3].Buffer = &WriteSteps[3].State;
+ WriteSteps[3].Size = sizeof (Variable->State);
+
+ Steps = ARRAY_SIZE (WriteSteps);
+ }
+
+ for (Index = 0; Index < Steps; ++Index) {
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ TRUE,
+ mVariableModuleGlobal->FvbInstance,
+ WriteSteps[Index].Offset,
+ WriteSteps[Index].Size,
+ WriteSteps[Index].Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ Variable->State = VAR_ADDED;
+ if (!Volatile) {
+ CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize);
+ }
+
+ *NewVariable = (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset);
+ *Offset += HEADER_ALIGN (VariableSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Rebase the given variable pointer(s) to the equivalent one in given variable
+ storage via VarStore.
+
+ @param[in] InVarTrackPtr Pointer to current variable in cache.
+ @param[out] OutVarTrackPtr Pointer to rebased variable against VarStore.
+ @param[in] VarStore Start of variable storage to rebase against.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] ByOffset If TRUE, don't do variable search in VarStore.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameters passed.
+ @retval EFI_NOT_FOUND Given variable (VariableName & VendorGuid)
was
+ not found in VarStore, if ByOffset is FALSE.
+
+**/
+EFI_STATUS
+RebaseVariablePtr (
+ IN VARIABLE_POINTER_TRACK *InVarTrackPtr,
+ OUT VARIABLE_POINTER_TRACK *OutVarTrackPtr,
+ IN VARIABLE_STORE_HEADER *VarStore,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN ByOffset
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ VARIABLE_HEADER *NewStart;
+
+ if ((InVarTrackPtr == NULL) || (OutVarTrackPtr == NULL) || (VarStore ==
NULL)) {
+ ASSERT (InVarTrackPtr != NULL);
+ ASSERT (OutVarTrackPtr != NULL);
+ ASSERT (VarStore != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ( (InVarTrackPtr->CurrPtr == NULL)
+ || (InVarTrackPtr->StartPtr == GetStartPointer (VarStore)))
+ {
+ CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof
(VARIABLE_POINTER_TRACK));
+ return EFI_SUCCESS;
+ }
+
+ NewStart = GetStartPointer (VarStore);
+ if (ByOffset) {
+ OutVarTrackPtr->CurrPtr = (VARIABLE_HEADER *)
+ ((UINTN)NewStart + ((UINTN)InVarTrackPtr->CurrPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+
+ if (InVarTrackPtr->InDeletedTransitionPtr != NULL) {
+ OutVarTrackPtr->InDeletedTransitionPtr =
+ (VARIABLE_HEADER *)((UINTN)NewStart +
+ ((UINTN)InVarTrackPtr->InDeletedTransitionPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+ } else {
+ OutVarTrackPtr->InDeletedTransitionPtr = NULL;
+ }
+
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+ } else {
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrackPtr,
AuthFormat);
+ if ((OutVarTrackPtr->CurrPtr == NULL) || EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ( (VarStore == mNvVariableCache)
+ || ((UINTN)VarStore == (UINTN)mVariableModuleGlobal-
VariableGlobal.NonVolatileVariableBase))
+ {
+ OutVarTrackPtr->Volatile = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the given variable is from HOB.
+
+ @param[in] CacheVariable Pointer to current variable in cache.
+
+ @retval TRUE The variable is from HOB.
+ @retval FALSE The variable is NOT from HOB.
+
+**/
+BOOLEAN
+IsHobVariable (
+ IN VARIABLE_POINTER_TRACK *CacheVariable
+ )
+{
+ VARIABLE_STORE_HEADER *HobVarStore;
+
+ HobVarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ return (CacheVariable->CurrPtr != NULL &&
+ HobVarStore != NULL &&
+ CacheVariable->StartPtr == GetStartPointer (HobVarStore));
+}
+
+/**
+ Get temporary buffer for a new variable data.
+
+ @retval Pointer to the buffer address.
+
+**/
+VARIABLE_HEADER *
+GetNewVariableBuffer (
+ VOID
+ )
+{
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ NewVariable = GetEndPointer (VarStore);
+
+ SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff);
+
+ return NewVariable;
+}
+
+/**
+ Delete old copies of variable completely.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in,out] CacheVariable Pointer to current variable in cache.
+ @param[in] VolatileFlag Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval Others Failed to update variable state.
+
+**/
+EFI_STATUS
+DeleteVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ EFI_STATUS Status;
+
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+ //
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ Status = UpdateVariableState (
+ Variable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ ASSERT (CacheVariable->CurrPtr != NULL);
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ FALSE,
+ TRUE,
+ FALSE,
+ &gVariableInfo
+ );
+ if (!Variable->Volatile) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check if it's the right time to update a variable.
+
+ @param[in] Attributes Attributes of a variable.
+
+ @retval TRUE It's ready for variable update.
+ @retval FALSE It's NOT ready for variable update.
+
+**/
+BOOLEAN
+ReadyForUpdate (
+ IN UINT32 Attributes
+ )
+{
+ if ((mVariableModuleGlobal->FvbInstance == NULL) &&
+ !mVariableModuleGlobal->VariableGlobal.EmuNvMode)
+ {
+ //
+ // The FVB protocol is not ready, so the
EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ // is not installed.
+ //
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Trying to update NV variable prior to the installation of
+ // EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL
ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ //
+ // Trying to update volatile authenticated variable prior to the
+ // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The
authenticated
+ // variable perhaps is not initialized, just return here.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL
ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check parameters associated with the variable to update.
+
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in] CacheVariable Pointer to current variable in cache.
@param[in] VariableName Name of variable.
@param[in] VendorGuid Guid of variable.
@param[in] Data Variable data.
@@ -1667,9 +1999,130 @@ AutoUpdateLangVariable (
@param[in] Attributes Attributes of the variable.
@param[in] KeyIndex Index of associated public key.
@param[in] MonotonicCount Value of associated monotonic count.
- @param[in, out] CacheVariable The variable information which is used to keep
track of variable usage.
@param[in] TimeStamp Value of associated TimeStamp.

+ @retval EFI_SUCCESS The variable is ok to be updated.
+ @retval EFI_ALREADY_STARTED No need to update the variable.
+ @retval EFI_WRITE_PROTECTED The variable cannot be updated.
+ @retval EFI_INVALID_PARAMETER The variable attributes are not valid.
+ @retval EFI_NOT_FOUND Trying to delete non-existing variable.
+
+**/
+EFI_STATUS
+ValidateVariableParameters (
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN VARIABLE_POINTER_TRACK *CacheVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ BOOLEAN AuthFlag;
+
+ AuthFlag = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (Variable->CurrPtr != NULL) {
+ //
+ // Update/Delete existing variable.
+ //
+ if (AtRuntime ()) {
+ //
+ // If AtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Only variable that have NV attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)
== 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only variable that have RT attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
== 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Variable content unchanged and no need to update timestamp, just return.
+ //
+ if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)
+ && (TimeStamp == NULL)
+ && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) == DataSize)
+ && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr,
AuthFlag), DataSize) == 0))
+ {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ //
+ // Create a new variable.
+ //
+
+ //
+ // Make sure we are trying to create a new variable. You cannot delete a
new
+ // variable.
+ //
+ if ((DataSize == 0) ||
+ ((Attributes &
(EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
0))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime.
+ //
+ if ( AtRuntime ()
+ && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)
+ || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the variable region with Variable information. If
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in,out] CacheVariable The variable information which is used
+ to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
@retval EFI_SUCCESS The update operation is success.
@retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other
data into this region.

@@ -1687,710 +2140,381 @@ UpdateVariable (
IN EFI_TIME *TimeStamp OPTIONAL
)
{
- EFI_STATUS Status;
- VARIABLE_HEADER *NextVariable;
- UINTN ScratchSize;
- UINTN MaxDataSize;
- UINTN VarNameOffset;
- UINTN VarDataOffset;
- UINTN VarNameSize;
- UINTN VarSize;
- BOOLEAN Volatile;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- UINT8 State;
- VARIABLE_POINTER_TRACK *Variable;
- VARIABLE_POINTER_TRACK NvVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
- UINT8 *BufferForMerge;
- UINTN MergedBufSize;
- BOOLEAN DataReady;
- UINTN DataOffset;
- BOOLEAN IsCommonVariable;
- BOOLEAN IsCommonUserVariable;
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
- BOOLEAN AuthFormat;
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *VarGlobal;
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *UpdatingVariable;
+ UINTN VarSize;
+ UINTN UpdateSize;
+ UINTN Offset;
+ VARIABLE_POINTER_TRACK *Variable;
+ VARIABLE_POINTER_TRACK NvVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ BOOLEAN DeleteFlag;
+ BOOLEAN VolatileFlag;
+ BOOLEAN HobVarOnlyFlag;
+ EFI_PHYSICAL_ADDRESS VarStoreBase;
+ UINTN *LastVariableOffset;

- if ((mVariableModuleGlobal->FvbInstance == NULL)
&& !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // The FVB protocol is not ready, so the
EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
- //
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Trying to update NV variable prior to the installation of
EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- //
- DEBUG ((DEBUG_ERROR, "Update NV variable before
EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- //
- // Trying to update volatile authenticated variable prior to the installation of
EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- // The authenticated variable perhaps is not initialized, just return here.
- //
- DEBUG ((DEBUG_ERROR, "Update AUTH variable before
EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- }
+ if (!ReadyForUpdate (Attributes)) {
+ return EFI_NOT_AVAILABLE_YET;
}

- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ VarGlobal = &mVariableModuleGlobal->VariableGlobal;
+
+ if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
+ || (Attributes == 0)
+ || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS
+ |EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)))
+ {
+ DeleteFlag = TRUE;
+ } else {
+ DeleteFlag = FALSE;
+ }
+
+ if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)
+ || ((CacheVariable->CurrPtr != NULL) &&
+ ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) !=
0)))
+ {
+ VolatileFlag = FALSE;
+ } else {
+ VolatileFlag = TRUE;
+ }

//
// Check if CacheVariable points to the variable in variable HOB.
// If yes, let CacheVariable points to the variable in NV variable cache.
//
- if ((CacheVariable->CurrPtr != NULL) &&
- (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
- (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))
- )
- {
- CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
- CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
- CacheVariable->Volatile = FALSE;
- Status = FindVariableEx (VariableName, VendorGuid, FALSE,
CacheVariable, AuthFormat);
+ HobVarOnlyFlag = FALSE;
+ if (IsHobVariable (CacheVariable)) {
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ CacheVariable,
+ mNvVariableCache,
+ VariableName,
+ VendorGuid,
+ FALSE
+ );
if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
//
// There is no matched variable in NV variable cache.
//
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
|| (Attributes == 0)) {
+ if (DeleteFlag) {
//
- // It is to delete variable,
- // go to delete this variable in variable HOB and
- // try to flush other variables from HOB to flash.
+ // Leave the deletion to FlushHobVariableToFlash() before return.
//
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE,
TRUE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- return EFI_SUCCESS;
+ HobVarOnlyFlag = TRUE;
+ Status = EFI_SUCCESS;
+ goto Done;
}
}
}

+ //
+ // Determine the physical position of variable store to update, due to cache
+ // mechanims of variable service.
+ //
if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
+ //
+ // - Add new variable (volatile or non-volatile); Or
+ // - Update/delete volatile variable in place.
+ //
Variable = CacheVariable;
} else {
//
- // Update/Delete existing NV variable.
- // CacheVariable points to the variable in the memory copy of Flash area
- // Now let Variable points to the same variable in Flash area.
+ // - Update/Delete existing NV variable.
+ // CacheVariable points to the variable in the memory copy of Flash area.
+ // Now let Variable points to the same variable in Flash area.
//
- VariableStoreHeader = (VARIABLE_STORE_HEADER
*)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
- Variable = &NvVariable;
- Variable->StartPtr = GetStartPointer (VariableStoreHeader);
- Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr +
((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
-
- Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr +
((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
- if (CacheVariable->InDeletedTransitionPtr != NULL) {
- Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable-
StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr -
(UINTN)CacheVariable->StartPtr));
- } else {
- Variable->InDeletedTransitionPtr = NULL;
- }
-
- Variable->Volatile = FALSE;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)
+ VarGlobal->NonVolatileVariableBase;
+ Variable = &NvVariable;
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ Variable,
+ VariableStoreHeader,
+ VariableName,
+ VendorGuid,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
}

- Fvb = mVariableModuleGlobal->FvbInstance;
-
//
- // Tricky part: Use scratch data area at the end of volatile variable store
- // as a temporary storage.
+ // Validate variable parameters.
//
- NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER
*)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
- ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
- SetMem (NextVariable, ScratchSize, 0xff);
- DataReady = FALSE;
-
- if (Variable->CurrPtr != NULL) {
- //
- // Update/Delete existing variable.
- //
- if (AtRuntime ()) {
- //
- // If AtRuntime and the variable is Volatile and Runtime Access,
- // the volatile is ReadOnly, and SetVariable should be aborted and
- // return EFI_WRITE_PROTECTED.
- //
- if (Variable->Volatile) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
-
- //
- // Only variable that have NV attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) ==
0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Only variable that have RT attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
== 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Setting a data variable with no access, or zero DataSize attributes
- // causes it to be deleted.
- // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero
will
- // not delete the variable.
- //
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) ||
((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE,
FALSE, TRUE, FALSE, &gVariableInfo);
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- FlushHobVariableToFlash (VariableName, VendorGuid);
- }
- }
+ Status = ValidateVariableParameters (
+ Variable,
+ CacheVariable,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }

- goto Done;
- }
+ //
+ // Add or update a variable. Allocate a buffer to hold it temporarily.
+ //
+ NewVariable = GetNewVariableBuffer ();

+ //
+ // Fill-up variable data first, if necessary.
+ //
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ if (DeleteFlag) {
//
- // If the variable is marked valid, and the same data has been passed in,
- // then return to the caller immediately.
+ // No need to fill up variable buffer when deleting a variable. But the
+ // buffer is still needed if variable protection is employed.
//
- if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize)
&&
- (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr,
AuthFormat), DataSize) == 0) &&
- ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
- (TimeStamp == NULL))
- {
- //
- // Variable content unchanged and no need to update timestamp, just return.
- //
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE,
TRUE, FALSE, FALSE, &gVariableInfo);
- Status = EFI_SUCCESS;
- goto Done;
- } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
- (CacheVariable->CurrPtr->State == (VAR_ADDED &
VAR_IN_DELETED_TRANSITION)))
- {
- //
- // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
- //
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
- //
- // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable
Header and Name.
- // From DataOffset of NextVariable is to save the existing variable data.
- //
- DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr,
AuthFormat);
- BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);
- CopyMem (
- BufferForMerge,
- (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),
- DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
- );
-
- //
- // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default
MaxDataSize.
- //
- if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize -
DataOffset;
- } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
- } else {
- MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize -
DataOffset;
- }
-
- //
- // Append the new data to the end of existing data.
- // Max Harware error record variable data size is different from
common/auth variable.
- //
- if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -
DataOffset;
- }
-
- if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize >
MaxDataSize) {
- //
- // Existing data size + new data size exceed maximum variable size
limitation.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (
- (UINT8 *)(
- (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable-
CurrPtr, AuthFormat)
- ),
- Data,
- DataSize
- );
- MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
+
- DataSize;
-
- //
- // BufferForMerge(from DataOffset of NextVariable) has included the
merged existing and new data.
- //
- Data = BufferForMerge;
- DataSize = MergedBufSize;
- DataReady = TRUE;
- }
-
- //
- // Mark the old variable as in delete transition.
- //
- State = CacheVariable->CurrPtr->State;
- State &= VAR_IN_DELETED_TRANSITION;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ VarSize = 0;
} else {
- //
- // Not found existing variable. Create a new variable.
- //
+ VarSize = SetVariableData (
+ NewVariable,
+ CacheVariable->CurrPtr,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );

- if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Make sure we are trying to create a new variable.
- // Setting a data variable with zero DataSize or no access attributes means to
delete it.
- //
- if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Only variable have NV|RT attribute can be created in Runtime.
- //
- if (AtRuntime () &&
- (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes &
EFI_VARIABLE_NON_VOLATILE) == 0)))
- {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Function part - create a new variable and copy the data.
- // Both update a variable and create a variable will come here.
- //
- NextVariable->StartId = VARIABLE_DATA;
- //
- // NextVariable->State = VAR_ADDED;
- //
- NextVariable->Reserved = 0;
- if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER
*)NextVariable;
- AuthVariable->PubKeyIndex = KeyIndex;
- AuthVariable->MonotonicCount = MonotonicCount;
- ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
-
- if (((Attributes &
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
- (TimeStamp != NULL))
- {
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- //
- // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set,
only
- // when the new TimeStamp value is later than the current timestamp
associated
- // with the variable, we need associate the new timestamp with the
updated value.
- //
- if (Variable->CurrPtr != NULL) {
- if (VariableCompareTimeStampInternal
(&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)-
TimeStamp), TimeStamp)) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- CopyMem (&AuthVariable->TimeStamp,
&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)-
TimeStamp), sizeof (EFI_TIME));
- }
- }
- }
- }
- }
-
- //
- // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the
returned
- // Attributes bitmask parameter of a GetVariable() call.
- //
- NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
-
- VarNameOffset = GetVariableHeaderSize (AuthFormat);
- VarNameSize = StrSize (VariableName);
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarNameOffset),
- VariableName,
- VarNameSize
- );
- VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE
(VarNameSize);
-
- //
- // If DataReady is TRUE, it means the variable data has been saved into
- // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
- //
- if (!DataReady) {
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarDataOffset),
- Data,
- DataSize
- );
- }
-
- CopyMem (
- GetVendorGuidPtr (NextVariable, AuthFormat),
- VendorGuid,
- sizeof (EFI_GUID)
- );
- //
- // There will be pad bytes after Data, the NextVariable->NameSize and
- // NextVariable->DataSize should not include pad size so that variable
- // service can get actual size in GetVariable.
- //
- SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
- SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
-
- //
- // The actual size of the variable that stores in storage should
- // include pad size.
- //
- VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Create a nonvolatile variable.
- //
- Volatile = FALSE;
-
- IsCommonVariable = FALSE;
- IsCommonUserVariable = FALSE;
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
IsCommonVariable = TRUE;
- IsCommonUserVariable = IsUserVariable (NextVariable);
+ IsCommonUserVariable = IsUserVariable (NewVariable);
}
+ }

- if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
- && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) >
PcdGet32 (PcdHwErrStorageSize)))
- || (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
CommonVariableTotalSize) > mVariableModuleGlobal-
CommonVariableSpace))
- || (IsCommonVariable && AtRuntime () && ((VarSize +
mVariableModuleGlobal->CommonVariableTotalSize) >
mVariableModuleGlobal->CommonRuntimeVariableSpace))
- || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
CommonUserVariableTotalSize) > mVariableModuleGlobal-
CommonMaxUserVariableSpace)))
- {
- if (AtRuntime ()) {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
CommonUserVariableTotalSize) > mVariableModuleGlobal-
CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName,
VendorGuid, Attributes, VarSize);
- }
-
- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
CommonVariableTotalSize) > mVariableModuleGlobal-
CommonRuntimeVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName,
VendorGuid, Attributes, VarSize);
- }
-
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Perform garbage collection & reclaim operation, and integrate the new
variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
- &mVariableModuleGlobal->NonVolatileLastVariableOffset,
- FALSE,
- Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
- );
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER
*)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr -
(UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE,
FALSE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- } else {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
CommonUserVariableTotalSize) > mVariableModuleGlobal-
CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName,
VendorGuid, Attributes, VarSize);
- }
+ //
+ // We might need to do protection for non-volatile variable before flushing
+ // the data to storage. A null version (meaning no protection) of following
+ // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any
+ // changes to original data.
+ //
+ if (!VolatileFlag) {
+ Status = ProtectedVariableLibUpdate (
+ Variable->CurrPtr,
+ Variable->InDeletedTransitionPtr,
+ NewVariable,
+ &VarSize
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }

- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
CommonVariableTotalSize) > mVariableModuleGlobal-
CommonVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName,
VendorGuid, Attributes, VarSize);
- }
- }
+ Status = EFI_SUCCESS;
+ }

+ //
+ // Mark the old variable as in delete transition first. There's no such need
+ // for deleting a variable, even if variable protection is employed.
+ //
+ if ( !DeleteFlag
+ && (CacheVariable->CurrPtr != NULL)
+ && ( (CacheVariable->CurrPtr->State == VAR_ADDED)
+ || (CacheVariable->CurrPtr->State == (VAR_ADDED &
VAR_IN_DELETED_TRANSITION))))
+ {
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION,
+ Variable->Volatile
+ );
+ if (EFI_ERROR (Status)) {
goto Done;
}
-
- if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Four steps
- // 1. Write variable header
- // 2. Set variable state to header valid
- // 3. Write variable data
- // 4. Set variable state to valid
- //
- //
- // Step 1:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)GetVariableHeaderSize (AuthFormat),
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 2:
- //
- NextVariable->State = VAR_HEADER_VALID_ONLY;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset +
OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 3:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset +
GetVariableHeaderSize (AuthFormat),
- (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),
- (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)
+ }
+
+ //
+ // Have enough space to store the variable?
+ //
+ Status = CheckVariableStoreSpace (
+ NewVariable,
+ VarSize,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VolatileFlag
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ //
+ // Not a chance.
+ //
+ goto Done;
+ }
+
+ //
+ // Maybe not...
+ //
+ VarStoreBase = (VolatileFlag) ? VarGlobal->VolatileVariableBase
+ : VarGlobal->NonVolatileVariableBase;
+ LastVariableOffset = (VolatileFlag)
+ ? &mVariableModuleGlobal->VolatileLastVariableOffset
+ : &mVariableModuleGlobal->NonVolatileLastVariableOffset;
+ if (!EFI_ERROR (Status)) {
+ //
+ // There's enough free space at the tail of variable storage.
+ //
+
+ //
+ // If non-volatile variable is protected, a separate variable
(MetaDataHmacVar)
+ // is always updated along with current updating variable. The buffer pointed
+ // by NewVariable must have two variables. They should be written at this
+ // time orderly.
+ //
+ NextVariable = NewVariable;
+ UpdatingVariable = NULL;
+ UpdateSize = 0;
+ while ( !EFI_ERROR (Status)
+ && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize)
+ {
+ UpdatingVariable = NextVariable;
+ NextVariable = GetNextVariablePtr (UpdatingVariable, VarGlobal-
AuthFormat);
+ UpdateSize = (UINTN)NextVariable - (UINTN)UpdatingVariable;
+
+ Status = WriteVariable (
+ VarStoreBase,
+ LastVariableOffset,
+ &UpdatingVariable,
+ (UINT32)UpdateSize,
+ VolatileFlag,
+ VarGlobal->AuthFormat
);
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 4:
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset +
OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Update the memory copy of Flash region.
- //
- CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal-
NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
- } else {
- //
- // Emulated non-volatile variable mode.
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
}

- mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN
(VarSize);
-
+ //
+ // UpdatingVariable must point to the last written variable. Restore it to
+ // the first one so that we can calculate the offset in variable storage.
+ //
+ UpdatingVariable = (VARIABLE_HEADER *)((UINTN)UpdatingVariable +
UpdateSize
+ - VarSize);
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN
(VarSize);
+ mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
} else {
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN
(VarSize);
+ mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
if (IsCommonUserVariable) {
- mVariableModuleGlobal->CommonUserVariableTotalSize +=
HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VarSize;
}
}
- } else {
- //
- // Create a volatile variable.
- //
- Volatile = TRUE;

- if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
- ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal-
VariableGlobal.VolatileVariableBase)))->Size)
- {
- //
- // Perform garbage collection & reclaim operation, and integrate the new
variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
- &mVariableModuleGlobal->VolatileLastVariableOffset,
- TRUE,
+ //
+ // Mark the old variable(s) as deleted.
+ //
+ if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
+ Status = DeleteVariable (
+ VariableName,
+ VendorGuid,
Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
+ CacheVariable,
+ VolatileFlag
);
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER
*)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr -
(UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE,
FALSE, FALSE, &gVariableInfo);
- }
-
- goto Done;
}
-
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- TRUE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->VolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN
(VarSize);
- }
-
- //
- // Mark the old variable as deleted.
- //
- if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION old variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
+ } else {
+ //
+ // There's not enough space at the tail of variable storage but there's
+ // enough free space holes in the whole storage. Perform garbage collection
+ // & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ VarStoreBase,
+ LastVariableOffset,
+ VolatileFlag,
+ Variable,
+ NewVariable,
+ VarSize
);
- if (!EFI_ERROR (Status) && !Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ UpdatingVariable = Variable->CurrPtr;

- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE,
FALSE, FALSE, &gVariableInfo);
- if (!Volatile) {
- FlushHobVariableToFlash (VariableName, VendorGuid);
+ if (EFI_ERROR (Status) &&
+ ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0))
+ {
+ //
+ // Out of space.
+ //
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ IsCommonVariable = TRUE;
+
+ if (IsCommonUserVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
}
}

Done:
if (!EFI_ERROR (Status)) {
- if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes &
EFI_VARIABLE_NON_VOLATILE) != 0)) {
- VolatileCacheInstance = &(mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);
+ if (!VolatileFlag) {
+ Offset = (UpdatingVariable != NULL) ? (UINTN)UpdatingVariable -
(UINTN)VarStoreBase
+ : 0;
+ Status = ProtectedVariableLibWriteFinal (
+ NewVariable,
+ VarSize,
+ Offset
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ VolatileFlag,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ //
+ // HOB copy of the same variable is no longer needed, no matter it has
+ // been deleted, updated or added from/to real variable storage.
+ //
+ if (HobVarOnlyFlag || !VolatileFlag) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+
+ if (!VolatileFlag) {
+ VolatileCacheInstance = &(VarGlobal-
VariableRuntimeCacheContext.VariableRuntimeNvCache);
} else {
- VolatileCacheInstance = &(mVariableModuleGlobal-
VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
+ VolatileCacheInstance = &(VarGlobal-
VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
}

if (VolatileCacheInstance->Store != NULL) {
@@ -2401,6 +2525,11 @@ Done:
);
ASSERT_EFI_ERROR (Status);
}
+ } else if (Status == EFI_ALREADY_STARTED) {
+ //
+ // Meaning nothing needs to be done. Just return success.
+ //
+ Status = EFI_SUCCESS;
}

return Status;
@@ -2440,7 +2569,6 @@ VariableServiceGetVariable (
{
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
- UINTN VarDataSize;

if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -2458,28 +2586,26 @@ VariableServiceGetVariable (
}

//
- // Get data size
+ // Get data and its size
//
- VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal-
VariableGlobal.AuthFormat);
- ASSERT (VarDataSize != 0);
+ if (!Variable.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (
+ Variable.CurrPtr,
+ Data,
+ (UINT32 *)DataSize,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ }

- if (*DataSize >= VarDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
+ if (Variable.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }

- CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);
-
- *DataSize = VarDataSize;
+ if (!EFI_ERROR (Status)) {
UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE,
FALSE, FALSE, FALSE, &gVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = VarDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
}

Done:
@@ -2860,7 +2986,7 @@ VariableServiceSetVariable (
// Parse non-volatile variable data and get last variable offset.
//
NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
- while (IsValidVariableHeader (NextVariable, GetEndPointer
((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
+ while (IsValidVariableHeader (NextVariable, GetEndPointer
((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) {
NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
}

@@ -3022,7 +3148,12 @@ VariableServiceQueryVariableInfoInternal (
//
// Now walk through the related variable store.
//
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
{
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (VariableStoreHeader),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
VariableGlobal.AuthFormat);
VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;

@@ -3315,7 +3446,7 @@ FlushHobVariableToFlash (
//
mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
for ( Variable = GetStartPointer (VariableStoreHeader)
- ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
+ ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
AuthFormat)
; Variable = GetNextVariablePtr (Variable, AuthFormat)
)
{
@@ -3525,11 +3656,11 @@ ConvertNormalVarStorageToAuthVarStorage (
VARIABLE_HEADER *StartPtr;
UINT8 *NextPtr;
VARIABLE_HEADER *EndPtr;
- UINTN AuthVarStroageSize;
+ UINTN AuthVarStorageSize;
AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
VARIABLE_STORE_HEADER *AuthVarStorage;

- AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
+ AuthVarStorageSize = sizeof (VARIABLE_STORE_HEADER);
//
// Set AuthFormat as FALSE for normal variable storage
//
@@ -3542,10 +3673,10 @@ ConvertNormalVarStorageToAuthVarStorage (
EndPtr = GetEndPointer (NormalVarStorage);
while (StartPtr < EndPtr) {
if (StartPtr->State == VAR_ADDED) {
- AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
- AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
- AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr-
NameSize);
- AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr-
DataSize);
+ AuthVarStorageSize = HEADER_ALIGN (AuthVarStorageSize);
+ AuthVarStorageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ AuthVarStorageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr-
NameSize);
+ AuthVarStorageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr-
DataSize);
}

StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal-
VariableGlobal.AuthFormat);
@@ -3554,7 +3685,7 @@ ConvertNormalVarStorageToAuthVarStorage (
//
// Allocate Runtime memory for Auth Variable Storage
//
- AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
+ AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStorageSize);
ASSERT (AuthVarStorage != NULL);
if (AuthVarStorage == NULL) {
return NULL;
@@ -3608,7 +3739,7 @@ ConvertNormalVarStorageToAuthVarStorage (
AuthVarStorage->State = NormalVarStorage->State;
AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr -
(UINTN)AuthVarStorage);
CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
- ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
+ ASSERT (AuthVarStorage->Size <= AuthVarStorageSize);

//
// Restore AuthFormat
@@ -3774,7 +3905,7 @@ VariableCommonInitialize (
//
// Allocate memory for volatile variable store, note that there is a scratch
space to store scratch data.
//
- ScratchSize = GetMaxVariableSize ();
+ ScratchSize = GetMaxVariableSize () * 2;
mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
VolatileVariableStore = AllocateRuntimePool (PcdGet32
(PcdVariableStoreSize) + ScratchSize);
if (VolatileVariableStore == NULL) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index 03fec3048dc4..52bf29ec4c5c 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -3,7 +3,7 @@
and volatile storage space and install variable architecture protocol.

Copyright (C) 2013, Red Hat, Inc.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <Protocol/VariablePolicy.h>
#include <Library/VariablePolicyLib.h>
+#include "VariableParsing.h"

EFI_STATUS
EFIAPI
@@ -534,6 +535,29 @@ VariableServiceInitialize (
EFI_EVENT ReadyToBootEvent;
EFI_EVENT EndOfDxeEvent;

+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialze protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion =
PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
index 62cde0335512..5904bcbff78a 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
@@ -1,13 +1,14 @@
/** @file
Provides variable driver extended services.

-Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "Variable.h"
#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"

/**
Finds variable in storage blocks of volatile and non-volatile storage areas.
@@ -38,6 +39,7 @@ VariableExLibFindVariable (
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ PROTECTED_VARIABLE_INFO VarInfo;

Status = FindVariable (
VariableName,
@@ -56,9 +58,12 @@ VariableExLibFindVariable (
return Status;
}

- AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
+ AuthVariableInfo->NameSize = NameSizeOfVariable (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VariableName = GetVariableNamePtr (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VendorGuid = GetVendorGuidPtr (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
AuthVariable = (AUTHENTICATED_VARIABLE_HEADER
*)Variable.CurrPtr;
AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
@@ -66,6 +71,24 @@ VariableExLibFindVariable (
AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
}

+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = Variable.CurrPtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+ VarInfo.Flags.Auth = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // In case the variable is encrypted.
+ //
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}

@@ -99,6 +122,7 @@ VariableExLibFindNextVariable (
VARIABLE_HEADER *VariablePtr;
AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
VARIABLE_STORE_HEADER
*VariableStoreHeader[VariableStoreTypeMax];
+ PROTECTED_VARIABLE_INFO VarInfo;

VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER
*)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER
*)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
@@ -123,6 +147,7 @@ VariableExLibFindNextVariable (
return Status;
}

+ AuthVariableInfo->NameSize = NameSizeOfVariable (VariablePtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr,
mVariableModuleGlobal->VariableGlobal.AuthFormat);
@@ -135,6 +160,20 @@ VariableExLibFindNextVariable (
AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
}

+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = VariablePtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}

@@ -256,3 +295,123 @@ VariableExLibAtRuntime (
{
return AtRuntime ();
}
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not
valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *Global;
+ VARIABLE_RUNTIME_CACHE *CacheInstance;
+ VARIABLE_HEADER *VariableCache;
+
+ if ((mVariableModuleGlobal == NULL) || (mNvVariableCache == NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Flush the cache to store.
+ //
+ if (Size == (UINT32)-1) {
+ Status = FtwVariableSpace (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ mNvVariableCache
+ );
+ if ( !EFI_ERROR (Status)
+ && (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0))
+ {
+ FlushHobVariableToFlash (NULL, NULL);
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *)(UINTN)mVariableModuleGlobal-
VariableGlobal.HobVariableBase);
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ }
+ }
+
+ return Status;
+ }
+
+ if ( (VariableInfo == NULL)
+ || (VariableInfo->StoreIndex == VAR_INDEX_INVALID)
+ || (Buffer == NULL)
+ || (Size == 0))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+ ASSERT (Buffer != NULL);
+ ASSERT (Size != 0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Global = &mVariableModuleGlobal->VariableGlobal;
+
+ VariableCache = (VARIABLE_HEADER *)((UINTN)mNvVariableCache +
(UINTN)VariableInfo->StoreIndex);
+
+ ASSERT (
+ StrCmp (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariableCache, Global->AuthFormat)
+ ) == 0
+ );
+ ASSERT (
+ CompareGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariableCache, Global->AuthFormat)
+ )
+ );
+
+ //
+ // Forcibly update part data of flash copy of the variable ...
+ //
+ Status = UpdateVariableStore (
+ Global,
+ FALSE,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)(Global->NonVolatileVariableBase + VariableInfo->StoreIndex +
Offset),
+ Size,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // ... as well as the local cached copy.
+ //
+ CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size);
+
+ //
+ // Sync remote cached copy.
+ //
+ CacheInstance = &Global-
VariableRuntimeCacheContext.VariableRuntimeNvCache;
+ if (CacheInstance->Store != NULL) {
+ Status = SynchronizeRuntimeVariableCache (
+ CacheInstance,
+ (UINTN)VariableInfo->StoreIndex + Offset,
+ Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
index 5e9d40b67ac2..e8b8f0b7f705 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
@@ -1,7 +1,7 @@
/** @file
Common variable non-volatile store routines.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -120,6 +120,181 @@ InitEmuNonVolatileVariableStore (
return EFI_SUCCESS;
}

+/**
+
+ Create a dummy variable used to fill the gap in NV variable storage caused by
+ the invalid variables found in HMAC verification phase.
+
+ @param[out] Variable Variable buffer.
+ @param[in] Name Variable Name.
+ @param[in] Guid Vendor GUID of the variable.
+ @param[in] Size Whole size of the variable requested.
+ @param[in] AuthFlag Variable format flag.
+
+**/
+STATIC
+VOID
+CreateDummyVariable (
+ OUT VARIABLE_HEADER *Variable,
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN UINT32 Size,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ ASSERT (Variable != NULL);
+
+ if (Name == NULL) {
+ Name = L"Dummy";
+ }
+
+ if (AuthFlag) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+ AuthVariable->StartId = VARIABLE_DATA;
+ AuthVariable->State = VAR_ADDED & VAR_DELETED;
+ AuthVariable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ AuthVariable->NameSize = (UINT32)StrSize (Name);
+ AuthVariable->DataSize = Size - sizeof
(AUTHENTICATED_VARIABLE_HEADER)
+ - AuthVariable->NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof
(EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name,
AuthVariable->NameSize);
+ } else {
+ Variable->StartId = VARIABLE_DATA;
+ Variable->State = VAR_ADDED & VAR_DELETED;
+ Variable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ Variable->NameSize = (UINT32)StrSize (Name);
+ Variable->DataSize = Size - sizeof (VARIABLE_HEADER) - Variable-
NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof
(EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name,
Variable->NameSize);
+ }
+}
+
+/**
+
+ Init protected variable store.
+
+ @param[in, out] VariableStore Pointer to real protected variable store base.
+
+**/
+EFI_STATUS
+InitProtectedVariableStore (
+ IN OUT VARIABLE_STORE_HEADER *VariableStore
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ UINTN Size;
+ UINTN Index;
+ BOOLEAN AuthFlag;
+ EFI_PHYSICAL_ADDRESS NextVariableStore;
+ EFI_PHYSICAL_ADDRESS *VarList;
+ UINTN NumVars;
+ UINTN CurrVar;
+
+ SetMem (
+ (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER),
+ VariableStore->Size - sizeof (VARIABLE_STORE_HEADER),
+ 0xFF
+ );
+ Index = sizeof (VARIABLE_STORE_HEADER);
+
+ VarList = NULL;
+ NumVars = 0;
+ ProtectedVariableLibGetSortedList (&VarList, &NumVars);
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+
+ for (CurrVar = 0; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ break;
+ }
+
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ continue;
+ } else {
+ ASSERT (VarInfo.StoreIndex == HEADER_ALIGN (VarInfo.StoreIndex));
+ ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof
(VARIABLE_STORE_HEADER)));
+ ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHeaderSize
(AuthFlag));
+ }
+
+ //
+ // Fill gap caused by invalid variable.
+ //
+ if (VarInfo.StoreIndex > Index) {
+ Size = (UINTN)VarInfo.StoreIndex - Index;
+ CreateDummyVariable (
+ (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index),
+ NULL,
+ NULL,
+ (UINT32)Size,
+ AuthFlag
+ );
+ Index += Size;
+ }
+
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer,
Size);
+
+ Index += Size;
+ Index = HEADER_ALIGN (Index);
+
+ NextVariableStore = (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore +
VarInfo.StoreIndex + Size);
+ }
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ for ( ; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)&NextVariableStore, VarInfo.Buffer, Size);
+ Status = ProtectedVariableLibRefresh (VarInfo.Buffer, 0,
NextVariableStore - (UINTN)VariableStore, FALSE);
+ NextVariableStore = NextVariableStore + Size;
+ }
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
/**
Init real non-volatile variable store.

@@ -230,6 +405,16 @@ InitRealNonVolatileVariableStore (
return EFI_VOLUME_CORRUPTED;
}

+ //
+ // Overwrite the store with verified copy of protected variables, if enabled.
+ //
+ Status = InitProtectedVariableStore (VariableStore);
+ if ((Status != EFI_SUCCESS) && (Status != EFI_UNSUPPORTED)) {
+ FreePool (NvStorageData);
+ DEBUG ((DEBUG_ERROR, "Variable integrity might have been
compromised\n"));
+ return Status;
+ }
+
mNvFvHeaderCache = FvHeader;

*VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
@@ -323,7 +508,12 @@ InitNonVolatileVariableStore (
// Parse non-volatile variable data and get last variable offset.
//
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (mNvVariableCache),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_HARDWARE_ERROR_RECORD)) ==
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD))
{
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
index 39060ed405b8..000e4b546888 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
@@ -2,11 +2,12 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

+#include "Variable.h"
#include "VariableParsing.h"

/**
@@ -15,6 +16,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.

@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -23,10 +26,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
)
{
- if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId !=
VARIABLE_DATA)) {
+ if ( (Variable == NULL)
+ || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >=
(UINTN)VariableStoreEnd)
+ || (Variable->StartId != VARIABLE_DATA))
+ {
//
// Variable is NULL or has reached the end of variable store,
// or the StartId is not correct.
@@ -341,6 +348,52 @@ GetVariableDataOffset (
return Value;
}

+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in,out] Data Pointer to buffer used to store the variable data.
+ @param[in,out] DataSize Size of buffer passed by Data.
+ Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable
data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINT32 Size;
+
+ if (DataSize == NULL) {
+ ASSERT (DataSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size = (UINT32)DataSizeOfVariable (Variable, AuthFlag);
+ if (*DataSize < Size) {
+ *DataSize = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Data == NULL) {
+ ASSERT (Data != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size);
+ *DataSize = Size;
+
+ return EFI_SUCCESS;
+}
+
/**

This code gets the pointer to the next variable header.
@@ -479,7 +532,7 @@ FindVariableEx (
InDeletedVariable = NULL;

for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
- ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
+ ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, AuthFormat)
; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
)
{
@@ -608,7 +661,7 @@ VariableServiceGetNextVariableInternal (
//
// Switch to the next variable store if needed
//
- while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
+ while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr,
AuthFormat)) {
//
// Find current storage index
//
@@ -804,3 +857,260 @@ UpdateVariableInfo (
}
}
}
+
+/**
+
+ 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
+ )
+{
+ VARIABLE_STORE_HEADER *Stores[2];
+ UINTN Index;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableBuffer;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
+ BOOLEAN AuthFlag;
+ UINTN NameSize;
+ UINTN DataSize;
+ UINTN VariableSize;
+
+ if ((VariableInfo == NULL) || ( (VariableInfo->Buffer == NULL)
+ && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->Buffer != NULL || VariableInfo->StoreIndex !=
VAR_INDEX_INVALID);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Stores[0] = mNvVariableCache;
+ Stores[1] = (mVariableModuleGlobal != NULL)
+ ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal-
VariableGlobal.NonVolatileVariableBase
+ : NULL;
+
+ VariableBuffer = VariableInfo->Buffer;
+ VariablePtr = NULL;
+ if (VariableInfo->StoreIndex != VAR_INDEX_INVALID) {
+ for (Index = 0; Index < ARRAY_SIZE (Stores); ++Index) {
+ if (Stores[Index] == NULL) {
+ continue;
+ }
+
+ if ((UINTN)VariableInfo->StoreIndex
+ < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]))
+ {
+ VariablePtr = (VARIABLE_HEADER *)((UINTN)Stores[Index] +
(UINTN)VariableInfo->StoreIndex);
+ VariableInfo->Buffer = VariablePtr;
+ break;
+ }
+ }
+ } else {
+ VariablePtr = VariableInfo->Buffer;
+ }
+
+ if (VariablePtr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+ ASSERT (AuthFlag == TRUE || AuthFlag == FALSE);
+
+ //
+ // Make a copy of the whole variable if a buffer is passed in.
+ //
+ if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+ VariableSize = (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag)
+ - (UINTN)VariablePtr;
+ CopyMem (VariableBuffer, VariablePtr, VariableSize);
+ }
+
+ //
+ // AuthVariable header
+ //
+ if (AuthFlag) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
+
+ VariableInfo->Header.State = AuthVariablePtr->State;
+ VariableInfo->Header.Attributes = AuthVariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = AuthVariablePtr->PubKeyIndex;
+ VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+ &(AuthVariablePtr->MonotonicCount)
+ );
+ if (VariableInfo->Header.TimeStamp != NULL) {
+ CopyMem (
+ VariableInfo->Header.TimeStamp,
+ &AuthVariablePtr->TimeStamp,
+ sizeof (EFI_TIME)
+ );
+ } else if (VariableBuffer != NULL) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER
*)VariableBuffer;
+ VariableInfo->Header.TimeStamp = &AuthVariablePtr->TimeStamp;
+ }
+ } else {
+ VariableInfo->Header.State = VariablePtr->State;
+ VariableInfo->Header.Attributes = VariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = 0;
+ VariableInfo->Header.MonotonicCount = 0;
+ VariableInfo->Header.TimeStamp = NULL;
+ }
+
+ //
+ // VendorGuid
+ //
+ if (VariableInfo->Header.VendorGuid != NULL) {
+ CopyGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariablePtr, AuthFlag)
+ );
+ } else {
+ VariableInfo->Header.VendorGuid = GetVendorGuidPtr (VariablePtr,
AuthFlag);
+ }
+
+ //
+ // VariableName
+ //
+ NameSize = NameSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.VariableName != NULL)
+ && (VariableInfo->Header.NameSize >= NameSize))
+ {
+ CopyMem (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.VariableName != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.VariableName = GetVariableNamePtr (VariablePtr,
AuthFlag);
+ }
+
+ //
+ // Data
+ //
+ DataSize = DataSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.Data != NULL)
+ && (VariableInfo->Header.DataSize >= DataSize))
+ {
+ CopyMem (
+ VariableInfo->Header.Data,
+ GetVariableDataPtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.Data != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.Data = GetVariableDataPtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // Update size information about name & data.
+ //
+ VariableInfo->Header.NameSize = NameSize;
+ VariableInfo->Header.DataSize = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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
+ )
+{
+ VARIABLE_STORE_HEADER *VarStore;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableStart;
+ VARIABLE_HEADER *VariableEnd;
+ BOOLEAN AuthFlag;
+
+ if (VariableInfo == NULL) {
+ ASSERT (VariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mNvVariableCache != NULL) {
+ VarStore = mNvVariableCache;
+ } else if (mVariableModuleGlobal != NULL) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStart = GetStartPointer (VarStore);
+ VariableEnd = GetEndPointer (VarStore);
+
+ if ((VariableInfo->Flags.Auth != TRUE) && (VariableInfo->Flags.Auth != FALSE))
{
+ VariableInfo->Flags.Auth = CompareGuid (
+ &VarStore->Signature,
+ &gEfiAuthenticatedVariableGuid
+ );
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = VariableStart;
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex);
+ if (VariablePtr >= VariableEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariablePtr = GetNextVariablePtr (VariablePtr, AuthFlag);
+ }
+
+ if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableInfo->StoreIndex = (UINTN)VariablePtr - (UINTN)VarStore;
+ return GetVariableInfo (VariableInfo);
+}
diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
index 9bb30bc1e804..dc319feee727 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
@@ -7,7 +7,7 @@
This external input must be validated carefully to avoid security issue like
buffer overflow, integer overflow.

-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
[JianJW]
It looks that there's no other changes in this file. No need to update the year.

SPDX-License-Identifier: BSD-2-Clause-Patent

**/
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
index 517cae7b00f8..c2b689f6202d 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -14,7 +14,7 @@
VariableServiceSetVariable(), VariableServiceQueryVariableInfo(),
ReclaimForOS(),
SmmVariableGetStatistics() should also do validation based on its own
knowledge.

-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -1045,6 +1045,13 @@ VariableWriteServiceInitializeSmm (
{
EFI_STATUS Status;

+ Status = ProtectedVariableLibWriteInit ();
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed.
Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
Status = VariableWriteServiceInitialize ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status
= %r\n", Status));
@@ -1143,10 +1150,32 @@ MmVariableServiceInitialize (
VOID
)
{
- EFI_STATUS Status;
- EFI_HANDLE VariableHandle;
- VOID *SmmFtwRegistration;
- VOID *SmmEndOfDxeRegistration;
+ EFI_STATUS Status;
+ EFI_HANDLE VariableHandle;
+ VOID *SmmFtwRegistration;
+ VOID *SmmEndOfDxeRegistration;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialize protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion =
PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }

//
// Variable initialize.
diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
index 4aaeb5ba8806..8fb8679671ad 100644
---
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
+++
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -13,7 +13,7 @@

InitCommunicateBuffer() is really function to check the variable data size.

-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -36,11 +36,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/MmUnblockMemoryLib.h>
+#include <Library/IoLib.h>
[JianJW]
I didn't find any interface from IoLib.h used this file.


#include <Guid/EventGroup.h>
#include <Guid/SmmVariableCommon.h>

#include "PrivilegePolymorphic.h"
+#include "Variable.h"
#include "VariableParsing.h"

EFI_HANDLE mHandle = NULL;
@@ -53,6 +55,8 @@ VARIABLE_INFO_ENTRY *mVariableInfo
= NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer =
NULL;
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
UINTN mVariableBufferSize;
UINTN mVariableRuntimeHobCacheBufferSize;
UINTN mVariableRuntimeNvCacheBufferSize;
@@ -616,7 +620,6 @@ FindVariableInRuntimeCache (
)
{
EFI_STATUS Status;
- UINTN TempDataSize;
VARIABLE_POINTER_TRACK RtPtrTrack;
VARIABLE_STORE_TYPE StoreType;
VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
@@ -669,31 +672,23 @@ FindVariableInRuntimeCache (
//
// Get data size
//
- TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr,
mVariableAuthFormat);
- ASSERT (TempDataSize != 0);
-
- if (*DataSize >= TempDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr,
mVariableAuthFormat), TempDataSize);
- *DataSize = TempDataSize;
-
- UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE,
FALSE, FALSE, TRUE, &mVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = TempDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
+ if (!RtPtrTrack.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Data,
(UINT32 *)DataSize, mVariableAuthFormat);
+ }
+
+ if (RtPtrTrack.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize,
mVariableAuthFormat);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile,
TRUE, FALSE, FALSE, FALSE, &mVariableInfo);
}
}
}

-Done:
if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {
*Attributes = RtPtrTrack.CurrPtr->Attributes;
--
2.35.1.windows.2