From: "Wu, Hao A" <hao.a.wu@intel.com>
To: "Vang, Judah" <judah.vang@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Wang, Jian J" <jian.j.wang@intel.com>,
"Gao, Liming" <gaoliming@byosoft.com.cn>,
"Mistry, Nishant C" <nishant.c.mistry@intel.com>
Subject: Re: [PATCH v3 09/28] MdeModulePkg: Add support for Protected Variables
Date: Mon, 13 Jun 2022 06:08:49 +0000 [thread overview]
Message-ID: <DM6PR11MB40256D7D352B8E3CCAF69597CAAB9@DM6PR11MB4025.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20220609060322.3491-10-judah.vang@intel.com>
Sorry, I tried by my best to review the patch, but I am not able to tell if this patch will not break the existing scenarios.
Could you help to provide the information on what kind of 'no-harm' tests were done for this patch? Thanks in advance.
Please refer to my inline comments below (tagged as "[Hao]"):
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Thursday, June 9, 2022 2:03 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v3 09/28] MdeModulePkg: Add support for Protected Variables
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> V3: Fix 'NextVariableStore' parameter for CopyMem. It was causing
> an exception. Need to correctly cast 'NextVariableStore' so all
> platforms build. Add code to initialize 'ContextIn' structure in
> SmmVariableReay() to fix issue with NULL function pointer.
>
> V1: 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@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> 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 | 127 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2142
> +++++++++++---------
> 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 |
> 67 +-
> 15 files changed, 2484 insertions(+), 1053 deletions(-)
>
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> index 3858adf6739d..b7a3d3942ba7 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
> #
> @@ -75,6 +75,7 @@ [LibraryClasses]
> VariablePolicyLib
> VariablePolicyHelperLib
> SafeIntLib
> + ProtectedVariableLib
>
> [Protocols]
> gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> index 8c552b87e080..4ba467a73255 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
> #
> @@ -84,6 +84,7 @@ [LibraryClasses]
> VariablePolicyLib
> VariablePolicyHelperLib
> SafeIntLib
> + 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 f09bed40cf51..956a872cda09 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
> @@ -80,6 +80,7 @@ [LibraryClasses]
> VariableFlashInfoLib
> VariablePolicyLib
> VariablePolicyHelperLib
> + ProtectedVariableLib
>
> [Protocols]
> gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> index a668abb82b15..a2065f4bc6e0 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
>
> **/
> @@ -33,6 +33,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Library/VarCheckLib.h>
> #include <Library/VariableFlashInfoLib.h>
> #include <Library/SafeIntLib.h>
> +#include <Library/ProtectedVariableLib.h>
> #include <Guid/GlobalVariable.h>
> #include <Guid/EventGroup.h>
> #include <Guid/VariableFormat.h>
> @@ -820,4 +821,128 @@ 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
> +EFIAPI
> +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))
> + {
[Hao]: Please help to preserve the origin comments here:
//
// 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), 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..19b432b772d7 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,386 @@ 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)))
[Hao]: Sorry for a question, what will be the scenario when this part of the condition is hit:
(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;
> +
> + if (Variable->CurrPtr != NULL) {
> + UpdatingVariable = Variable->CurrPtr;
> + } else {
> + UpdatingVariable = (VARIABLE_HEADER *)(((UINTN)VarStoreBase +
> *LastVariableOffset) - VarSize);
> }
> - }
>
> - 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,
[Hao]: Are the above inputs right for the variable deletion case?
Seems not identical with the origin logic.
> + 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 +2530,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 +2574,6 @@ VariableServiceGetVariable (
> {
> EFI_STATUS Status;
> VARIABLE_POINTER_TRACK Variable;
> - UINTN VarDataSize;
>
> if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
> return EFI_INVALID_PARAMETER;
> @@ -2458,28 +2591,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 +2991,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 +3153,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 +3451,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 +3661,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 +3678,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 +3690,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 +3744,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 +3910,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 d5c409c914d1..4595bf8c9d02 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
> @@ -542,6 +543,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 9e2d8fe0fe0c..32dd9901b260 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.
[Hao]: Please help to add return status description information
Best Regards,
Hao Wu
> +
> +**/
> +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 ((VOID *)(UINTN)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.
>
> @@ -236,6 +411,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;
> @@ -329,7 +514,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 5253c328dcd9..f7bac0227577 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));
> @@ -1152,10 +1159,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..5d4b4f9b3da7 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;
> @@ -724,6 +719,7 @@ Done:
>
> **/
> EFI_STATUS
> +EFIAPI
> FindVariableInSmm (
> IN CHAR16 *VariableName,
> IN EFI_GUID *VendorGuid,
> @@ -1633,7 +1629,8 @@ SmmVariableReady (
> IN VOID *Context
> )
> {
> - EFI_STATUS Status;
> + EFI_STATUS Status;
> + PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
>
> Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID
> **)&mSmmVariable);
> if (EFI_ERROR (Status)) {
> @@ -1731,6 +1728,28 @@ SmmVariableReady (
> );
> ASSERT_EFI_ERROR (Status);
>
> + ContextIn.StructSize = sizeof (ContextIn);
> + ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +
> + ContextIn.FindVariableSmm = FindVariableInSmm;
> + ContextIn.GetVariableInfo = GetVariableInfo;
> + ContextIn.GetNextVariableInfo = GetNextVariableInfo;
> + ContextIn.VariableServiceUser = FromRuntimeModule;
> + ContextIn.MaxVariableSize = 0;
> + ContextIn.UpdateVariableStore = NULL;
> + ContextIn.UpdateVariable = NULL;
> +
> + Status = ProtectedVariableLibInitialize (&ContextIn);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "%a: %d ProtectedVariableLibInitialize() return status: %r\n",
> + __FUNCTION__,
> + __LINE__,
> + Status
> + ));
> + }
> +
> gBS->CloseEvent (Event);
> }
>
> --
> 2.35.1.windows.2
next prev parent reply other threads:[~2022-06-13 6:09 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-09 6:02 [PATCH v3 00/28] UEFI variable protection Judah Vang
2022-06-09 6:02 ` [PATCH v3 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-06-13 6:05 ` [edk2-devel] " Wu, Hao A
2022-06-09 6:02 ` [PATCH v3 02/28] SecurityPkg: Add new GUIDs for Judah Vang
2022-06-09 6:02 ` [PATCH v3 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
2022-06-09 6:02 ` [PATCH v3 04/28] MdeModulePkg: Add reference to new Ppi Guid Judah Vang
2022-06-09 6:02 ` [PATCH v3 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
2022-06-13 6:07 ` [edk2-devel] " Wu, Hao A
2022-06-09 6:03 ` [PATCH v3 06/28] MdeModulePkg: Add new include files Judah Vang
2022-06-13 6:07 ` [edk2-devel] " Wu, Hao A
2022-06-09 6:03 ` [PATCH v3 07/28] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
2022-06-09 6:03 ` [PATCH v3 08/28] MdeModulePkg: Add new Variable functionality Judah Vang
2022-06-13 6:08 ` Wu, Hao A
2022-06-09 6:03 ` [PATCH v3 09/28] MdeModulePkg: Add support for Protected Variables Judah Vang
2022-06-13 6:08 ` Wu, Hao A [this message]
2022-06-09 6:03 ` [PATCH v3 10/28] SecurityPkg: Add new KeyService types and defines Judah Vang
2022-06-09 6:03 ` [PATCH v3 11/28] SecurityPkg: Update RPMC APIs with index Judah Vang
2022-06-09 6:03 ` [PATCH v3 12/28] SecurityPkg: Add new variable types and functions Judah Vang
2022-06-09 6:03 ` [PATCH v3 13/28] SecurityPkg: Fix GetVariableKey API Judah Vang
2022-06-09 6:03 ` [PATCH v3 14/28] SecurityPkg: Add null encryption variable libs Judah Vang
2022-06-09 6:03 ` [PATCH v3 15/28] SecurityPkg: Add VariableKey library function Judah Vang
2022-06-09 6:03 ` [PATCH v3 16/28] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
2022-06-09 6:03 ` [PATCH v3 17/28] SecurityPkg: Add Protected Variable Services Judah Vang
2022-06-09 8:30 ` Min Xu
2022-06-16 19:23 ` [edk2-devel] " Judah Vang
2022-08-07 17:34 ` Wang, Jian J
2022-06-09 6:03 ` [PATCH v3 18/28] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
2022-06-13 6:08 ` [edk2-devel] " Wu, Hao A
2022-06-09 6:03 ` [PATCH v3 19/28] SecurityPkg: Add references to new *.inf files Judah Vang
2022-06-09 6:03 ` [PATCH v3 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull Judah Vang
2022-06-09 6:03 ` [PATCH v3 21/28] UefiPayloadPkg: Add ProtectedVariable reference Judah Vang
2022-06-09 6:03 ` [PATCH v3 22/28] EmulatorPkg: " Judah Vang
2022-07-13 5:21 ` [edk2-devel] " Ni, Ray
2022-06-09 6:03 ` [PATCH v3 23/28] OvmfPkg: " Judah Vang
2022-06-09 6:03 ` [PATCH v3 24/28] OvmfPkg: Add ProtectedVariableLib reference Judah Vang
2022-06-09 6:03 ` [PATCH v3 25/28] " Judah Vang
2022-06-09 6:03 ` [PATCH v3 26/28] " Judah Vang
2022-06-09 6:03 ` [PATCH v3 27/28] OvmfPkg: Add ProtectedVariable reference Judah Vang
2022-06-09 6:03 ` [PATCH v3 28/28] CryptoPkg: Enable cypto HMAC KDF and AES library Judah Vang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DM6PR11MB40256D7D352B8E3CCAF69597CAAB9@DM6PR11MB4025.namprd11.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox