From nobody Thu Apr 25 09:37:48 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+89428+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+89428+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1651255521; cv=none; d=zohomail.com; s=zohoarc; b=XZE6HvFCAd01vaEj4ruxAdcnX+mURsRdHux8uLTl0I0iP8jKQihsB9vz0j3l8ALPbKkeW18dWz1lT6FLeJj/VtlCvp32l0L2bB4rSO9/MWtW+WYFQ5kg0qZkrN90tGHa7p10M+QJgCbr/biY1+R2TiBiJUh5ba9svZ1CxEJATWk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1651255521; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=7Qd0vSppBpK9Y9veiO/h68VTzdf1QganRdvXYQhQHwo=; b=P+0KeqN2z72xU1w88ocKi+xD+Njes2jIqMN+xmcUNue592FalzcE4wFQH3s45FcmpJPJHhv9h41IWw//CuaHvB6XnCFJqEzs5PZQHgL+/saWcEc3tp75jsMLRJ4NrgK/nsCoQVCenffxbkLJE/459aCB2v2SXppVELxU7XXKTmQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+89428+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1651255521642295.686450146404; Fri, 29 Apr 2022 11:05:21 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id nCwpYY1788612xILdDsQHR82; Fri, 29 Apr 2022 11:05:21 -0700 X-Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web08.13430.1651255518273693340 for ; Fri, 29 Apr 2022 11:05:20 -0700 X-IronPort-AV: E=McAfee;i="6400,9594,10332"; a="248659205" X-IronPort-AV: E=Sophos;i="5.91,186,1647327600"; d="scan'208";a="248659205" X-Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Apr 2022 11:05:17 -0700 X-IronPort-AV: E=Sophos;i="5.91,186,1647327600"; d="scan'208";a="514955685" X-Received: from jvang-mobl.amr.corp.intel.com ([10.212.198.238]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Apr 2022 11:05:16 -0700 From: "Judah Vang" To: devel@edk2.groups.io Cc: Jian J Wang , Liming Gao , Nishant C Mistry Subject: [edk2-devel] [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables Date: Fri, 29 Apr 2022 11:04:11 -0700 Message-Id: <20220429180430.3292-10-judah.vang@intel.com> In-Reply-To: <20220429180430.3292-1-judah.vang@intel.com> References: <20220429180430.3292-1-judah.vang@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,judah.vang@intel.com X-Gm-Message-State: BDshcsX4X9cfloPSXqQq1kk8x1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1651255521; bh=qCik+zdReI3bhdNErAIBoGSGBDQIvYaxZVXNiF4WyM0=; h=Cc:Date:From:Reply-To:Subject:To; b=Gm5DMJ7hYqmFGV9S0LvvYRwmCKMolZs9ugdvudps5pH/tqasFY62ErluK7tbu3m59Xu rjgmqrSETlP4ORfUjwgcR1I+9xo14Yb0qky+GnXafT10VmYRt4B7wS7gK0ph8mxeNrS5K JESpBGGae7sF7L09v3zvxuVfaCbajOEP11E= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1651255522959100028 Content-Type: text/plain; charset="utf-8" REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2594 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 Cc: Liming Gao Cc: Nishant C Mistry Signed-off-by: Jian J Wang Signed-off-by: Nishant C Mistry Signed-off-by: Judah Vang --- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | = 3 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | = 3 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf | = 4 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | = 3 +- MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 12= 6 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 9= 1 +- MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 34= 9 +++- MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 213= 9 +++++++++++--------- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 2= 6 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 16= 7 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 19= 4 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 32= 0 ++- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c | = 2 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 3= 9 +- MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c | 4= 1 +- 15 files changed, 2454 insertions(+), 1053 deletions(-) diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.= inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index c9434df631ee..c0b90e6ca066 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -9,7 +9,7 @@ # This external input must be validated carefully to avoid security issue= s such as # buffer overflow or integer overflow. # -# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
# Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -73,6 +73,7 @@ [LibraryClasses] VarCheckLib VariablePolicyLib VariablePolicyHelperLib + ProtectedVariableLib =20 [Protocols] gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/M= deModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf index eaa97a01c6e5..6f9f027fbb0f 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf @@ -18,7 +18,7 @@ # may not be modified without authorization. If platform fails to protect= these resources, # the authentication service provided in this driver will be broken, and = the behavior is undefined. # -# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
# Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -82,6 +82,7 @@ [LibraryClasses] UefiBootServicesTableLib VariablePolicyLib VariablePolicyHelperLib + ProtectedVariableLib =20 [Protocols] gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeD= xe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.i= nf 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.
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -61,6 +61,8 @@ [LibraryClasses] SafeIntLib PcdLib MmUnblockMemoryLib + ProtectedVariableLib + IoLib =20 [Protocols] gEfiVariableWriteArchProtocolGuid ## PRODUCES diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneM= m.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf index d8c4f77e7f1f..6ea7b8d4293e 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf @@ -18,7 +18,7 @@ # may not be modified without authorization. If platform fails to protect= these resources, # the authentication service provided in this driver will be broken, and = the behavior is undefined. # -# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
# Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -78,6 +78,7 @@ [LibraryClasses] VarCheckLib VariablePolicyLib VariablePolicyHelperLib + ProtectedVariableLib =20 [Protocols] gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeMod= ulePkg/Universal/Variable/RuntimeDxe/Variable.h index 31e408976a35..97b4f9c906ff 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -2,7 +2,7 @@ The internal header file includes the common header files, defines internal structure and functions used by Variable modules. =20 -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ @@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include #include @@ -823,4 +824,127 @@ VariableExLibAtRuntime ( VOID ); =20 +/** + 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 o= r not; + if it is non-volatile, need FTW. + @param[in, out] UpdatingPtrTrack Pointer to updating variable poi= nter track structure. + @param[in] NewVariable Pointer to new variable. + @param[in] NewVariableSize New variable size. + + @return EFI_SUCCESS Reclaim operation has finished succ= essfully. + @return EFI_OUT_OF_RESOURCES No enough memory resources or varia= ble space. + @return Others Unexpect error happened during recl= aim 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 VARIA= BLE_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 u= pdate. + @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 informatio= n. + @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 successful= ly. + @retval EFI_UNSUPPORTED If this function is called directly in r= untime. + @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 caref= ully 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 t= han the + data, this value contains the require= d 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 f= ound. + +**/ +EFI_STATUS +FindVariableInSmm ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ); + #endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h b= /MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h index 951e8a089e34..3a4e8019aaf9 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h @@ -2,7 +2,7 @@ Functions in this module are associated with variable parsing operations= and are intended to be usable across variable driver source files. =20 -Copyright (c) 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ @@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent =20 @param[in] Variable Pointer to the Variable Header. @param[in] VariableStoreEnd Pointer to the Variable Store End. + @param[in] AuthFormat Auth-variable indicator. =20 @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 ); =20 /** @@ -192,6 +194,28 @@ GetVariableDataOffset ( IN BOOLEAN AuthFormat ); =20 +/** + Get variable data payload. + + @param[in] Variable Pointer to the Variable Header. + @param[out] Data Pointer to buffer used to store the variabl= e 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 variabl= e data. + +**/ +EFI_STATUS +GetVariableData ( + IN VARIABLE_HEADER *Variable, + IN OUT VOID *Data, + IN OUT UINT32 *DataSize, + IN BOOLEAN AuthFlag + ); + /** =20 This code gets the pointer to the next variable header. @@ -344,4 +368,67 @@ UpdateVariableInfo ( IN OUT VARIABLE_INFO_ENTRY **VariableInfo ); =20 +/** + + Retrieve details of the variable next to given variable within VariableS= tore. + + If VarInfo->Address is NULL, the first one in VariableStore is returned. + + VariableStart and/or VariableEnd can be given optionally for the situati= on + 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 deter= mine + the correct variable storage range. + + @param VariableStore Pointer to a variable storage. It's opti= onal. + @param VariableStart Start point of valid range in VariableSt= ore. + @param VariableEnd End point of valid range in VariableStor= e. + @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 successful= ly. + +**/ +EFI_STATUS +EFIAPI +GetNextVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VarInfo + ); + +/** + + Retrieve details about a variable and return them in VariableInfo->Heade= r. + + If VariableInfo->Address is given, this function will calculate its offs= et + relative to given variable storage via VariableStore; Otherwise, it will= try + other internal variable storages or cached copies. It's assumed that, fo= r all + copies of NV variable storage, all variables are stored in the same rela= tive + 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->Addres= s, + this function will return the variable memory address inside VariableSto= re, + if given, via VariableInfo->Address; Otherwise, the address of other sto= rage + 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 opti= onal. + @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 rang= e of + any given or internal storage copies. + @retval EFI_SUCCESS Variable details are retrieved successful= ly. + +**/ +EFI_STATUS +EFIAPI +GetVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VarInfo + ); + #endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c b/MdeModu= lePkg/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. =20 -Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ =20 #include "Variable.h" +#include "VariableNonVolatile.h" +#include "VariableParsing.h" +#include "VariableRuntimeCache.h" =20 /** Gets LBA of block and offset by given address. @@ -155,3 +158,347 @@ FtwVariableSpace ( =20 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 o= r not; + if it is non-volatile, need FTW. + @param[in, out] UpdatingPtrTrack Pointer to updating variable poi= nter track structure. + @param[in] NewVariable Pointer to new variable. + @param[in] NewVariableSize New variable size. + + @return EFI_SUCCESS Reclaim operation has finished succ= essfully. + @return EFI_OUT_OF_RESOURCES No enough memory resources or varia= ble space. + @return Others Unexpect error happened during recl= aim 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 =3D mVariableModuleGlobal->VariableGlobal.Au= thFormat; + UpdatingVariable =3D NULL; + UpdatingInDeletedTransition =3D NULL; + if (UpdatingPtrTrack !=3D NULL) { + UpdatingVariable =3D UpdatingPtrTrack->CurrPtr; + UpdatingInDeletedTransition =3D UpdatingPtrTrack->InDeletedTransitionP= tr; + } + + VariableStoreHeader =3D (VARIABLE_STORE_HEADER *)((UINTN)VariableBase); + + CommonVariableTotalSize =3D 0; + CommonUserVariableTotalSize =3D 0; + HwErrVariableTotalSize =3D 0; + + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { + // + // Start Pointers for the variable. + // + Variable =3D GetStartPointer (VariableStoreHeader); + MaximumBufferSize =3D sizeof (VARIABLE_STORE_HEADER); + + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHe= ader), AuthFormat)) { + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); + if (((Variable->State =3D=3D VAR_ADDED) || (Variable->State =3D=3D (= VAR_IN_DELETED_TRANSITION & VAR_ADDED))) && + (Variable !=3D UpdatingVariable) && + (Variable !=3D UpdatingInDeletedTransition) + ) + { + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; + MaximumBufferSize +=3D VariableSize; + } + + Variable =3D NextVariable; + } + + if (NewVariable !=3D NULL) { + // + // Add the new variable size. + // + MaximumBufferSize +=3D NewVariableSize; + } + + // + // Reserve the 1 Bytes with Oxff to identify the + // end of the variable buffer. + // + MaximumBufferSize +=3D 1; + ValidBuffer =3D AllocatePool (MaximumBufferSize); + if (ValidBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // For NV variable reclaim, don't allocate pool here and just use mNvV= ariableCache + // as the buffer to reduce SMRAM consumption for SMM variable driver. + // + MaximumBufferSize =3D mNvVariableCache->Size; + ValidBuffer =3D (UINT8 *)mNvVariableCache; + } + + SetMem (ValidBuffer, MaximumBufferSize, 0xff); + + // + // Copy variable store header. + // + CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER= )); + CurrPtr =3D (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuff= er); + + // + // Reinstall all ADDED variables as long as they are not identical to Up= dating Variable. + // + Variable =3D GetStartPointer (VariableStoreHeader); + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHead= er), AuthFormat)) { + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); + if ((Variable !=3D UpdatingVariable) && (Variable->State =3D=3D VAR_AD= DED)) { + VariableSize =3D (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) + =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) + { + HwErrVariableTotalSize +=3D VariableSize; + } else { + CommonVariableTotalSize +=3D VariableSize; + if (IsUserVariable (Variable)) { + CommonUserVariableTotalSize +=3D VariableSize; + } + } + } + + CurrPtr +=3D VariableSize; + } + + Variable =3D NextVariable; + } + + // + // Reinstall all in delete transition variables. + // + Variable =3D GetStartPointer (VariableStoreHeader); + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHead= er), AuthFormat)) { + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); + if ((Variable !=3D UpdatingVariable) && (Variable !=3D UpdatingInDelet= edTransition) && (Variable->State =3D=3D (VAR_IN_DELETED_TRANSITION & VAR_A= DDED)) && + (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFor= mat)) =3D=3D FALSE)) + { + FoundAdded =3D FALSE; + AddedVariable =3D GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuf= fer); + while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABL= E_STORE_HEADER *)ValidBuffer), AuthFormat)) { + NextAddedVariable =3D GetNextVariablePtr (AddedVariable, AuthForma= t); + NameSize =3D NameSizeOfVariable (AddedVariable, AuthForma= t); + if (CompareGuid ( + GetVendorGuidPtr (AddedVariable, AuthFormat), + GetVendorGuidPtr (Variable, AuthFormat) + ) && (NameSize =3D=3D NameSizeOfVariable (Variable, AuthForm= at))) + { + Point0 =3D (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat= ); + Point1 =3D (VOID *)GetVariableNamePtr (Variable, AuthFormat); + if (CompareMem (Point0, Point1, NameSize) =3D=3D 0) { + FoundAdded =3D TRUE; + break; + } + } + + AddedVariable =3D NextAddedVariable; + } + + if (!FoundAdded) { + // + // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED. + // + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; + CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize); + ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; + if (!IsVolatile) { + (VOID)ProtectedVariableLibRefresh ( + (VARIABLE_HEADER *)CurrPtr, + VariableSize, + (UINTN)CurrPtr - (UINTN)ValidBuffer, + FALSE + ); + + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) + =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) + { + HwErrVariableTotalSize +=3D VariableSize; + } else { + CommonVariableTotalSize +=3D VariableSize; + if (IsUserVariable (Variable)) { + CommonUserVariableTotalSize +=3D VariableSize; + } + } + } + + CurrPtr +=3D VariableSize; + } + } + + Variable =3D NextVariable; + } + + // + // Install the new variable if it is not NULL. + // + if (NewVariable !=3D NULL) { + if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > Variable= StoreHeader->Size) { + // + // No enough space to store the new variable. + // + Status =3D EFI_OUT_OF_RESOURCES; + goto Done; + } + + if (!IsVolatile) { + if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) = =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize +=3D NewVariableSize; + } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RE= CORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + CommonVariableTotalSize +=3D NewVariableSize; + if (IsUserVariable (NewVariable)) { + CommonUserVariableTotalSize +=3D NewVariableSize; + } + } + + if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) || + (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariable= Space) || + (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxU= serVariableSpace)) + { + // + // No enough space to store the new variable by NV or NV+HR attrib= ute. + // + Status =3D EFI_OUT_OF_RESOURCES; + goto Done; + } + } + + CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize); + ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; + if (UpdatingVariable !=3D NULL) { + UpdatingPtrTrack->CurrPtr =3D (VARIABLE_HEADER *)((UI= NTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer (= (VARIABLE_STORE_HEADER *)ValidBuffer))); + UpdatingPtrTrack->InDeletedTransitionPtr =3D NULL; + } + + CurrPtr +=3D NewVariableSize; + } + + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { + // + // If volatile/emulated non-volatile variable store, just copy valid b= uffer. + // + SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff); + CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (= UINTN)ValidBuffer); + *LastVariableOffset =3D (UINTN)CurrPtr - (UINTN)ValidBuffer; + if (!IsVolatile) { + // + // Emulated non-volatile variable mode. + // + mVariableModuleGlobal->HwErrVariableTotalSize =3D HwErrVariable= TotalSize; + mVariableModuleGlobal->CommonVariableTotalSize =3D CommonVariabl= eTotalSize; + mVariableModuleGlobal->CommonUserVariableTotalSize =3D CommonUserVar= iableTotalSize; + } + + Status =3D EFI_SUCCESS; + } else { + // + // If non-volatile variable store, perform FTW here. + // + Status =3D FtwVariableSpace ( + VariableBase, + (VARIABLE_STORE_HEADER *)ValidBuffer + ); + if (!EFI_ERROR (Status)) { + *LastVariableOffset =3D (UINTN)CurrPt= r - (UINTN)ValidBuffer; + mVariableModuleGlobal->HwErrVariableTotalSize =3D HwErrVariable= TotalSize; + mVariableModuleGlobal->CommonVariableTotalSize =3D CommonVariabl= eTotalSize; + mVariableModuleGlobal->CommonUserVariableTotalSize =3D CommonUserVar= iableTotalSize; + } else { + mVariableModuleGlobal->HwErrVariableTotalSize =3D 0; + mVariableModuleGlobal->CommonVariableTotalSize =3D 0; + mVariableModuleGlobal->CommonUserVariableTotalSize =3D 0; + Variable =3D GetStartPoint= er ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase); + while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STO= RE_HEADER *)(UINTN)VariableBase), AuthFormat)) { + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) = =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + mVariableModuleGlobal->HwErrVariableTotalSize +=3D VariableSize; + } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_REC= ORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + mVariableModuleGlobal->CommonVariableTotalSize +=3D VariableSize; + if (IsUserVariable (Variable)) { + mVariableModuleGlobal->CommonUserVariableTotalSize +=3D Variab= leSize; + } + } + + Variable =3D NextVariable; + } + + *LastVariableOffset =3D (UINTN)Variable - (UINTN)VariableBase; + } + } + +Done: + DoneStatus =3D EFI_SUCCESS; + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { + DoneStatus =3D SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeC= acheContext.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, VariableStore= Header->Size); + DoneStatus =3D SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeC= acheContext.VariableRuntimeNvCache, + 0, + VariableStoreHeader->Size + ); + ASSERT_EFI_ERROR (DoneStatus); + } + + if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) { + Status =3D DoneStatus; + } + + return Status; +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeMod= ulePkg/Universal/Variable/RuntimeDxe/Variable.c index 6c1a3440ac8c..6e86099eb72b 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -16,7 +16,7 @@ VariableServiceSetVariable() should also check authenticate data to avoi= d buffer overflow, integer overflow. It should also check attribute to avoid authentication= bypass. =20 -Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP
Copyright (c) Microsoft Corporation.
Copyright (c) 2022, ARM Limited. All rights reserved.
@@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "VariableParsing.h" #include "VariableRuntimeCache.h" =20 -VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal =3D NULL; =20 /// /// Define a memory cache that improves the search performance for a varia= ble. @@ -458,7 +458,7 @@ CalculateCommonUserVariableTotalSize ( // if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace !=3D= mVariableModuleGlobal->CommonVariableSpace)) { Variable =3D GetStartPointer (mNvVariableCache); - while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCach= e))) { + while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCach= e), mVariableModuleGlobal->VariableGlobal.AuthFormat)) { NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlobal= ->VariableGlobal.AuthFormat); VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D= EFI_VARIABLE_HARDWARE_ERROR_RECORD) { @@ -497,330 +497,6 @@ InitializeVariableQuota ( CalculateCommonUserVariableTotalSize (); } =20 -/** - - 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 o= r not; - if it is non-volatile, need FTW. - @param[in, out] UpdatingPtrTrack Pointer to updating variable poi= nter track structure. - @param[in] NewVariable Pointer to new variable. - @param[in] NewVariableSize New variable size. - - @return EFI_SUCCESS Reclaim operation has finished succ= essfully. - @return EFI_OUT_OF_RESOURCES No enough memory resources or varia= ble space. - @return Others Unexpect error happened during recl= aim 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 =3D mVariableModuleGlobal->VariableGlobal.Au= thFormat; - UpdatingVariable =3D NULL; - UpdatingInDeletedTransition =3D NULL; - if (UpdatingPtrTrack !=3D NULL) { - UpdatingVariable =3D UpdatingPtrTrack->CurrPtr; - UpdatingInDeletedTransition =3D UpdatingPtrTrack->InDeletedTransitionP= tr; - } - - VariableStoreHeader =3D (VARIABLE_STORE_HEADER *)((UINTN)VariableBase); - - CommonVariableTotalSize =3D 0; - CommonUserVariableTotalSize =3D 0; - HwErrVariableTotalSize =3D 0; - - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { - // - // Start Pointers for the variable. - // - Variable =3D GetStartPointer (VariableStoreHeader); - MaximumBufferSize =3D sizeof (VARIABLE_STORE_HEADER); - - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHe= ader))) { - NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); - if (((Variable->State =3D=3D VAR_ADDED) || (Variable->State =3D=3D (= VAR_IN_DELETED_TRANSITION & VAR_ADDED))) && - (Variable !=3D UpdatingVariable) && - (Variable !=3D UpdatingInDeletedTransition) - ) - { - VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; - MaximumBufferSize +=3D VariableSize; - } - - Variable =3D NextVariable; - } - - if (NewVariable !=3D NULL) { - // - // Add the new variable size. - // - MaximumBufferSize +=3D NewVariableSize; - } - - // - // Reserve the 1 Bytes with Oxff to identify the - // end of the variable buffer. - // - MaximumBufferSize +=3D 1; - ValidBuffer =3D AllocatePool (MaximumBufferSize); - if (ValidBuffer =3D=3D NULL) { - return EFI_OUT_OF_RESOURCES; - } - } else { - // - // For NV variable reclaim, don't allocate pool here and just use mNvV= ariableCache - // as the buffer to reduce SMRAM consumption for SMM variable driver. - // - MaximumBufferSize =3D mNvVariableCache->Size; - ValidBuffer =3D (UINT8 *)mNvVariableCache; - } - - SetMem (ValidBuffer, MaximumBufferSize, 0xff); - - // - // Copy variable store header. - // - CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER= )); - CurrPtr =3D (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuff= er); - - // - // Reinstall all ADDED variables as long as they are not identical to Up= dating Variable. - // - Variable =3D GetStartPointer (VariableStoreHeader); - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHead= er))) { - NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); - if ((Variable !=3D UpdatingVariable) && (Variable->State =3D=3D VAR_AD= DED)) { - VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; - CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize); - CurrPtr +=3D VariableSize; - if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_= ERROR_RECORD) =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - HwErrVariableTotalSize +=3D VariableSize; - } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HA= RDWARE_ERROR_RECORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - CommonVariableTotalSize +=3D VariableSize; - if (IsUserVariable (Variable)) { - CommonUserVariableTotalSize +=3D VariableSize; - } - } - } - - Variable =3D NextVariable; - } - - // - // Reinstall all in delete transition variables. - // - Variable =3D GetStartPointer (VariableStoreHeader); - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHead= er))) { - NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); - if ((Variable !=3D UpdatingVariable) && (Variable !=3D UpdatingInDelet= edTransition) && (Variable->State =3D=3D (VAR_IN_DELETED_TRANSITION & VAR_A= DDED))) { - // - // Buffer has cached all ADDED variable. - // Per IN_DELETED variable, we have to guarantee that - // no ADDED one in previous buffer. - // - - FoundAdded =3D FALSE; - AddedVariable =3D GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuf= fer); - while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABL= E_STORE_HEADER *)ValidBuffer))) { - NextAddedVariable =3D GetNextVariablePtr (AddedVariable, AuthForma= t); - NameSize =3D NameSizeOfVariable (AddedVariable, AuthForma= t); - if (CompareGuid ( - GetVendorGuidPtr (AddedVariable, AuthFormat), - GetVendorGuidPtr (Variable, AuthFormat) - ) && (NameSize =3D=3D NameSizeOfVariable (Variable, AuthForm= at))) - { - Point0 =3D (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat= ); - Point1 =3D (VOID *)GetVariableNamePtr (Variable, AuthFormat); - if (CompareMem (Point0, Point1, NameSize) =3D=3D 0) { - FoundAdded =3D TRUE; - break; - } - } - - AddedVariable =3D NextAddedVariable; - } - - if (!FoundAdded) { - // - // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED. - // - VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; - CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize); - ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; - CurrPtr +=3D VariableSize; - if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWAR= E_ERROR_RECORD) =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - HwErrVariableTotalSize +=3D VariableSize; - } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_= HARDWARE_ERROR_RECORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - CommonVariableTotalSize +=3D VariableSize; - if (IsUserVariable (Variable)) { - CommonUserVariableTotalSize +=3D VariableSize; - } - } - } - } - - Variable =3D NextVariable; - } - - // - // Install the new variable if it is not NULL. - // - if (NewVariable !=3D NULL) { - if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > Variable= StoreHeader->Size) { - // - // No enough space to store the new variable. - // - Status =3D EFI_OUT_OF_RESOURCES; - goto Done; - } - - if (!IsVolatile) { - if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) = =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - HwErrVariableTotalSize +=3D NewVariableSize; - } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RE= CORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - CommonVariableTotalSize +=3D NewVariableSize; - if (IsUserVariable (NewVariable)) { - CommonUserVariableTotalSize +=3D NewVariableSize; - } - } - - if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) || - (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariable= Space) || - (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxU= serVariableSpace)) - { - // - // No enough space to store the new variable by NV or NV+HR attrib= ute. - // - Status =3D EFI_OUT_OF_RESOURCES; - goto Done; - } - } - - CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize); - ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; - if (UpdatingVariable !=3D NULL) { - UpdatingPtrTrack->CurrPtr =3D (VARIABLE_HEADER *)((UI= NTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer (= (VARIABLE_STORE_HEADER *)ValidBuffer))); - UpdatingPtrTrack->InDeletedTransitionPtr =3D NULL; - } - - CurrPtr +=3D NewVariableSize; - } - - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { - // - // If volatile/emulated non-volatile variable store, just copy valid b= uffer. - // - SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff); - CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (= UINTN)ValidBuffer); - *LastVariableOffset =3D (UINTN)CurrPtr - (UINTN)ValidBuffer; - if (!IsVolatile) { - // - // Emulated non-volatile variable mode. - // - mVariableModuleGlobal->HwErrVariableTotalSize =3D HwErrVariable= TotalSize; - mVariableModuleGlobal->CommonVariableTotalSize =3D CommonVariabl= eTotalSize; - mVariableModuleGlobal->CommonUserVariableTotalSize =3D CommonUserVar= iableTotalSize; - } - - Status =3D EFI_SUCCESS; - } else { - // - // If non-volatile variable store, perform FTW here. - // - Status =3D FtwVariableSpace ( - VariableBase, - (VARIABLE_STORE_HEADER *)ValidBuffer - ); - if (!EFI_ERROR (Status)) { - *LastVariableOffset =3D (UINTN)CurrPt= r - (UINTN)ValidBuffer; - mVariableModuleGlobal->HwErrVariableTotalSize =3D HwErrVariable= TotalSize; - mVariableModuleGlobal->CommonVariableTotalSize =3D CommonVariabl= eTotalSize; - mVariableModuleGlobal->CommonUserVariableTotalSize =3D CommonUserVar= iableTotalSize; - } else { - mVariableModuleGlobal->HwErrVariableTotalSize =3D 0; - mVariableModuleGlobal->CommonVariableTotalSize =3D 0; - mVariableModuleGlobal->CommonUserVariableTotalSize =3D 0; - Variable =3D GetStartPoint= er ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase); - while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STO= RE_HEADER *)(UINTN)VariableBase))) { - NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); - VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; - if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) = =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - mVariableModuleGlobal->HwErrVariableTotalSize +=3D VariableSize; - } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_REC= ORD) !=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - mVariableModuleGlobal->CommonVariableTotalSize +=3D VariableSize; - if (IsUserVariable (Variable)) { - mVariableModuleGlobal->CommonUserVariableTotalSize +=3D Variab= leSize; - } - } - - Variable =3D NextVariable; - } - - *LastVariableOffset =3D (UINTN)Variable - (UINTN)VariableBase; - } - } - -Done: - DoneStatus =3D EFI_SUCCESS; - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { - DoneStatus =3D SynchronizeRuntimeVariableCache ( - &mVariableModuleGlobal->VariableGlobal.VariableRuntimeC= acheContext.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, VariableStore= Header->Size); - DoneStatus =3D SynchronizeRuntimeVariableCache ( - &mVariableModuleGlobal->VariableGlobal.VariableRuntimeC= acheContext.VariableRuntimeNvCache, - 0, - VariableStoreHeader->Size - ); - ASSERT_EFI_ERROR (DoneStatus); - } - - if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) { - Status =3D DoneStatus; - } - - return Status; -} - /** Finds variable in storage blocks of volatile and non-volatile storage ar= eas. =20 @@ -1657,9 +1333,665 @@ AutoUpdateLangVariable ( } =20 /** - Update the variable region with Variable information. If EFI_VARIABLE_AU= THENTICATED_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. =20 + @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 =3D=3D NULL) || (VariableSize =3D=3D 0)) { + return EFI_SUCCESS; + } + + if (VolatileFlag) { + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + if ((UINT32)(VariableSize + mVariableModuleGlobal->VolatileLastVariabl= eOffset) + > VarStore->Size) + { + return EFI_BUFFER_TOO_SMALL; + } + } else { + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0) { + IsCommonVariable =3D TRUE; + IsCommonUserVariable =3D IsUserVariable (NewVariable); + } else { + IsCommonVariable =3D FALSE; + IsCommonUserVariable =3D FALSE; + } + + CommonVariableTotalSize =3D mVariableModuleGlobal->CommonVariableT= otalSize + VariableSize; + CommonUserVariableTotalSize =3D mVariableModuleGlobal->CommonUserVaria= bleTotalSize + VariableSize; + HwErrVariableTotalSize =3D mVariableModuleGlobal->HwErrVariableTo= talSize + VariableSize; + + if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) && + (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize))) + || (IsCommonVariable && (CommonVariableTotalSize > mVariableModuleG= lobal->CommonVariableSpace)) + || (IsCommonVariable && + AtRuntime () && + (CommonVariableTotalSize > mVariableModuleGlobal->CommonRuntime= VariableSpace)) + || (IsCommonUserVariable && + (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMax= UserVariableSpace))) + { + if (AtRuntime ()) { + if (IsCommonUserVariable && + ((VariableSize + mVariableModuleGlobal->CommonUserVariableTota= lSize) + > mVariableModuleGlobal->CommonMaxUserVariableSpace)) + { + RecordVarErrorFlag ( + VAR_ERROR_FLAG_USER_ERROR, + VariableName, + VendorGuid, + Attributes, + VariableSize + ); + } + + if (IsCommonVariable && + ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSiz= e) + > 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 =3D KeyIndex; + NewVariable->MonotonicCount =3D MonotonicCount; + + if ((TimeStamp !=3D NULL) && + ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != =3D 0)) + { + // + // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, on= ly + // when the new TimeStamp value is later than the current timestamp as= sociated + // with the variable, we need associate the new timestamp with the upd= ated value. + // + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) !=3D 0) && + (OldVariable !=3D NULL) && + !VariableCompareTimeStampInternal (&OldVariable->TimeStamp, TimeSt= amp)) + { + TimeStamp =3D &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 =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; + + if (AuthFormat) { + SetVariableAuthData ( + (AUTHENTICATED_VARIABLE_HEADER *)NewVariable, + (AUTHENTICATED_VARIABLE_HEADER *)OldVariable, + Attributes, + KeyIndex, + MonotonicCount, + TimeStamp + ); + } + + NewVariable->StartId =3D VARIABLE_DATA; + NewVariable->State =3D VAR_ADDED; + NewVariable->Reserved =3D 0; + NewVariable->Attributes =3D Attributes & (~EFI_VARIABLE_APPEND_WRITE); + + CopyMem ( + GetVendorGuidPtr (NewVariable, AuthFormat), + VendorGuid, + sizeof (EFI_GUID) + ); + + NameSize =3D 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 =3D GetVariableDataPtr (NewVariable, AuthFormat); + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) !=3D 0) && + (OldVariable !=3D NULL) && + ((OldVariable->State =3D=3D VAR_ADDED) || + (OldVariable->State =3D=3D (VAR_ADDED & VAR_IN_DELETED_TRANSITION))= )) + { + // + // Get old data, which might be encrypted. + // + OldDataSize =3D mVariableModuleGlobal->ScratchBufferSize + - ((UINTN)DataPtr - (UINTN)NewVariable); + Status =3D ProtectedVariableLibGetByBuffer ( + OldVariable, + DataPtr, + (UINT32 *)&OldDataSize, + AuthFormat + ); + if (Status =3D=3D EFI_UNSUPPORTED) { + OldDataSize =3D DataSizeOfVariable (OldVariable, AuthFormat); + CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat), OldD= ataSize); + } else if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + + DataPtr +=3D OldDataSize; + // + // Update data size. + // + SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat= ); + } + + CopyMem (DataPtr, Data, DataSize); + + // + // The actual size of the variable stored in storage should include padd= ing. + // + return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) - (UINTN)New= Variable); +} + +/** + 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 =3D UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + Volatile, + FALSE, + mVariableModuleGlobal->FvbInstance, + (UINTN)&Variable->State, + sizeof (NewState), + &NewState + ); + if (!EFI_ERROR (Status) && (CacheVariable !=3D NULL)) { + CacheVariable->State =3D 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 w= ritten. + @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 =3D *NewVariable; + if (Volatile) { + // + // For non-volatile variable, one step only : + // + WriteSteps[0].Offset =3D *Offset; + WriteSteps[0].Buffer =3D (UINT8 *)Variable; + WriteSteps[0].Size =3D VariableSize; + + Steps =3D 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 =3D 0xff; + WriteSteps[0].Offset =3D *Offset; + WriteSteps[0].Buffer =3D (UINT8 *)Variable; + WriteSteps[0].Size =3D (UINT32)GetVariableHeaderSize (AuthFormat); + + WriteSteps[1].State =3D VAR_HEADER_VALID_ONLY; + WriteSteps[1].Offset =3D *Offset + OFFSET_OF (VARIABLE_HEADER, State); + WriteSteps[1].Buffer =3D &WriteSteps[1].State; + WriteSteps[1].Size =3D sizeof (Variable->State); + + WriteSteps[2].Offset =3D *Offset + GetVariableHeaderSize (AuthFormat); + WriteSteps[2].Buffer =3D (UINT8 *)Variable + GetVariableHeaderSize (Au= thFormat); + WriteSteps[2].Size =3D VariableSize - (UINT32)GetVariableHeaderSize = (AuthFormat); + + WriteSteps[3].State =3D VAR_ADDED; + WriteSteps[3].Offset =3D *Offset + OFFSET_OF (VARIABLE_HEADER, State); + WriteSteps[3].Buffer =3D &WriteSteps[3].State; + WriteSteps[3].Size =3D sizeof (Variable->State); + + Steps =3D ARRAY_SIZE (WriteSteps); + } + + for (Index =3D 0; Index < Steps; ++Index) { + Status =3D 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 =3D VAR_ADDED; + if (!Volatile) { + CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize); + } + + *NewVariable =3D (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset); + *Offset +=3D HEADER_ALIGN (VariableSize); + + return EFI_SUCCESS; +} + +/** + Rebase the given variable pointer(s) to the equivalent one in given vari= able + storage via VarStore. + + @param[in] InVarTrackPtr Pointer to current variable in cache. + @param[out] OutVarTrackPtr Pointer to rebased variable against Va= rStore. + @param[in] VarStore Start of variable storage to rebase ag= ainst. + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] ByOffset If TRUE, don't do variable search in V= arStore. + + @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 FALS= E. + +**/ +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 =3D=3D NULL) || (OutVarTrackPtr =3D=3D NULL) || (VarS= tore =3D=3D NULL)) { + ASSERT (InVarTrackPtr !=3D NULL); + ASSERT (OutVarTrackPtr !=3D NULL); + ASSERT (VarStore !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; + + if ( (InVarTrackPtr->CurrPtr =3D=3D NULL) + || (InVarTrackPtr->StartPtr =3D=3D GetStartPointer (VarStore))) + { + CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof (VARIABLE_POINTER_TRACK= )); + return EFI_SUCCESS; + } + + NewStart =3D GetStartPointer (VarStore); + if (ByOffset) { + OutVarTrackPtr->CurrPtr =3D (VARIABLE_HEADER *) + ((UINTN)NewStart + ((UINTN)InVarTrackPtr->Cu= rrPtr - + (UINTN)InVarTrackPtr->St= artPtr)); + + if (InVarTrackPtr->InDeletedTransitionPtr !=3D NULL) { + OutVarTrackPtr->InDeletedTransitionPtr =3D + (VARIABLE_HEADER *)((UINTN)NewStart + + ((UINTN)InVarTrackPtr->InDeletedTransitionPtr - + (UINTN)InVarTrackPtr->StartPtr)); + } else { + OutVarTrackPtr->InDeletedTransitionPtr =3D NULL; + } + + OutVarTrackPtr->StartPtr =3D NewStart; + OutVarTrackPtr->EndPtr =3D GetEndPointer (VarStore); + } else { + OutVarTrackPtr->StartPtr =3D NewStart; + OutVarTrackPtr->EndPtr =3D GetEndPointer (VarStore); + + Status =3D FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrac= kPtr, AuthFormat); + if ((OutVarTrackPtr->CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } + + if ( (VarStore =3D=3D mNvVariableCache) + || ((UINTN)VarStore =3D=3D (UINTN)mVariableModuleGlobal->VariableGlob= al.NonVolatileVariableBase)) + { + OutVarTrackPtr->Volatile =3D 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 =3D (VARIABLE_STORE_HEADER *)(UINTN) + mVariableModuleGlobal->VariableGlobal.HobVariableBase; + return (CacheVariable->CurrPtr !=3D NULL && + HobVarStore !=3D NULL && + CacheVariable->StartPtr =3D=3D 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 st= ore + // as a temporary storage. + // + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + NewVariable =3D 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 storag= e. + @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 !=3D NULL) { + ASSERT (CacheVariable->InDeletedTransitionPtr !=3D NULL); + // + // Both ADDED and IN_DELETED_TRANSITION variable are present, + // set IN_DELETED_TRANSITION one to DELETED state first. + // + Status =3D UpdateVariableState ( + Variable->InDeletedTransitionPtr, + CacheVariable->InDeletedTransitionPtr, + CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED, + VolatileFlag + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + ASSERT (CacheVariable->CurrPtr !=3D NULL); + Status =3D 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 =3D=3D NULL) && + !mVariableModuleGlobal->VariableGlobal.EmuNvMode) + { + // + // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTO= COL + // is not installed. + // + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 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) !=3D 0) { + // + // Trying to update volatile authenticated variable prior to the + // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The authenticat= ed + // variable perhaps is not initialized, just return here. + // + DEBUG (( + DEBUG_ERROR, + "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL read= y - %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. =20 + @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 =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; + + if ((DataSize =3D=3D 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != =3D 0)) { + return EFI_ALREADY_STARTED; + } + + if (Variable->CurrPtr !=3D 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 R= untime. + // + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)= =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Only variable that have RT attributes can be updated/deleted in R= untime. + // + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCES= S) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Variable content unchanged and no need to update timestamp, just re= turn. + // + if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) + && (TimeStamp =3D=3D NULL) + && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) =3D=3D Da= taSize) + && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, A= uthFlag), DataSize) =3D=3D 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 =3D=3D 0) || + ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVI= CE_ACCESS)) =3D=3D 0)) + { + return EFI_NOT_FOUND; + } + + // + // Only variable have NV|RT attribute can be created in Runtime. + // + if ( AtRuntime () + && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) =3D=3D 0) + || ((Attributes & EFI_VARIABLE_NON_VOLATILE) =3D=3D 0))) + { + return EFI_INVALID_PARAMETER; + } + } + + return EFI_SUCCESS; +} + +/** + Update the variable region with Variable information. If EFI_VARIABLE_AU= THENTICATED_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 oth= er data into this region. =20 @@ -1687,710 +2140,381 @@ UpdateVariable ( IN EFI_TIME *TimeStamp OPTIONAL ) { - EFI_STATUS Status; - VARIABLE_HEADER *NextVariable; - UINTN ScratchSize; - UINTN MaxDataSize; - UINTN VarNameOffset; - UINTN VarDataOffset; - UINTN VarNameSize; - UINTN VarSize; - BOOLEAN Volatile; - EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; - UINT8 State; - VARIABLE_POINTER_TRACK *Variable; - VARIABLE_POINTER_TRACK NvVariable; - VARIABLE_STORE_HEADER *VariableStoreHeader; - VARIABLE_RUNTIME_CACHE *VolatileCacheInstance; - UINT8 *BufferForMerge; - UINTN MergedBufSize; - BOOLEAN DataReady; - UINTN DataOffset; - BOOLEAN IsCommonVariable; - BOOLEAN IsCommonUserVariable; - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - BOOLEAN AuthFormat; + EFI_STATUS Status; + VARIABLE_GLOBAL *VarGlobal; + VARIABLE_HEADER *NewVariable; + VARIABLE_HEADER *NextVariable; + VARIABLE_HEADER *UpdatingVariable; + UINTN VarSize; + UINTN UpdateSize; + UINTN Offset; + VARIABLE_POINTER_TRACK *Variable; + VARIABLE_POINTER_TRACK NvVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_RUNTIME_CACHE *VolatileCacheInstance; + BOOLEAN IsCommonVariable; + BOOLEAN IsCommonUserVariable; + BOOLEAN DeleteFlag; + BOOLEAN VolatileFlag; + BOOLEAN HobVarOnlyFlag; + EFI_PHYSICAL_ADDRESS VarStoreBase; + UINTN *LastVariableOffset; =20 - if ((mVariableModuleGlobal->FvbInstance =3D=3D NULL) && !mVariableModule= Global->VariableGlobal.EmuNvMode) { - // - // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTO= COL is not installed. - // - if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { - // - // Trying to update NV variable prior to the installation of EFI_VAR= IABLE_WRITE_ARCH_PROTOCOL - // - DEBUG ((DEBUG_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_A= RCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET)); - return EFI_NOT_AVAILABLE_YET; - } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { - // - // Trying to update volatile authenticated variable prior to the ins= tallation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL - // The authenticated variable perhaps is not initialized, just retur= n 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; } =20 - AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; + VarGlobal =3D &mVariableModuleGlobal->VariableGlobal; + + if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) && (DataSize = =3D=3D 0)) + || (Attributes =3D=3D 0) + || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS + |EFI_VARIABLE_BOOTSERVICE_ACCESS)= ) =3D=3D 0))) + { + DeleteFlag =3D TRUE; + } else { + DeleteFlag =3D FALSE; + } + + if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) + || ((CacheVariable->CurrPtr !=3D NULL) && + ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)= !=3D 0))) + { + VolatileFlag =3D FALSE; + } else { + VolatileFlag =3D TRUE; + } =20 // // 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 !=3D NULL) && - (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0) && - (CacheVariable->StartPtr =3D=3D GetStartPointer ((VARIABLE_STORE_HEA= DER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase)) - ) - { - CacheVariable->StartPtr =3D GetStartPointer (mNvVariableCache); - CacheVariable->EndPtr =3D GetEndPointer (mNvVariableCache); - CacheVariable->Volatile =3D FALSE; - Status =3D FindVariableEx (VariableName, VendorGuid, = FALSE, CacheVariable, AuthFormat); + HobVarOnlyFlag =3D FALSE; + if (IsHobVariable (CacheVariable)) { + Status =3D RebaseVariablePtr ( + CacheVariable, + CacheVariable, + mNvVariableCache, + VariableName, + VendorGuid, + FALSE + ); if ((CacheVariable->CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { // // There is no matched variable in NV variable cache. // - if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) && (DataSiz= e =3D=3D 0)) || (Attributes =3D=3D 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 =3D TRUE; + Status =3D EFI_SUCCESS; + goto Done; } } } =20 + // + // Determine the physical position of variable store to update, due to c= ache + // mechanims of variable service. + // if ((CacheVariable->CurrPtr =3D=3D NULL) || CacheVariable->Volatile) { + // + // - Add new variable (volatile or non-volatile); Or + // - Update/delete volatile variable in place. + // Variable =3D CacheVariable; } else { // - // Update/Delete existing NV variable. - // CacheVariable points to the variable in the memory copy of Flash ar= ea - // 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 =3D (VARIABLE_STORE_HEADER *)((UINTN)mVariableModu= leGlobal->VariableGlobal.NonVolatileVariableBase); - Variable =3D &NvVariable; - Variable->StartPtr =3D GetStartPointer (VariableStoreHeader); - Variable->EndPtr =3D (VARIABLE_HEADER *)((UINTN)Variable->StartPtr = + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr)); - - Variable->CurrPtr =3D (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + = ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr)); - if (CacheVariable->InDeletedTransitionPtr !=3D NULL) { - Variable->InDeletedTransitionPtr =3D (VARIABLE_HEADER *)((UINTN)Vari= able->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)Cac= heVariable->StartPtr)); - } else { - Variable->InDeletedTransitionPtr =3D NULL; - } - - Variable->Volatile =3D FALSE; + VariableStoreHeader =3D (VARIABLE_STORE_HEADER *)(UINTN) + VarGlobal->NonVolatileVariableBase; + Variable =3D &NvVariable; + Status =3D RebaseVariablePtr ( + CacheVariable, + Variable, + VariableStoreHeader, + VariableName, + VendorGuid, + TRUE + ); + ASSERT_EFI_ERROR (Status); } =20 - Fvb =3D mVariableModuleGlobal->FvbInstance; - // - // Tricky part: Use scratch data area at the end of volatile variable st= ore - // as a temporary storage. + // Validate variable parameters. // - NextVariable =3D GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariab= leModuleGlobal->VariableGlobal.VolatileVariableBase)); - ScratchSize =3D mVariableModuleGlobal->ScratchBufferSize; - SetMem (NextVariable, ScratchSize, 0xff); - DataReady =3D FALSE; - - if (Variable->CurrPtr !=3D 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 =3D EFI_WRITE_PROTECTED; - goto Done; - } - - // - // Only variable that have NV attributes can be updated/deleted in R= untime. - // - if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)= =3D=3D 0) { - Status =3D EFI_INVALID_PARAMETER; - goto Done; - } - - // - // Only variable that have RT attributes can be updated/deleted in R= untime. - // - if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCES= S) =3D=3D 0) { - Status =3D 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 ze= ro will - // not delete the variable. - // - if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) && (DataSize = =3D=3D 0)) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BO= OTSERVICE_ACCESS)) =3D=3D 0)) { - if (Variable->InDeletedTransitionPtr !=3D NULL) { - // - // Both ADDED and IN_DELETED_TRANSITION variable are present, - // set IN_DELETED_TRANSITION one to DELETED state first. - // - ASSERT (CacheVariable->InDeletedTransitionPtr !=3D NULL); - State =3D CacheVariable->InDeletedTransitionPtr->State; - State &=3D VAR_DELETED; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - Variable->Volatile, - FALSE, - Fvb, - (UINTN)&Variable->InDeletedTransitionPtr->State, - sizeof (UINT8), - &State - ); - if (!EFI_ERROR (Status)) { - if (!Variable->Volatile) { - CacheVariable->InDeletedTransitionPtr->State =3D State; - } - } else { - goto Done; - } - } - - State =3D CacheVariable->CurrPtr->State; - State &=3D VAR_DELETED; - - Status =3D 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 =3D State; - FlushHobVariableToFlash (VariableName, VendorGuid); - } - } + Status =3D ValidateVariableParameters ( + Variable, + CacheVariable, + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + KeyIndex, + MonotonicCount, + TimeStamp + ); + if (EFI_ERROR (Status)) { + goto Done; + } =20 - goto Done; - } + // + // Add or update a variable. Allocate a buffer to hold it temporarily. + // + NewVariable =3D GetNewVariableBuffer (); =20 + // + // Fill-up variable data first, if necessary. + // + IsCommonVariable =3D FALSE; + IsCommonUserVariable =3D 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) =3D=3D Da= taSize) && - (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, Aut= hFormat), DataSize) =3D=3D 0) && - ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) && - (TimeStamp =3D=3D NULL)) - { - // - // Variable content unchanged and no need to update timestamp, just = return. - // - UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FA= LSE, TRUE, FALSE, FALSE, &gVariableInfo); - Status =3D EFI_SUCCESS; - goto Done; - } else if ((CacheVariable->CurrPtr->State =3D=3D VAR_ADDED) || - (CacheVariable->CurrPtr->State =3D=3D (VAR_ADDED & VAR_IN_D= ELETED_TRANSITION))) - { - // - // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing var= iable. - // - if ((Attributes & EFI_VARIABLE_APPEND_WRITE) !=3D 0) { - // - // NOTE: From 0 to DataOffset of NextVariable is reserved for Vari= able Header and Name. - // From DataOffset of NextVariable is to save the existing variabl= e data. - // - DataOffset =3D GetVariableDataOffset (CacheVariable->CurrPtr, = AuthFormat); - BufferForMerge =3D (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 defaul= t MaxDataSize. - // - if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { - MaxDataSize =3D mVariableModuleGlobal->MaxAuthVariableSize - Dat= aOffset; - } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { - MaxDataSize =3D mVariableModuleGlobal->MaxVariableSize - DataOff= set; - } else { - MaxDataSize =3D mVariableModuleGlobal->MaxVolatileVariableSize -= DataOffset; - } - - // - // Append the new data to the end of existing data. - // Max Harware error record variable data size is different from c= ommon/auth variable. - // - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D EFI_V= ARIABLE_HARDWARE_ERROR_RECORD) { - MaxDataSize =3D PcdGet32 (PcdMaxHardwareErrorVariableSize) - Dat= aOffset; - } - - if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + Data= Size > MaxDataSize) { - // - // Existing data size + new data size exceed maximum variable si= ze limitation. - // - Status =3D EFI_INVALID_PARAMETER; - goto Done; - } - - CopyMem ( - (UINT8 *)( - (UINTN)BufferForMerge + DataSizeOfVariable (CacheVaria= ble->CurrPtr, AuthFormat) - ), - Data, - DataSize - ); - MergedBufSize =3D DataSizeOfVariable (CacheVariable->CurrPtr, Auth= Format) + - DataSize; - - // - // BufferForMerge(from DataOffset of NextVariable) has included th= e merged existing and new data. - // - Data =3D BufferForMerge; - DataSize =3D MergedBufSize; - DataReady =3D TRUE; - } - - // - // Mark the old variable as in delete transition. - // - State =3D CacheVariable->CurrPtr->State; - State &=3D VAR_IN_DELETED_TRANSITION; - - Status =3D 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 =3D State; - } - } + VarSize =3D 0; } else { - // - // Not found existing variable. Create a new variable. - // + VarSize =3D SetVariableData ( + NewVariable, + CacheVariable->CurrPtr, + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + KeyIndex, + MonotonicCount, + TimeStamp + ); =20 - if ((DataSize =3D=3D 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != =3D 0)) { - Status =3D 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 =3D=3D 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS= | EFI_VARIABLE_BOOTSERVICE_ACCESS)) =3D=3D 0)) { - Status =3D EFI_NOT_FOUND; - goto Done; - } - - // - // Only variable have NV|RT attribute can be created in Runtime. - // - if (AtRuntime () && - (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) =3D=3D 0) || ((Attrib= utes & EFI_VARIABLE_NON_VOLATILE) =3D=3D 0))) - { - Status =3D 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 =3D VARIABLE_DATA; - // - // NextVariable->State =3D VAR_ADDED; - // - NextVariable->Reserved =3D 0; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Next= Variable; - AuthVariable->PubKeyIndex =3D KeyIndex; - AuthVariable->MonotonicCount =3D MonotonicCount; - ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME)); - - if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)= !=3D 0) && - (TimeStamp !=3D NULL)) - { - if ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 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 timestam= p associated - // with the variable, we need associate the new timestamp with the= updated value. - // - if (Variable->CurrPtr !=3D 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 retu= rned - // Attributes bitmask parameter of a GetVariable() call. - // - NextVariable->Attributes =3D Attributes & (~EFI_VARIABLE_APPEND_WRITE); - - VarNameOffset =3D GetVariableHeaderSize (AuthFormat); - VarNameSize =3D StrSize (VariableName); - CopyMem ( - (UINT8 *)((UINTN)NextVariable + VarNameOffset), - VariableName, - VarNameSize - ); - VarDataOffset =3D VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSiz= e); - - // - // 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 =3D VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); - if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { - // - // Create a nonvolatile variable. - // - Volatile =3D FALSE; - - IsCommonVariable =3D FALSE; - IsCommonUserVariable =3D FALSE; if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0) { IsCommonVariable =3D TRUE; - IsCommonUserVariable =3D IsUserVariable (NextVariable); + IsCommonUserVariable =3D IsUserVariable (NewVariable); } + } =20 - if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) - && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > = PcdGet32 (PcdHwErrStorageSize))) - || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVa= riableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) - || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModule= Global->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVari= ableSpace)) - || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->Comm= onUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpac= e))) - { - if (AtRuntime ()) { - if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->Com= monUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpa= ce)) { - RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, Ven= dorGuid, Attributes, VarSize); - } - - if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonV= ariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) { - RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, V= endorGuid, Attributes, VarSize); - } - - Status =3D EFI_OUT_OF_RESOURCES; - goto Done; - } - - // - // Perform garbage collection & reclaim operation, and integrate the= new variable at the same time. - // - Status =3D Reclaim ( - mVariableModuleGlobal->VariableGlobal.NonVolatileVariable= Base, - &mVariableModuleGlobal->NonVolatileLastVariableOffset, - FALSE, - Variable, - NextVariable, - HEADER_ALIGN (VarSize) - ); - if (!EFI_ERROR (Status)) { - // - // The new variable has been integrated successfully during reclai= ming. - // - if (Variable->CurrPtr !=3D NULL) { - CacheVariable->CurrPtr =3D (VARIABLE_HEADER *)((U= INTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable-= >StartPtr)); - CacheVariable->InDeletedTransitionPtr =3D NULL; - } - - UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, = FALSE, FALSE, &gVariableInfo); - FlushHobVariableToFlash (VariableName, VendorGuid); - } else { - if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->Com= monUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpa= ce)) { - RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, Ven= dorGuid, Attributes, VarSize); - } + // + // We might need to do protection for non-volatile variable before flush= ing + // the data to storage. A null version (meaning no protection) of follow= ing + // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any + // changes to original data. + // + if (!VolatileFlag) { + Status =3D ProtectedVariableLibUpdate ( + Variable->CurrPtr, + Variable->InDeletedTransitionPtr, + NewVariable, + &VarSize + ); + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { + return Status; + } =20 - if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonV= ariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) { - RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, V= endorGuid, Attributes, VarSize); - } - } + Status =3D EFI_SUCCESS; + } =20 + // + // 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 !=3D NULL) + && ( (CacheVariable->CurrPtr->State =3D=3D VAR_ADDED) + || (CacheVariable->CurrPtr->State =3D=3D (VAR_ADDED & VAR_IN_DELET= ED_TRANSITION)))) + { + Status =3D 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 =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset, - (UINT32)GetVariableHeaderSize (AuthFormat), - (UINT8 *)NextVariable - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - - // - // Step 2: - // - NextVariable->State =3D VAR_HEADER_VALID_ONLY; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariab= leOffset + OFFSET_OF (VARIABLE_HEADER, State), - sizeof (UINT8), - &NextVariable->State - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - - // - // Step 3: - // - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + Ge= tVariableHeaderSize (AuthFormat), - (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)), - (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat) + } + + // + // Have enough space to store the variable? + // + Status =3D CheckVariableStoreSpace ( + NewVariable, + VarSize, + VariableName, + VendorGuid, + Attributes, + VolatileFlag + ); + if (Status =3D=3D EFI_OUT_OF_RESOURCES) { + // + // Not a chance. + // + goto Done; + } + + // + // Maybe not... + // + VarStoreBase =3D (VolatileFlag) ? VarGlobal->VolatileVariableBase + : VarGlobal->NonVolatileVariableBase; + LastVariableOffset =3D (VolatileFlag) + ? &mVariableModuleGlobal->VolatileLastVariableOffs= et + : &mVariableModuleGlobal->NonVolatileLastVariableO= ffset; + if (!EFI_ERROR (Status)) { + // + // There's enough free space at the tail of variable storage. + // + + // + // If non-volatile variable is protected, a separate variable (MetaDat= aHmacVar) + // is always updated along with current updating variable. The buffer = pointed + // by NewVariable must have two variables. They should be written at t= his + // time orderly. + // + NextVariable =3D NewVariable; + UpdatingVariable =3D NULL; + UpdateSize =3D 0; + while ( !EFI_ERROR (Status) + && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize) + { + UpdatingVariable =3D NextVariable; + NextVariable =3D GetNextVariablePtr (UpdatingVariable, VarGlobal= ->AuthFormat); + UpdateSize =3D (UINTN)NextVariable - (UINTN)UpdatingVariable; + + Status =3D WriteVariable ( + VarStoreBase, + LastVariableOffset, + &UpdatingVariable, + (UINT32)UpdateSize, + VolatileFlag, + VarGlobal->AuthFormat ); - - if (EFI_ERROR (Status)) { - goto Done; - } - - // - // Step 4: - // - NextVariable->State =3D VAR_ADDED; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariab= leOffset + 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->NonVolat= ileLastVariableOffset, (UINT8 *)NextVariable, VarSize); - } else { - // - // Emulated non-volatile variable mode. - // - NextVariable->State =3D VAR_ADDED; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariab= leOffset, - (UINT32)VarSize, - (UINT8 *)NextVariable - ); - - if (EFI_ERROR (Status)) { - goto Done; - } } =20 - mVariableModuleGlobal->NonVolatileLastVariableOffset +=3D HEADER_ALIGN= (VarSize); - + // + // UpdatingVariable must point to the last written variable. Restore i= t to + // the first one so that we can calculate the offset in variable stora= ge. + // + UpdatingVariable =3D (VARIABLE_HEADER *)((UINTN)UpdatingVariable + Upd= ateSize + - VarSize); if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) { - mVariableModuleGlobal->HwErrVariableTotalSize +=3D HEADER_ALIGN (Var= Size); + mVariableModuleGlobal->HwErrVariableTotalSize +=3D VarSize; } else { - mVariableModuleGlobal->CommonVariableTotalSize +=3D HEADER_ALIGN (Va= rSize); + mVariableModuleGlobal->CommonVariableTotalSize +=3D VarSize; if (IsCommonUserVariable) { - mVariableModuleGlobal->CommonUserVariableTotalSize +=3D HEADER_ALI= GN (VarSize); + mVariableModuleGlobal->CommonUserVariableTotalSize +=3D VarSize; } } - } else { - // - // Create a volatile variable. - // - Volatile =3D TRUE; =20 - if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffs= et) > - ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal->Variable= Global.VolatileVariableBase)))->Size) - { - // - // Perform garbage collection & reclaim operation, and integrate the= new variable at the same time. - // - Status =3D Reclaim ( - mVariableModuleGlobal->VariableGlobal.VolatileVariableBas= e, - &mVariableModuleGlobal->VolatileLastVariableOffset, - TRUE, + // + // Mark the old variable(s) as deleted. + // + if (!EFI_ERROR (Status) && (Variable->CurrPtr !=3D NULL)) { + Status =3D DeleteVariable ( + VariableName, + VendorGuid, Variable, - NextVariable, - HEADER_ALIGN (VarSize) + CacheVariable, + VolatileFlag ); - if (!EFI_ERROR (Status)) { - // - // The new variable has been integrated successfully during reclai= ming. - // - if (Variable->CurrPtr !=3D NULL) { - CacheVariable->CurrPtr =3D (VARIABLE_HEADER *)((U= INTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable-= >StartPtr)); - CacheVariable->InDeletedTransitionPtr =3D NULL; - } - - UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, F= ALSE, FALSE, &gVariableInfo); - } - - goto Done; } - - NextVariable->State =3D VAR_ADDED; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - TRUE, - TRUE, - Fvb, - mVariableModuleGlobal->VolatileLastVariableOff= set, - (UINT32)VarSize, - (UINT8 *)NextVariable - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - - mVariableModuleGlobal->VolatileLastVariableOffset +=3D HEADER_ALIGN (V= arSize); - } - - // - // Mark the old variable as deleted. - // - if (!EFI_ERROR (Status) && (Variable->CurrPtr !=3D NULL)) { - if (Variable->InDeletedTransitionPtr !=3D NULL) { - // - // Both ADDED and IN_DELETED_TRANSITION old variable are present, - // set IN_DELETED_TRANSITION one to DELETED state first. - // - ASSERT (CacheVariable->InDeletedTransitionPtr !=3D NULL); - State =3D CacheVariable->InDeletedTransitionPtr->State; - State &=3D VAR_DELETED; - Status =3D UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - Variable->Volatile, - FALSE, - Fvb, - (UINTN)&Variable->InDeletedTransitionPtr->State, - sizeof (UINT8), - &State - ); - if (!EFI_ERROR (Status)) { - if (!Variable->Volatile) { - CacheVariable->InDeletedTransitionPtr->State =3D State; - } - } else { - goto Done; - } - } - - State =3D CacheVariable->CurrPtr->State; - State &=3D VAR_DELETED; - - Status =3D 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 colle= ction + // & reclaim operation, and integrate the new variable at the same tim= e. + // + Status =3D Reclaim ( + VarStoreBase, + LastVariableOffset, + VolatileFlag, + Variable, + NewVariable, + VarSize ); - if (!EFI_ERROR (Status) && !Variable->Volatile) { - CacheVariable->CurrPtr->State =3D State; - } - } + UpdatingVariable =3D Variable->CurrPtr; =20 - if (!EFI_ERROR (Status)) { - UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, F= ALSE, FALSE, &gVariableInfo); - if (!Volatile) { - FlushHobVariableToFlash (VariableName, VendorGuid); + if (EFI_ERROR (Status) && + ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0)) + { + // + // Out of space. + // + IsCommonUserVariable =3D IsUserVariable (NewVariable); + IsCommonVariable =3D 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 + ); + } } } =20 Done: if (!EFI_ERROR (Status)) { - if (((Variable->CurrPtr !=3D NULL) && !Variable->Volatile) || ((Attrib= utes & EFI_VARIABLE_NON_VOLATILE) !=3D 0)) { - VolatileCacheInstance =3D &(mVariableModuleGlobal->VariableGlobal.Va= riableRuntimeCacheContext.VariableRuntimeNvCache); + if (!VolatileFlag) { + Offset =3D (UpdatingVariable !=3D NULL) ? (UINTN)UpdatingVariable - = (UINTN)VarStoreBase + : 0; + Status =3D ProtectedVariableLibWriteFinal ( + NewVariable, + VarSize, + Offset + ); + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { + return Status; + } + + Status =3D EFI_SUCCESS; + } + + UpdateVariableInfo ( + VariableName, + VendorGuid, + VolatileFlag, + FALSE, + TRUE, + FALSE, + FALSE, + &gVariableInfo + ); + // + // HOB copy of the same variable is no longer needed, no matter it has + // been deleted, updated or added from/to real variable storage. + // + if (HobVarOnlyFlag || !VolatileFlag) { + FlushHobVariableToFlash (VariableName, VendorGuid); + } + + if (!VolatileFlag) { + VolatileCacheInstance =3D &(VarGlobal->VariableRuntimeCacheContext.V= ariableRuntimeNvCache); } else { - VolatileCacheInstance =3D &(mVariableModuleGlobal->VariableGlobal.Va= riableRuntimeCacheContext.VariableRuntimeVolatileCache); + VolatileCacheInstance =3D &(VarGlobal->VariableRuntimeCacheContext.V= ariableRuntimeVolatileCache); } =20 if (VolatileCacheInstance->Store !=3D NULL) { @@ -2401,6 +2525,11 @@ Done: ); ASSERT_EFI_ERROR (Status); } + } else if (Status =3D=3D EFI_ALREADY_STARTED) { + // + // Meaning nothing needs to be done. Just return success. + // + Status =3D EFI_SUCCESS; } =20 return Status; @@ -2440,7 +2569,6 @@ VariableServiceGetVariable ( { EFI_STATUS Status; VARIABLE_POINTER_TRACK Variable; - UINTN VarDataSize; =20 if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (DataSize = =3D=3D NULL)) { return EFI_INVALID_PARAMETER; @@ -2458,28 +2586,26 @@ VariableServiceGetVariable ( } =20 // - // Get data size + // Get data and its size // - VarDataSize =3D DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlo= bal->VariableGlobal.AuthFormat); - ASSERT (VarDataSize !=3D 0); + if (!Variable.Volatile) { + // + // Currently only non-volatile variable needs protection. + // + Status =3D ProtectedVariableLibGetByBuffer ( + Variable.CurrPtr, + Data, + (UINT32 *)DataSize, + mVariableModuleGlobal->VariableGlobal.AuthFormat + ); + } =20 - if (*DataSize >=3D VarDataSize) { - if (Data =3D=3D NULL) { - Status =3D EFI_INVALID_PARAMETER; - goto Done; - } + if (Variable.Volatile || (Status =3D=3D EFI_UNSUPPORTED)) { + Status =3D GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize= , mVariableModuleGlobal->VariableGlobal.AuthFormat); + } =20 - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGl= obal->VariableGlobal.AuthFormat), VarDataSize); - - *DataSize =3D VarDataSize; + if (!EFI_ERROR (Status)) { UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE,= FALSE, FALSE, FALSE, &gVariableInfo); - - Status =3D EFI_SUCCESS; - goto Done; - } else { - *DataSize =3D VarDataSize; - Status =3D EFI_BUFFER_TOO_SMALL; - goto Done; } =20 Done: @@ -2860,7 +2986,7 @@ VariableServiceSetVariable ( // Parse non-volatile variable data and get last variable offset. // NextVariable =3D GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Poin= t); - while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_S= TORE_HEADER *)(UINTN)Point))) { + while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_S= TORE_HEADER *)(UINTN)Point), AuthFormat)) { NextVariable =3D GetNextVariablePtr (NextVariable, AuthFormat); } =20 @@ -3022,7 +3148,12 @@ VariableServiceQueryVariableInfoInternal ( // // Now walk through the related variable store. // - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHead= er))) { + while (IsValidVariableHeader ( + Variable, + GetEndPointer (VariableStoreHeader), + mVariableModuleGlobal->VariableGlobal.AuthFormat + )) + { NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlobal->= VariableGlobal.AuthFormat); VariableSize =3D (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable; =20 @@ -3315,7 +3446,7 @@ FlushHobVariableToFlash ( // mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D 0; for ( Variable =3D GetStartPointer (VariableStoreHeader) - ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreH= eader)) + ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreH= eader), AuthFormat) ; Variable =3D GetNextVariablePtr (Variable, AuthFormat) ) { @@ -3525,11 +3656,11 @@ ConvertNormalVarStorageToAuthVarStorage ( VARIABLE_HEADER *StartPtr; UINT8 *NextPtr; VARIABLE_HEADER *EndPtr; - UINTN AuthVarStroageSize; + UINTN AuthVarStorageSize; AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr; VARIABLE_STORE_HEADER *AuthVarStorage; =20 - AuthVarStroageSize =3D sizeof (VARIABLE_STORE_HEADER); + AuthVarStorageSize =3D sizeof (VARIABLE_STORE_HEADER); // // Set AuthFormat as FALSE for normal variable storage // @@ -3542,10 +3673,10 @@ ConvertNormalVarStorageToAuthVarStorage ( EndPtr =3D GetEndPointer (NormalVarStorage); while (StartPtr < EndPtr) { if (StartPtr->State =3D=3D VAR_ADDED) { - AuthVarStroageSize =3D HEADER_ALIGN (AuthVarStroageSize); - AuthVarStroageSize +=3D sizeof (AUTHENTICATED_VARIABLE_HEADER); - AuthVarStroageSize +=3D StartPtr->NameSize + GET_PAD_SIZE (StartPtr-= >NameSize); - AuthVarStroageSize +=3D StartPtr->DataSize + GET_PAD_SIZE (StartPtr-= >DataSize); + AuthVarStorageSize =3D HEADER_ALIGN (AuthVarStorageSize); + AuthVarStorageSize +=3D sizeof (AUTHENTICATED_VARIABLE_HEADER); + AuthVarStorageSize +=3D StartPtr->NameSize + GET_PAD_SIZE (StartPtr-= >NameSize); + AuthVarStorageSize +=3D StartPtr->DataSize + GET_PAD_SIZE (StartPtr-= >DataSize); } =20 StartPtr =3D GetNextVariablePtr (StartPtr, mVariableModuleGlobal->Vari= ableGlobal.AuthFormat); @@ -3554,7 +3685,7 @@ ConvertNormalVarStorageToAuthVarStorage ( // // Allocate Runtime memory for Auth Variable Storage // - AuthVarStorage =3D AllocateRuntimeZeroPool (AuthVarStroageSize); + AuthVarStorage =3D AllocateRuntimeZeroPool (AuthVarStorageSize); ASSERT (AuthVarStorage !=3D NULL); if (AuthVarStorage =3D=3D NULL) { return NULL; @@ -3608,7 +3739,7 @@ ConvertNormalVarStorageToAuthVarStorage ( AuthVarStorage->State =3D NormalVarStorage->State; AuthVarStorage->Size =3D (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVar= Storage); CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid); - ASSERT (AuthVarStorage->Size <=3D AuthVarStroageSize); + ASSERT (AuthVarStorage->Size <=3D AuthVarStorageSize); =20 // // Restore AuthFormat @@ -3774,7 +3905,7 @@ VariableCommonInitialize ( // // Allocate memory for volatile variable store, note that there is a scr= atch space to store scratch data. // - ScratchSize =3D GetMaxVariableSize (); + ScratchSize =3D GetMaxVariableSize () * 2; mVariableModuleGlobal->ScratchBufferSize =3D ScratchSize; VolatileVariableStore =3D AllocateRuntimePool (PcdGet= 32 (PcdVariableStoreSize) + ScratchSize); if (VolatileVariableStore =3D=3D NULL) { diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/Mde= ModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c index 03fec3048dc4..52bf29ec4c5c 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c @@ -3,7 +3,7 @@ and volatile storage space and install variable architecture protocol. =20 Copyright (C) 2013, Red Hat, Inc. -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
(C) Copyright 2015 Hewlett Packard Enterprise Development LP
Copyright (c) Microsoft Corporation. SPDX-License-Identifier: BSD-2-Clause-Patent @@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent =20 #include #include +#include "VariableParsing.h" =20 EFI_STATUS EFIAPI @@ -534,6 +535,29 @@ VariableServiceInitialize ( EFI_EVENT ReadyToBootEvent; EFI_EVENT EndOfDxeEvent; =20 + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; + + // + // Initialze protected variable service, if enabled. + // + ContextIn.StructSize =3D sizeof (ContextIn); + ContextIn.StructVersion =3D PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; + + ContextIn.FindVariableSmm =3D NULL; + ContextIn.GetVariableInfo =3D GetVariableInfo; + ContextIn.GetNextVariableInfo =3D GetNextVariableInfo; + ContextIn.UpdateVariableStore =3D VariableExLibUpdateNvVariable; + ContextIn.UpdateVariable =3D VariableExLibUpdateVariable; + + ContextIn.MaxVariableSize =3D (UINT32)GetMaxVariableSize (); + ContextIn.VariableServiceUser =3D FromSmmModule; + + Status =3D ProtectedVariableLibInitialize (&ContextIn); + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + Status =3D VariableCommonInitialize (); ASSERT_EFI_ERROR (Status); =20 diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/M= deModulePkg/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. =20 -Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ =20 #include "Variable.h" #include "VariableParsing.h" +#include "VariableRuntimeCache.h" =20 /** Finds variable in storage blocks of volatile and non-volatile storage ar= eas. @@ -38,6 +39,7 @@ VariableExLibFindVariable ( EFI_STATUS Status; VARIABLE_POINTER_TRACK Variable; AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + PROTECTED_VARIABLE_INFO VarInfo; =20 Status =3D FindVariable ( VariableName, @@ -56,9 +58,12 @@ VariableExLibFindVariable ( return Status; } =20 - AuthVariableInfo->DataSize =3D DataSizeOfVariable (Variable.CurrPtr, m= VariableModuleGlobal->VariableGlobal.AuthFormat); - AuthVariableInfo->Data =3D GetVariableDataPtr (Variable.CurrPtr, m= VariableModuleGlobal->VariableGlobal.AuthFormat); - AuthVariableInfo->Attributes =3D Variable.CurrPtr->Attributes; + AuthVariableInfo->NameSize =3D NameSizeOfVariable (Variable.CurrPtr,= mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->VariableName =3D GetVariableNamePtr (Variable.CurrPtr,= mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->VendorGuid =3D GetVendorGuidPtr (Variable.CurrPtr, m= VariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->DataSize =3D DataSizeOfVariable (Variable.CurrPtr,= mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->Data =3D GetVariableDataPtr (Variable.CurrPtr,= mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->Attributes =3D Variable.CurrPtr->Attributes; if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)= Variable.CurrPtr; AuthVariableInfo->PubKeyIndex =3D AuthVariable->PubKeyIndex; @@ -66,6 +71,24 @@ VariableExLibFindVariable ( AuthVariableInfo->TimeStamp =3D &AuthVariable->TimeStamp; } =20 + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header)); + + VarInfo.Buffer =3D Variable.CurrPtr; + VarInfo.PlainData =3D NULL; + VarInfo.PlainDataSize =3D 0; + VarInfo.Flags.Auth =3D mVariableModuleGlobal->VariableGlobal.AuthForm= at; + + // + // In case the variable is encrypted. + // + Status =3D ProtectedVariableLibGetByInfo (&VarInfo); + if (!EFI_ERROR (Status)) { + if (VarInfo.PlainData !=3D NULL) { + AuthVariableInfo->Data =3D VarInfo.PlainData; + AuthVariableInfo->DataSize =3D VarInfo.PlainDataSize; + } + } + return EFI_SUCCESS; } =20 @@ -99,6 +122,7 @@ VariableExLibFindNextVariable ( VARIABLE_HEADER *VariablePtr; AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr; VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax= ]; + PROTECTED_VARIABLE_INFO VarInfo; =20 VariableStoreHeader[VariableStoreTypeVolatile] =3D (VARIABLE_STORE_HEADE= R *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; VariableStoreHeader[VariableStoreTypeHob] =3D (VARIABLE_STORE_HEADE= R *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; @@ -123,6 +147,7 @@ VariableExLibFindNextVariable ( return Status; } =20 + AuthVariableInfo->NameSize =3D NameSizeOfVariable (VariablePtr, mVar= iableModuleGlobal->VariableGlobal.AuthFormat); AuthVariableInfo->VariableName =3D GetVariableNamePtr (VariablePtr, mVar= iableModuleGlobal->VariableGlobal.AuthFormat); AuthVariableInfo->VendorGuid =3D GetVendorGuidPtr (VariablePtr, mVaria= bleModuleGlobal->VariableGlobal.AuthFormat); AuthVariableInfo->DataSize =3D DataSizeOfVariable (VariablePtr, mVar= iableModuleGlobal->VariableGlobal.AuthFormat); @@ -135,6 +160,20 @@ VariableExLibFindNextVariable ( AuthVariableInfo->TimeStamp =3D &AuthVariablePtr->TimeStamp; } =20 + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header)); + + VarInfo.Buffer =3D VariablePtr; + VarInfo.PlainData =3D NULL; + VarInfo.PlainDataSize =3D 0; + + Status =3D ProtectedVariableLibGetByInfo (&VarInfo); + if (!EFI_ERROR (Status)) { + if (VarInfo.PlainData !=3D NULL) { + AuthVariableInfo->Data =3D VarInfo.PlainData; + AuthVariableInfo->DataSize =3D VarInfo.PlainDataSize; + } + } + return EFI_SUCCESS; } =20 @@ -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 informatio= n. + @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 successful= ly. + @retval EFI_UNSUPPORTED If this function is called directly in r= untime. + @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 =3D=3D NULL) || (mNvVariableCache =3D=3D NULL= )) { + return EFI_UNSUPPORTED; + } + + // + // Flush the cache to store. + // + if (Size =3D=3D (UINT32)-1) { + Status =3D FtwVariableSpace ( + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBa= se, + mNvVariableCache + ); + if ( !EFI_ERROR (Status) + && (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0)) + { + FlushHobVariableToFlash (NULL, NULL); + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0) { + FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.Hob= VariableBase); + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D 0; + } + } + + return Status; + } + + if ( (VariableInfo =3D=3D NULL) + || (VariableInfo->StoreIndex =3D=3D VAR_INDEX_INVALID) + || (Buffer =3D=3D NULL) + || (Size =3D=3D 0)) + { + ASSERT (VariableInfo !=3D NULL); + ASSERT (VariableInfo->StoreIndex !=3D VAR_INDEX_INVALID); + ASSERT (Buffer !=3D NULL); + ASSERT (Size !=3D 0); + return EFI_INVALID_PARAMETER; + } + + Global =3D &mVariableModuleGlobal->VariableGlobal; + + VariableCache =3D (VARIABLE_HEADER *)((UINTN)mNvVariableCache + (UINTN)V= ariableInfo->StoreIndex); + + ASSERT ( + StrCmp ( + VariableInfo->Header.VariableName, + GetVariableNamePtr (VariableCache, Global->AuthFormat) + ) =3D=3D 0 + ); + ASSERT ( + CompareGuid ( + VariableInfo->Header.VendorGuid, + GetVendorGuidPtr (VariableCache, Global->AuthFormat) + ) + ); + + // + // Forcibly update part data of flash copy of the variable ... + // + Status =3D UpdateVariableStore ( + Global, + FALSE, + FALSE, + mVariableModuleGlobal->FvbInstance, + (UINTN)(Global->NonVolatileVariableBase + VariableInfo->Stor= eIndex + 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 =3D &Global->VariableRuntimeCacheContext.VariableRuntimeNv= Cache; + if (CacheInstance->Store !=3D NULL) { + Status =3D SynchronizeRuntimeVariableCache ( + CacheInstance, + (UINTN)VariableInfo->StoreIndex + Offset, + Size + ); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile= .c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c index 5e9d40b67ac2..e8b8f0b7f705 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c @@ -1,7 +1,7 @@ /** @file Common variable non-volatile store routines. =20 -Copyright (c) 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ @@ -120,6 +120,181 @@ InitEmuNonVolatileVariableStore ( return EFI_SUCCESS; } =20 +/** + + Create a dummy variable used to fill the gap in NV variable storage caus= ed 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 !=3D NULL); + + if (Name =3D=3D NULL) { + Name =3D L"Dummy"; + } + + if (AuthFlag) { + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; + + AuthVariable->StartId =3D VARIABLE_DATA; + AuthVariable->State =3D VAR_ADDED & VAR_DELETED; + AuthVariable->Attributes =3D EFI_VARIABLE_NON_VOLATILE; + AuthVariable->NameSize =3D (UINT32)StrSize (Name); + AuthVariable->DataSize =3D Size - sizeof (AUTHENTICATED_VARIABLE_HEA= DER) + - AuthVariable->NameSize; + if (Guid !=3D NULL) { + CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof (EF= I_GUID)); + } + + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, AuthVa= riable->NameSize); + } else { + Variable->StartId =3D VARIABLE_DATA; + Variable->State =3D VAR_ADDED & VAR_DELETED; + Variable->Attributes =3D EFI_VARIABLE_NON_VOLATILE; + Variable->NameSize =3D (UINT32)StrSize (Name); + Variable->DataSize =3D Size - sizeof (VARIABLE_HEADER) - Variable->N= ameSize; + if (Guid !=3D NULL) { + CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof (EFI_GU= ID)); + } + + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, Variab= le->NameSize); + } +} + +/** + + Init protected variable store. + + @param[in, out] VariableStore Pointer to real protected variable store= base. + +**/ +EFI_STATUS +InitProtectedVariableStore ( + IN OUT VARIABLE_STORE_HEADER *VariableStore + ) +{ + EFI_STATUS Status; + PROTECTED_VARIABLE_INFO VarInfo; + UINTN Size; + UINTN Index; + BOOLEAN AuthFlag; + EFI_PHYSICAL_ADDRESS NextVariableStore; + EFI_PHYSICAL_ADDRESS *VarList; + UINTN NumVars; + UINTN CurrVar; + + SetMem ( + (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER), + VariableStore->Size - sizeof (VARIABLE_STORE_HEADER), + 0xFF + ); + Index =3D sizeof (VARIABLE_STORE_HEADER); + + VarList =3D NULL; + NumVars =3D 0; + ProtectedVariableLibGetSortedList (&VarList, &NumVars); + + // + // Search variable in the order of StoreIndex + // + ZeroMem (&VarInfo, sizeof (VarInfo)); + + for (CurrVar =3D 0; CurrVar < NumVars; CurrVar++) { + VarInfo.Buffer =3D NULL; + VarInfo.StoreIndex =3D VarList[CurrVar]; + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { + break; + } + + Status =3D ProtectedVariableLibFind (&VarInfo); + if (EFI_ERROR (Status)) { + break; + } + + ASSERT (VarInfo.Buffer !=3D NULL); + + AuthFlag =3D VarInfo.Flags.Auth; + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { + continue; + } else { + ASSERT (VarInfo.StoreIndex =3D=3D HEADER_ALIGN (VarInfo.StoreIndex)); + ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof (VARIABLE= _STORE_HEADER))); + ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHead= erSize (AuthFlag)); + } + + // + // Fill gap caused by invalid variable. + // + if (VarInfo.StoreIndex > Index) { + Size =3D (UINTN)VarInfo.StoreIndex - Index; + CreateDummyVariable ( + (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index), + NULL, + NULL, + (UINT32)Size, + AuthFlag + ); + Index +=3D Size; + } + + Size =3D (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag) + - (UINTN)VarInfo.Buffer; + CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer, = Size); + + Index +=3D Size; + Index =3D HEADER_ALIGN (Index); + + NextVariableStore =3D (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore + Va= rInfo.StoreIndex + Size); + } + + // + // Search variable in the order of StoreIndex + // + ZeroMem (&VarInfo, sizeof (VarInfo)); + for ( ; CurrVar < NumVars; CurrVar++) { + VarInfo.Buffer =3D NULL; + VarInfo.StoreIndex =3D VarList[CurrVar]; + Status =3D ProtectedVariableLibFind (&VarInfo); + if (EFI_ERROR (Status)) { + break; + } + + ASSERT (VarInfo.Buffer !=3D NULL); + + AuthFlag =3D VarInfo.Flags.Auth; + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { + Size =3D (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag) + - (UINTN)VarInfo.Buffer; + CopyMem ((UINT8 *)&NextVariableStore, VarInfo.Buffer, Size); + Status =3D ProtectedVariableLibRefresh (VarInfo.Buffer, 0= , NextVariableStore - (UINTN)VariableStore, FALSE); + NextVariableStore =3D NextVariableStore + Size; + } + } + + if (Status =3D=3D EFI_UNSUPPORTED) { + return Status; + } + + return EFI_SUCCESS; +} + /** Init real non-volatile variable store. =20 @@ -230,6 +405,16 @@ InitRealNonVolatileVariableStore ( return EFI_VOLUME_CORRUPTED; } =20 + // + // Overwrite the store with verified copy of protected variables, if ena= bled. + // + Status =3D InitProtectedVariableStore (VariableStore); + if ((Status !=3D EFI_SUCCESS) && (Status !=3D EFI_UNSUPPORTED)) { + FreePool (NvStorageData); + DEBUG ((DEBUG_ERROR, "Variable integrity might have been compromised\n= ")); + return Status; + } + mNvFvHeaderCache =3D FvHeader; =20 *VariableStoreBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore; @@ -323,7 +508,12 @@ InitNonVolatileVariableStore ( // Parse non-volatile variable data and get last variable offset. // Variable =3D GetStartPointer (mNvVariableCache); - while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache)= )) { + while (IsValidVariableHeader ( + Variable, + GetEndPointer (mNvVariableCache), + mVariableModuleGlobal->VariableGlobal.AuthFormat + )) + { NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlobal->= VariableGlobal.AuthFormat); VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_= HARDWARE_ERROR_RECORD)) =3D=3D (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HA= RDWARE_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. =20 -Copyright (c) 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ =20 +#include "Variable.h" #include "VariableParsing.h" =20 /** @@ -15,6 +16,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent =20 @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 ar= e not used. =20 @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 =3D=3D NULL) || (Variable >=3D VariableStoreEnd) || (Varia= ble->StartId !=3D VARIABLE_DATA)) { + if ( (Variable =3D=3D NULL) + || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >=3D (UINT= N)VariableStoreEnd) + || (Variable->StartId !=3D 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; } =20 +/** + Get variable data payload. + + @param[in] Variable Pointer to the Variable Header. + @param[in,out] Data Pointer to buffer used to store the variabl= e 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 variabl= e data. + +**/ +EFI_STATUS +GetVariableData ( + IN VARIABLE_HEADER *Variable, + IN OUT VOID *Data, + IN OUT UINT32 *DataSize, + IN BOOLEAN AuthFlag + ) +{ + UINT32 Size; + + if (DataSize =3D=3D NULL) { + ASSERT (DataSize !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + Size =3D (UINT32)DataSizeOfVariable (Variable, AuthFlag); + if (*DataSize < Size) { + *DataSize =3D Size; + return EFI_BUFFER_TOO_SMALL; + } + + if (Data =3D=3D NULL) { + ASSERT (Data !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size); + *DataSize =3D Size; + + return EFI_SUCCESS; +} + /** =20 This code gets the pointer to the next variable header. @@ -479,7 +532,7 @@ FindVariableEx ( InDeletedVariable =3D NULL; =20 for ( PtrTrack->CurrPtr =3D PtrTrack->StartPtr - ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr) + ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, Auth= Format) ; PtrTrack->CurrPtr =3D GetNextVariablePtr (PtrTrack->CurrPtr, Aut= hFormat) ) { @@ -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, Auth= Format)) { // // Find current storage index // @@ -804,3 +857,260 @@ UpdateVariableInfo ( } } } + +/** + + Retrieve details about a variable and return them in VariableInfo->Heade= r. + + If VariableInfo->Address is given, this function will calculate its offs= et + relative to given variable storage via VariableStore; Otherwise, it will= try + other internal variable storages or cached copies. It's assumed that, fo= r all + copies of NV variable storage, all variables are stored in the same rela= tive + 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->Addres= s, + this function will return the variable memory address inside VariableSto= re, + if given, via VariableInfo->Address; Otherwise, the address of other sto= rage + 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 rang= e of + any given or internal storage copies. + @retval EFI_SUCCESS Variable details are retrieved successful= ly. + +**/ +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 =3D=3D NULL) || ( (VariableInfo->Buffer =3D=3D NULL) + && (VariableInfo->StoreIndex =3D=3D VAR_IN= DEX_INVALID))) + { + ASSERT (VariableInfo !=3D NULL); + ASSERT (VariableInfo->Buffer !=3D NULL || VariableInfo->StoreIndex != =3D VAR_INDEX_INVALID); + return EFI_INVALID_PARAMETER; + } + + Stores[0] =3D mNvVariableCache; + Stores[1] =3D (mVariableModuleGlobal !=3D NULL) + ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->Var= iableGlobal.NonVolatileVariableBase + : NULL; + + VariableBuffer =3D VariableInfo->Buffer; + VariablePtr =3D NULL; + if (VariableInfo->StoreIndex !=3D VAR_INDEX_INVALID) { + for (Index =3D 0; Index < ARRAY_SIZE (Stores); ++Index) { + if (Stores[Index] =3D=3D NULL) { + continue; + } + + if ((UINTN)VariableInfo->StoreIndex + < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index])) + { + VariablePtr =3D (VARIABLE_HEADER *)((UINTN)Stores[Index] = + (UINTN)VariableInfo->StoreIndex); + VariableInfo->Buffer =3D VariablePtr; + break; + } + } + } else { + VariablePtr =3D VariableInfo->Buffer; + } + + if (VariablePtr =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + AuthFlag =3D VariableInfo->Flags.Auth; + ASSERT (AuthFlag =3D=3D TRUE || AuthFlag =3D=3D FALSE); + + // + // Make a copy of the whole variable if a buffer is passed in. + // + if ((VariableBuffer !=3D NULL) && (VariableBuffer !=3D VariablePtr)) { + VariableSize =3D (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag) + - (UINTN)VariablePtr; + CopyMem (VariableBuffer, VariablePtr, VariableSize); + } + + // + // AuthVariable header + // + if (AuthFlag) { + AuthVariablePtr =3D (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr; + + VariableInfo->Header.State =3D AuthVariablePtr->State; + VariableInfo->Header.Attributes =3D AuthVariablePtr->Attributes; + VariableInfo->Header.PubKeyIndex =3D AuthVariablePtr->PubKeyIndex; + VariableInfo->Header.MonotonicCount =3D ReadUnaligned64 ( + &(AuthVariablePtr->MonotonicCo= unt) + ); + if (VariableInfo->Header.TimeStamp !=3D NULL) { + CopyMem ( + VariableInfo->Header.TimeStamp, + &AuthVariablePtr->TimeStamp, + sizeof (EFI_TIME) + ); + } else if (VariableBuffer !=3D NULL) { + AuthVariablePtr =3D (AUTHENTICATED_VARIABLE_HEADER *)= VariableBuffer; + VariableInfo->Header.TimeStamp =3D &AuthVariablePtr->TimeStamp; + } + } else { + VariableInfo->Header.State =3D VariablePtr->State; + VariableInfo->Header.Attributes =3D VariablePtr->Attributes; + VariableInfo->Header.PubKeyIndex =3D 0; + VariableInfo->Header.MonotonicCount =3D 0; + VariableInfo->Header.TimeStamp =3D NULL; + } + + // + // VendorGuid + // + if (VariableInfo->Header.VendorGuid !=3D NULL) { + CopyGuid ( + VariableInfo->Header.VendorGuid, + GetVendorGuidPtr (VariablePtr, AuthFlag) + ); + } else { + VariableInfo->Header.VendorGuid =3D GetVendorGuidPtr (VariablePtr, Aut= hFlag); + } + + // + // VariableName + // + NameSize =3D NameSizeOfVariable (VariablePtr, AuthFlag); + if ( (VariableInfo->Header.VariableName !=3D NULL) + && (VariableInfo->Header.NameSize >=3D NameSize)) + { + CopyMem ( + VariableInfo->Header.VariableName, + GetVariableNamePtr (VariablePtr, AuthFlag), + NameSize + ); + } else if (VariableInfo->Header.VariableName !=3D NULL) { + return EFI_BUFFER_TOO_SMALL; + } else { + VariableInfo->Header.VariableName =3D GetVariableNamePtr (VariablePtr,= AuthFlag); + } + + // + // Data + // + DataSize =3D DataSizeOfVariable (VariablePtr, AuthFlag); + if ( (VariableInfo->Header.Data !=3D NULL) + && (VariableInfo->Header.DataSize >=3D DataSize)) + { + CopyMem ( + VariableInfo->Header.Data, + GetVariableDataPtr (VariablePtr, AuthFlag), + NameSize + ); + } else if (VariableInfo->Header.Data !=3D NULL) { + return EFI_BUFFER_TOO_SMALL; + } else { + VariableInfo->Header.Data =3D GetVariableDataPtr (VariablePtr, AuthFla= g); + } + + // + // Update size information about name & data. + // + VariableInfo->Header.NameSize =3D NameSize; + VariableInfo->Header.DataSize =3D DataSize; + + return EFI_SUCCESS; +} + +/** + + Retrieve details of the variable next to given variable within VariableS= tore. + + If VarInfo->Address is NULL, the first one in VariableStore is returned. + + VariableStart and/or VariableEnd can be given optionally for the situati= on + 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 deter= mine + 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 successful= ly. + +**/ +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 =3D=3D NULL) { + ASSERT (VariableInfo !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + if (mNvVariableCache !=3D NULL) { + VarStore =3D mNvVariableCache; + } else if (mVariableModuleGlobal !=3D NULL) { + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBa= se; + } else { + return EFI_NOT_FOUND; + } + + VariableStart =3D GetStartPointer (VarStore); + VariableEnd =3D GetEndPointer (VarStore); + + if ((VariableInfo->Flags.Auth !=3D TRUE) && (VariableInfo->Flags.Auth != =3D FALSE)) { + VariableInfo->Flags.Auth =3D CompareGuid ( + &VarStore->Signature, + &gEfiAuthenticatedVariableGuid + ); + } + + AuthFlag =3D VariableInfo->Flags.Auth; + + if (VariableInfo->StoreIndex =3D=3D VAR_INDEX_INVALID) { + VariablePtr =3D VariableStart; + } else { + VariablePtr =3D (VARIABLE_HEADER *) + ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex); + if (VariablePtr >=3D VariableEnd) { + return EFI_NOT_FOUND; + } + + VariablePtr =3D GetNextVariablePtr (VariablePtr, AuthFlag); + } + + if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) { + return EFI_NOT_FOUND; + } + + VariableInfo->StoreIndex =3D (UINTN)VariablePtr - (UINTN)VarStore; + return GetVariableInfo (VariableInfo); +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCach= e.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. =20 -Copyright (c) 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/Mde= ModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c index 517cae7b00f8..c2b689f6202d 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c @@ -14,7 +14,7 @@ VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), Reclai= mForOS(), SmmVariableGetStatistics() should also do validation based on its own kn= owledge. =20 -Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
Copyright (c) 2018, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 @@ -1045,6 +1045,13 @@ VariableWriteServiceInitializeSmm ( { EFI_STATUS Status; =20 + Status =3D ProtectedVariableLibWriteInit (); + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { + DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed. = Status =3D %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return; + } + Status =3D VariableWriteServiceInitialize (); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. St= atus =3D %r\n", Status)); @@ -1143,10 +1150,32 @@ MmVariableServiceInitialize ( VOID ) { - EFI_STATUS Status; - EFI_HANDLE VariableHandle; - VOID *SmmFtwRegistration; - VOID *SmmEndOfDxeRegistration; + EFI_STATUS Status; + EFI_HANDLE VariableHandle; + VOID *SmmFtwRegistration; + VOID *SmmEndOfDxeRegistration; + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; + + // + // Initialize protected variable service, if enabled. + // + ContextIn.StructSize =3D sizeof (ContextIn); + ContextIn.StructVersion =3D PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; + + ContextIn.FindVariableSmm =3D NULL; + ContextIn.GetVariableInfo =3D GetVariableInfo; + ContextIn.GetNextVariableInfo =3D GetNextVariableInfo; + ContextIn.UpdateVariableStore =3D VariableExLibUpdateNvVariable; + ContextIn.UpdateVariable =3D VariableExLibUpdateVariable; + + ContextIn.MaxVariableSize =3D (UINT32)GetMaxVariableSize (); + ContextIn.VariableServiceUser =3D FromSmmModule; + + Status =3D ProtectedVariableLibInitialize (&ContextIn); + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { + ASSERT_EFI_ERROR (Status); + return Status; + } =20 // // Variable initialize. diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeD= xe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c index 4aaeb5ba8806..8fb8679671ad 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c @@ -13,7 +13,7 @@ =20 InitCommunicateBuffer() is really function to check the variable data si= ze. =20 -Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 @@ -36,11 +36,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include =20 #include #include =20 #include "PrivilegePolymorphic.h" +#include "Variable.h" #include "VariableParsing.h" =20 EFI_HANDLE mHandle =3D N= ULL; @@ -53,6 +55,8 @@ VARIABLE_INFO_ENTRY *mVariableInfo = =3D NULL; VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer =3D N= ULL; VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer =3D N= ULL; VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer =3D N= ULL; +VARIABLE_STORE_HEADER *mNvVariableCache =3D N= ULL; +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal =3D N= ULL; 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 =3D DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAu= thFormat); - ASSERT (TempDataSize !=3D 0); - - if (*DataSize >=3D TempDataSize) { - if (Data =3D=3D NULL) { - Status =3D EFI_INVALID_PARAMETER; - goto Done; - } - - CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAu= thFormat), TempDataSize); - *DataSize =3D TempDataSize; - - UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile,= TRUE, FALSE, FALSE, TRUE, &mVariableInfo); - - Status =3D EFI_SUCCESS; - goto Done; - } else { - *DataSize =3D TempDataSize; - Status =3D EFI_BUFFER_TOO_SMALL; - goto Done; + if (!RtPtrTrack.Volatile) { + // + // Currently only non-volatile variable needs protection. + // + Status =3D ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Da= ta, (UINT32 *)DataSize, mVariableAuthFormat); + } + + if (RtPtrTrack.Volatile || (Status =3D=3D EFI_UNSUPPORTED)) { + Status =3D GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)Da= taSize, mVariableAuthFormat); + } + + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile,= TRUE, FALSE, FALSE, FALSE, &mVariableInfo); } } } =20 -Done: if ((Status =3D=3D EFI_SUCCESS) || (Status =3D=3D EFI_BUFFER_TOO_SMALL))= { if ((Attributes !=3D NULL) && (RtPtrTrack.CurrPtr !=3D NULL)) { *Attributes =3D RtPtrTrack.CurrPtr->Attributes; --=20 2.35.1.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#89428): https://edk2.groups.io/g/devel/message/89428 Mute This Topic: https://groups.io/mt/90781896/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-