From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga01.intel.com (mga01.intel.com []) by mx.groups.io with SMTP id smtpd.web12.2719.1571212610613189618 for ; Wed, 16 Oct 2019 00:56:55 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: hao.a.wu@intel.com) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2019 00:56:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,303,1566889200"; d="scan'208";a="220698427" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by fmsmga004.fm.intel.com with ESMTP; 16 Oct 2019 00:56:54 -0700 Received: from fmsmsx115.amr.corp.intel.com (10.18.116.19) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.439.0; Wed, 16 Oct 2019 00:56:54 -0700 Received: from shsmsx154.ccr.corp.intel.com (10.239.6.54) by fmsmsx115.amr.corp.intel.com (10.18.116.19) with Microsoft SMTP Server (TLS) id 14.3.439.0; Wed, 16 Oct 2019 00:56:54 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.166]) by SHSMSX154.ccr.corp.intel.com ([10.239.6.54]) with mapi id 14.03.0439.000; Wed, 16 Oct 2019 15:56:51 +0800 From: "Wu, Hao A" To: "Kubacki, Michael A" , "devel@edk2.groups.io" CC: "Bi, Dandan" , Ard Biesheuvel , "Dong, Eric" , Laszlo Ersek , "Gao, Liming" , "Kinney, Michael D" , "Ni, Ray" , "Wang, Jian J" , "Yao, Jiewen" Subject: Re: [PATCH V4 07/10] MdeModulePkg/Variable: Add RT GetVariable() cache support Thread-Topic: [PATCH V4 07/10] MdeModulePkg/Variable: Add RT GetVariable() cache support Thread-Index: AQHVgudkLi9W5QwAdU2WG6DTDIhBIKdcz2rg Date: Wed, 16 Oct 2019 07:56:50 +0000 Message-ID: References: <20191014233001.33024-1-michael.a.kubacki@intel.com> <20191014233001.33024-8-michael.a.kubacki@intel.com> In-Reply-To: <20191014233001.33024-8-michael.a.kubacki@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: hao.a.wu@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Again, I would like to ask for help from other reviewers to look at this pa= tch (patch 7/10) and the next one (patch 8/10) (at least from the security perspective). Any help will be appreciated, thanks in advance. One comment inherited from the feedback on the V2 series: I saw AtRuntime() is still being added in file VariableSmmRuntimeDxe.c, cou= ld you help to double confirm? Another general level comment is that: Please help to update the MdeModulePkg.uni file as well for the introduce o= f the new PCD. Inline comments below: =20 > -----Original Message----- > From: Kubacki, Michael A > Sent: Tuesday, October 15, 2019 7:30 AM > To: devel@edk2.groups.io > Cc: Bi, Dandan; Ard Biesheuvel; Dong, Eric; Laszlo Ersek; Gao, Liming; Ki= nney, > Michael D; Ni, Ray; Wang, Jian J; Wu, Hao A; Yao, Jiewen > Subject: [PATCH V4 07/10] MdeModulePkg/Variable: Add RT GetVariable() > cache support >=20 > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D2220 >=20 > This change reduces SMIs for GetVariable () by maintaining a > UEFI variable cache in Runtime DXE in addition to the pre- > existing cache in SMRAM. When the Runtime Service GetVariable() > is invoked, a Runtime DXE cache is used instead of triggering an > SMI to VariableSmm. This can improve overall system performance > by servicing variable read requests without rendezvousing all > cores into SMM. >=20 > The runtime cache can be disabled with by setting the FeaturePCD > gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache > to FALSE. If the PCD is set to FALSE, the runtime cache will not be > used and an SMI will be triggered for Runtime Service > GetVariable () and GetNextVariableName () invocations. >=20 > The following are important points regarding the behavior of the > variable drivers when the variable runtime cache is enabled. >=20 > 1. All of the non-volatile storage contents are loaded into the > cache upon driver load. This one time load operation from storage > is preferred as opposed to building the cache on demand. An on- > demand cache would require a fallback SMI to load data into the > cache as variables are requested. >=20 > 2. SetVariable () requests will continue to always trigger an SMI. > This occurs regardless of whether the variable is volatile or > non-volatile. >=20 > 3. Both volatile and non-volatile variables are cached in a runtime > buffer. As is the case in the current EDK II variable driver, they > continue to be cached in separate buffers. >=20 > 4. The cache in Runtime DXE and SMM are intended to be exact copies > of one another. All SMM variable accesses only return data from the > SMM cache. The runtime caches are only updated after the variable I/O > operation is successful in SMM. The runtime caches are only updated > from SMM. >=20 > 5. Synchronization mechanisms are in place to ensure the runtime cache > content integrity with the SMM cache. These may result in updates to > runtime cache that are the same in content but different in offset and > size from updates to the SMM cache. >=20 > When using SMM variables with runtime cache enabled, two caches will now > be present. > 1. "Runtime Cache" - Maintained in VariableSmmRuntimeDxe. Used to > service > Runtime Services GetVariable () and GetNextVariableName () callers. > 2. "SMM Cache" - Maintained in VariableSmm to service SMM GetVariable () > and GetNextVariableName () callers. > a. This cache is retained so SMM modules do not operate on data outsid= e > SMRAM. >=20 > Because a race condition can occur if an SMI occurs during the execution > of runtime code reading from the runtime cache, a runtime cache read lock > is introduced that explicitly moves pending updates from SMM to the > runtime > cache if an SMM update occurs while the runtime cache is locked. Note tha= t > it is not expected a Runtime services call will interrupt SMM processing > since all CPU cores rendezvous in SMM. >=20 > It is possible to view UEFI variable read and write statistics by setting > the gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics > FeaturePcd > to TRUE and using the VariableInfo UEFI application in MdeModulePkg to > dump > variable statistics to the console. By doing so, a user can view the numb= er > of GetVariable () hits from the Runtime DXE variable driver (Runtime Cach= e > hits) and the SMM variable driver (SMM Cache hits). SMM Cache hits for > GetVariable () will occur when SMM modules invoke GetVariable (). >=20 > Cc: Dandan Bi > Cc: Ard Biesheuvel > Cc: Eric Dong > Cc: Laszlo Ersek > Cc: Liming Gao > Cc: Michael D Kinney > Cc: Ray Ni > Cc: Jian J Wang > Cc: Hao A Wu > Cc: Jiewen Yao > Signed-off-by: Michael Kubacki > --- > MdeModulePkg/MdeModulePkg.dec | = 12 + > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > | 2 + > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | = 2 > + >=20 > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.i > nf | 20 +- >=20 > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf > | 2 + > MdeModulePkg/Include/Guid/SmmVariableCommon.h | = 29 +- > MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | = 32 +- > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h > | 51 ++ > MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | = 50 +- > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c > | 153 ++++++ > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 1= 14 > ++++- >=20 > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe. > c | 512 +++++++++++++++++++- > 12 files changed, 938 insertions(+), 41 deletions(-) >=20 > diff --git a/MdeModulePkg/MdeModulePkg.dec > b/MdeModulePkg/MdeModulePkg.dec > index 59b8c21713..a00835cb84 100644 > --- a/MdeModulePkg/MdeModulePkg.dec > +++ b/MdeModulePkg/MdeModulePkg.dec > @@ -641,6 +641,18 @@ > # @Prompt Enable Device Path From Text support. >=20 > gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFrom > Text|TRUE|BOOLEAN|0x00010038 >=20 > + ## Indicates if the UEFI variable runtime cache should be enabled. > + # This setting only applies if SMM variables are enabled. When enable= d, all > variable > + # data for Runtime Service GetVariable () and GetNextVariableName () > calls is retrieved > + # from a runtime data buffer referred to as the "runtime cache". An S= MI is > not triggered > + # at all for these requests. Variables writes still trigger an SMI. T= his can > greatly > + # reduce overall system SMM usage as most boots tend to issue far mor= e > variable reads > + # than writes.

> + # TRUE - The UEFI variable runtime cache is enabled.
> + # FALSE - The UEFI variable runtime cache is disabled.
> + # @Prompt Enable the UEFI variable runtime cache. > + > gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALS > E|BOOLEAN|0x00010039 > + > ## Indicates if the statistics about variable usage will be collected.= This > information is > # stored as a vendor configuration table into the EFI system table. > # Set this PCD to TRUE to use VariableInfo application in > MdeModulePkg\Application directory to get > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > index 08a5490787..ceea5d1ff9 100644 > --- > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > @@ -40,6 +40,8 @@ > VariableNonVolatile.h > VariableParsing.c > VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > PrivilegePolymorphic.h > Measurement.c > TcgMorLockDxe.c > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf > index 6dc2721b81..bc3033588d 100644 > --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf > +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf > @@ -49,6 +49,8 @@ > VariableNonVolatile.h > VariableParsing.c > VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > VarCheck.c > Variable.h > PrivilegePolymorphic.h > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.inf > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.inf > index 14894e6f13..b5a779a233 100644 > --- > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.inf > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.inf > @@ -13,7 +13,7 @@ > # may not be modified without authorization. If platform fails to prote= ct > these resources, > # the authentication service provided in this driver will be broken, an= d the > behavior is undefined. > # > -# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
> +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -39,6 +39,10 @@ > VariableSmmRuntimeDxe.c > PrivilegePolymorphic.h > Measurement.c > + VariableParsing.c > + VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h >=20 > [Packages] > MdePkg/MdePkg.dec > @@ -65,7 +69,21 @@ > gEdkiiVariableLockProtocolGuid ## PRODUCES > gEdkiiVarCheckProtocolGuid ## PRODUCES >=20 > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics = ## > CONSUMES > + > [Guids] > + ## PRODUCES ## GUID # Signature of Variable store header > + ## CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiAuthenticatedVariableGuid > + > + ## PRODUCES ## GUID # Signature of Variable store header > + ## CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiVariableGuid > + > gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event > gEfiEventExitBootServicesGuid ## CONSUMES ## Event > ## CONSUMES ## GUID # Locate protocol > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.i > nf > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm. > inf > index f8a3742959..6e17f6cdf5 100644 > --- > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.i > nf > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm. > inf > @@ -49,6 +49,8 @@ > VariableNonVolatile.h > VariableParsing.c > VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > VarCheck.c > Variable.h > PrivilegePolymorphic.h > diff --git a/MdeModulePkg/Include/Guid/SmmVariableCommon.h > b/MdeModulePkg/Include/Guid/SmmVariableCommon.h > index c527a59891..ceef44dfd2 100644 > --- a/MdeModulePkg/Include/Guid/SmmVariableCommon.h > +++ b/MdeModulePkg/Include/Guid/SmmVariableCommon.h > @@ -1,7 +1,7 @@ > /** @file > The file defined some common structures used for communicating > between SMM variable module and SMM variable wrapper module. >=20 > -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
> +Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
> SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > **/ > @@ -9,6 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #ifndef _SMM_VARIABLE_COMMON_H_ > #define _SMM_VARIABLE_COMMON_H_ >=20 > +#include > #include >=20 > #define EFI_SMM_VARIABLE_WRITE_GUID \ > @@ -66,6 +67,16 @@ typedef struct { > #define > SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 >=20 > #define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 > +// > +// The payload for this function is > SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > +// > +#define > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT > 12 > + > +#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13 > +// > +// The payload for this function is > SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > +// > +#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO > 14 >=20 > /// > /// Size of SMM communicate header, without including the payload. > @@ -120,4 +131,20 @@ typedef struct { > UINTN VariablePayloadSize; > } SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE; >=20 > +typedef struct { > + BOOLEAN *ReadLock; > + BOOLEAN *PendingUpdate; > + BOOLEAN *HobFlushComplete; > + VARIABLE_STORE_HEADER *RuntimeHobCache; > + VARIABLE_STORE_HEADER *RuntimeNvCache; > + VARIABLE_STORE_HEADER *RuntimeVolatileCache; > +} > SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT; > + > +typedef struct { > + UINTN TotalHobStorageSize; > + UINTN TotalNvStorageSize; > + UINTN TotalVolatileStorageSize; > + BOOLEAN AuthenticatedVariableUsage; > +} SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO; > + > #endif // _SMM_VARIABLE_COMMON_H_ > diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h > b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h > index fb574b2e32..0b2bb6ae66 100644 > --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h > +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h > @@ -64,6 +64,21 @@ typedef enum { > VariableStoreTypeMax > } VARIABLE_STORE_TYPE; >=20 > +typedef struct { > + UINT32 PendingUpdateOffset; > + UINT32 PendingUpdateLength; > + VARIABLE_STORE_HEADER *Store; > +} VARIABLE_RUNTIME_CACHE; > + > +typedef struct { > + BOOLEAN *ReadLock; > + BOOLEAN *PendingUpdate; > + BOOLEAN *HobFlushComplete; > + VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache; > + VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache; > + VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache; > +} VARIABLE_RUNTIME_CACHE_CONTEXT; > + > typedef struct { > VARIABLE_HEADER *CurrPtr; > // > @@ -79,14 +94,15 @@ typedef struct { > } VARIABLE_POINTER_TRACK; >=20 > typedef struct { > - EFI_PHYSICAL_ADDRESS HobVariableBase; > - EFI_PHYSICAL_ADDRESS VolatileVariableBase; > - EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; > - EFI_LOCK VariableServicesLock; > - UINT32 ReentrantState; > - BOOLEAN AuthFormat; > - BOOLEAN AuthSupport; > - BOOLEAN EmuNvMode; > + EFI_PHYSICAL_ADDRESS HobVariableBase; > + EFI_PHYSICAL_ADDRESS VolatileVariableBase; > + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; > + VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext; > + EFI_LOCK VariableServicesLock; > + UINT32 ReentrantState; > + BOOLEAN AuthFormat; > + BOOLEAN AuthSupport; > + BOOLEAN EmuNvMode; > } VARIABLE_GLOBAL; >=20 > typedef struct { > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache. > h > new file mode 100644 > index 0000000000..f9804a1d69 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache. > h > @@ -0,0 +1,51 @@ > +/** @file > + The common variable volatile store routines shared by the DXE_RUNTIME > variable > + module and the DXE_SMM variable module. > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _VARIABLE_RUNTIME_CACHE_H_ > +#define _VARIABLE_RUNTIME_CACHE_H_ > + > +#include "Variable.h" > + > +/** > + Copies any pending updates to runtime variable caches. > + > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated success= fully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ); > + > +/** > + Synchronizes the runtime variable caches with all pending updates outs= ide > runtime. > + > + Ensures all conditions are met to maintain coherency for runtime cache > updates. This function will attempt > + to write the given update (and any other pending updates) if the ReadL= ock > is available. Otherwise, the > + update is added as a pending update for the given variable store and i= t will > be flushed to the runtime cache > + at the next opportunity the ReadLock is available. > + > + @param[in] VariableRuntimeCache Variable runtime cache structure for > the runtime cache being synchronized. > + @param[in] Offset Offset in bytes to apply the update. > + @param[in] Length Length of data in bytes of the update. > + > + @retval EFI_SUCCESS The update was added as a pending upda= te > successfully. If the variable runtime > + cache ReadLock was available, the runt= ime cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + > +**/ > +EFI_STATUS > +SynchronizeRuntimeVariableCache ( > + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, > + IN UINTN Offset, > + IN UINTN Length > + ); > + > +#endif > diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c > b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c > index 0bd2f22e1a..29d6aca993 100644 > --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c > +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c > @@ -25,6 +25,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #include "Variable.h" > #include "VariableNonVolatile.h" > #include "VariableParsing.h" > +#include "VariableRuntimeCache.h" >=20 > VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; >=20 > @@ -332,6 +333,12 @@ RecordVarErrorFlag ( > // Update the data in NV cache. > // > *VarErrFlag =3D TempFlag; > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN= ) > mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, > + sizeof (TempFlag) > + ); > + ASSERT_EFI_ERROR (Status); > } > } > } > @@ -766,12 +773,24 @@ Reclaim ( >=20 > Done: > if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCach > e, > + 0, > + VariableStoreHeader->Size > + ); > + ASSERT_EFI_ERROR (Status); > FreePool (ValidBuffer); > } else { > // > // For NV variable reclaim, we use mNvVariableCache as the buffer, s= o > copy the data back. > // > - CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, > VariableStoreHeader->Size); > + CopyMem (mNvVariableCache, (UINT8 *) (UINTN) VariableBase, > VariableStoreHeader->Size); > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + 0, > + VariableStoreHeader->Size > + ); > + ASSERT_EFI_ERROR (Status); > } >=20 > return Status; > @@ -1614,6 +1633,7 @@ UpdateVariable ( > VARIABLE_POINTER_TRACK *Variable; > VARIABLE_POINTER_TRACK NvVariable; > VARIABLE_STORE_HEADER *VariableStoreHeader; > + VARIABLE_RUNTIME_CACHE *VolatileCacheInstance; > UINT8 *BufferForMerge; > UINTN MergedBufSize; > BOOLEAN DataReady; > @@ -2275,6 +2295,23 @@ UpdateVariable ( > } >=20 > Done: > + if (!EFI_ERROR (Status)) { > + if (Variable->Volatile) { > + VolatileCacheInstance =3D &(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCach > e); > + } else { > + VolatileCacheInstance =3D &(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache); > + } > + > + if (VolatileCacheInstance->Store !=3D NULL) { > + Status =3D SynchronizeRuntimeVariableCache ( > + VolatileCacheInstance, > + 0, > + VolatileCacheInstance->Store->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + } > + > return Status; > } >=20 > @@ -3200,6 +3237,14 @@ FlushHobVariableToFlash ( > ErrorFlag =3D TRUE; > } > } > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.S > tore !=3D NULL) { > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache, > + 0, > + mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.S > tore->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > if (ErrorFlag) { > // > // We still have HOB variable(s) not flushed in flash. > @@ -3210,6 +3255,9 @@ FlushHobVariableToFlash ( > // All HOB variables have been flushed in flash. > // > DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been > flushed in flash.\n")); > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete !=3D NULL) > { > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) =3D TRUE; > + } > if (!AtRuntime ()) { > FreePool ((VOID *) VariableStoreHeader); > } > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c > new file mode 100644 > index 0000000000..bc93cc07d2 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c > @@ -0,0 +1,153 @@ > +/** @file > + Functions related to managing the UEFI variable runtime cache. This fi= le > should only include functions > + used by the SMM UEFI variable driver. > + > + Caution: This module requires additional review when modified. > + This driver will have external input - variable data. They may be inpu= t in > SMM mode. > + This external input must be validated carefully to avoid security issu= e like > + buffer overflow, integer overflow. > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; > +extern VARIABLE_STORE_HEADER *mNvVariableCache; > + > +/** > + Copies any pending updates to runtime variable caches. > + > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated success= fully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ) > +{ > + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext; > + > + VariableRuntimeCacheContext =3D &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + > + if (VariableRuntimeCacheContext->VariableRuntimeNvCache.Store =3D=3D > NULL || > + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store = =3D=3D > NULL || > + VariableRuntimeCacheContext->PendingUpdate =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + if (*(VariableRuntimeCacheContext->PendingUpdate)) { > + if (VariableRuntimeCacheContext->VariableRuntimeHobCache.Store !=3D > NULL && > + mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { > + CopyMem ( > + (VOID *) ( > + ((UINT8 *) (UINTN) VariableRuntimeCacheContext- > >VariableRuntimeHobCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset > + ), > + (VOID *) ( > + ((UINT8 *) (UINTN) mVariableModuleGlobal- > >VariableGlobal.HobVariableBase) + > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset =3D 0; > + } > + > + CopyMem ( > + (VOID *) ( > + ((UINT8 *) (UINTN) VariableRuntimeCacheContext- > >VariableRuntimeNvCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + (VOID *) ( > + ((UINT8 *) (UINTN) mNvVariableCache) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset =3D 0; > + > + CopyMem ( > + (VOID *) ( > + ((UINT8 *) (UINTN) VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset > + ), > + (VOID *) ( > + ((UINT8 *) (UINTN) mVariableModuleGlobal- > >VariableGlobal.VolatileVariableBase) + > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset =3D 0; > + *(VariableRuntimeCacheContext->PendingUpdate) =3D FALSE; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Synchronizes the runtime variable caches with all pending updates outs= ide > runtime. > + > + Ensures all conditions are met to maintain coherency for runtime cache > updates. This function will attempt > + to write the given update (and any other pending updates) if the ReadL= ock > is available. Otherwise, the > + update is added as a pending update for the given variable store and i= t will > be flushed to the runtime cache > + at the next opportunity the ReadLock is available. > + > + @param[in] VariableRuntimeCache Variable runtime cache structure for > the runtime cache being synchronized. > + @param[in] Offset Offset in bytes to apply the update. > + @param[in] Length Length of data in bytes of the update. > + > + @retval EFI_SUCCESS The update was added as a pending upda= te > successfully. If the variable runtime > + cache ReadLock was available, the runt= ime cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + > +**/ > +EFI_STATUS > +SynchronizeRuntimeVariableCache ( > + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, > + IN UINTN Offset, > + IN UINTN Length > + ) > +{ > + if (VariableRuntimeCache =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } else if (VariableRuntimeCache->Store =3D=3D NULL) { > + // The runtime cache may not be active or allocated yet. > + // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_Y= ET. > + return EFI_SUCCESS; > + } > + > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate =3D=3D NULL || > + mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) && > + VariableRuntimeCache->PendingUpdateLength > 0) { > + VariableRuntimeCache->PendingUpdateLength =3D > + (UINT32) ( > + MAX ( > + (UINTN) (VariableRuntimeCache->PendingUpdateOffset + > VariableRuntimeCache->PendingUpdateLength), > + Offset + Length > + ) - MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offs= et) > + ); > + VariableRuntimeCache->PendingUpdateOffset =3D > + (UINT32) MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, > Offset); > + } else { > + VariableRuntimeCache->PendingUpdateLength =3D (UINT32) Length; > + VariableRuntimeCache->PendingUpdateOffset =3D (UINT32) Offset; > + } > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) =3D TRUE; > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock) =3D=3D FALSE) { > + return FlushPendingRuntimeVariableCacheUpdates (); > + } > + > + return EFI_SUCCESS; > +} > diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c > index 5e24bc4a62..45814b8996 100644 > --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c > +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c > @@ -31,6 +31,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #include > #include "Variable.h" > #include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +extern VARIABLE_STORE_HEADER *mNvVariableCache; >=20 > BOOLEAN mAtRuntime = =3D FALSE; > UINT8 *mVariableBufferPay= load =3D NULL; > @@ -451,25 +454,29 @@ SmmVariableGetStatistics ( > EFI_STATUS > EFIAPI > SmmVariableHandler ( > - IN EFI_HANDLE DispatchHandle, > - IN CONST VOID *RegisterContext, > - IN OUT VOID *CommBuffer, > - IN OUT UINTN *CommBufferSize > + IN EFI_HANDLE DispatchHandle= , > + IN CONST VOID *RegisterConte= xt, > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommBufferSiz= e > ) > { > - EFI_STATUS Status; > - SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE > *SmmVariableHeader; > - SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME > *GetNextVariableName; > - SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO > *QueryVariableInfo; > - SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE > *GetPayloadSize; > - VARIABLE_INFO_ENTRY *VariableInfo; > - SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock; > - SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *CommVariableProperty; > - UINTN InfoSize; > - UINTN NameBufferSize; > - UINTN CommBufferPayloadSize= ; > - UINTN TempCommBufferSize; > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE > *SmmVariableHeader; > + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME > *GetNextVariableName; > + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO > *QueryVariableInfo; > + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE > *GetPayloadSize; > + > SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *RuntimeVariableCacheContext; > + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *GetRuntimeCacheInfo; > + SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE > *VariableToLock; > + SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *CommVariableProperty; > + VARIABLE_INFO_ENTRY *VariableInfo; > + VARIABLE_RUNTIME_CACHE_CONTEXT > *VariableCacheContext; > + VARIABLE_STORE_HEADER *VariableCache= ; > + UINTN InfoSize; > + UINTN NameBufferSize= ; > + UINTN CommBufferPayl= oadSize; > + UINTN TempCommBuffer= Size; >=20 > // > // If input is invalid, stop processing this SMI > @@ -789,6 +796,79 @@ SmmVariableHandler ( > ); > CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, > CommBufferPayloadSize); > break; > + case > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) > { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM > communication buffer size invalid!\n")); > + } else if (mEndOfDxe) { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot > init context after end of DXE!\n")); > + } else { > + RuntimeVariableCacheContext =3D > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *) SmmVariableFunctionHeader->Data; > + VariableCacheContext =3D &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + > + ASSERT (RuntimeVariableCacheContext->RuntimeVolatileCache !=3D > NULL); > + ASSERT (RuntimeVariableCacheContext->RuntimeNvCache !=3D NULL); > + ASSERT (RuntimeVariableCacheContext->PendingUpdate !=3D NULL); > + ASSERT (RuntimeVariableCacheContext->ReadLock !=3D NULL); > + ASSERT (RuntimeVariableCacheContext->HobFlushComplete !=3D NULL)= ; > + > + VariableCacheContext->VariableRuntimeHobCache.Store =3D > RuntimeVariableCacheContext->RuntimeHobCache; > + VariableCacheContext->VariableRuntimeVolatileCache.Store =3D > RuntimeVariableCacheContext->RuntimeVolatileCache; > + VariableCacheContext->VariableRuntimeNvCache.Store =3D > RuntimeVariableCacheContext->RuntimeNvCache; > + VariableCacheContext->PendingUpdate =3D > RuntimeVariableCacheContext->PendingUpdate; > + VariableCacheContext->ReadLock =3D > RuntimeVariableCacheContext->ReadLock; > + VariableCacheContext->HobFlushComplete =3D > RuntimeVariableCacheContext->HobFlushComplete; > + > + // Set up the intial pending request since the RT cache needs to= be in > sync with SMM cache > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D=3D= 0) { > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset =3D 0; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength =3D 0; > + } else { > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset =3D 0; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength =3D (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext- > >VariableRuntimeHobCache.Store->Signature), &(VariableCache- > >Signature)); > + } > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset =3D 0; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength =3D (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext- > >VariableRuntimeVolatileCache.Store->Signature), &(VariableCache- > >Signature)); > + > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mNvVariableCache; > + VariableCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset =3D 0; > + VariableCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength =3D (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store- > >Signature), &(VariableCache->Signature)); > + > + *(VariableCacheContext->PendingUpdate) =3D TRUE; > + *(VariableCacheContext->ReadLock) =3D FALSE; > + *(VariableCacheContext->HobFlushComplete) =3D FALSE; > + } > + Status =3D EFI_SUCCESS; > + break; > + case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE: > + Status =3D FlushPendingRuntimeVariableCacheUpdates (); > + break; > + case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) { > + DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication > buffer size invalid!\n")); > + return EFI_SUCCESS; > + } > + GetRuntimeCacheInfo =3D > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) > SmmVariableFunctionHeader->Data; > + > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + GetRuntimeCacheInfo->TotalHobStorageSize =3D VariableCache->Size= ; > + } else { > + GetRuntimeCacheInfo->TotalHobStorageSize =3D 0; > + } > + > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + GetRuntimeCacheInfo->TotalVolatileStorageSize =3D VariableCache->S= ize; > + VariableCache =3D (VARIABLE_STORE_HEADER *) (UINTN) > mNvVariableCache; > + GetRuntimeCacheInfo->TotalNvStorageSize =3D (UINTN) VariableCache- > >Size; > + GetRuntimeCacheInfo->AuthenticatedVariableUsage =3D > mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + Status =3D EFI_SUCCESS; > + break; >=20 > default: > Status =3D EFI_UNSUPPORTED; > diff --git > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.c > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.c > index 0a1888e5ef..e236ddff33 100644 > --- > a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.c > +++ > b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx > e.c > @@ -13,7 +13,7 @@ >=20 > InitCommunicateBuffer() is really function to check the variable data = size. >=20 > -Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
> +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
> SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > **/ > @@ -39,6 +39,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #include >=20 > #include "PrivilegePolymorphic.h" > +#include "VariableParsing.h" >=20 > EFI_HANDLE mHandle =3D NULL; > EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable =3D NULL; > @@ -46,8 +47,19 @@ EFI_EVENT mVirtualAddressChange= Event =3D > NULL; > EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication =3D > NULL; > UINT8 *mVariableBuffer =3D NULL; > UINT8 *mVariableBufferPhysical =3D NULL; > +VARIABLE_INFO_ENTRY *mVariableInfo =3D NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = =3D > NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = =3D > NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer > =3D NULL; > UINTN mVariableBufferSize; > +UINTN mVariableRuntimeHobCacheBufferSize; > +UINTN mVariableRuntimeNvCacheBufferSize; > +UINTN mVariableRuntimeVolatileCacheBufferSize= ; > UINTN mVariableBufferPayloadSize; > +BOOLEAN mVariableRuntimeCachePendingUpdate; > +BOOLEAN mVariableRuntimeCacheReadLock; > +BOOLEAN mVariableAuthFormat; > +BOOLEAN mHobFlushComplete; > EFI_LOCK mVariableServicesLock; > EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock; > EDKII_VAR_CHECK_PROTOCOL mVarCheck; > @@ -107,6 +119,72 @@ ReleaseLockOnlyAtBootTime ( > } > } >=20 > +/** > + Return TRUE if ExitBootServices () has been called. > + > + @retval TRUE If ExitBootServices () has been called. FALSE if > ExitBootServices () has not been called. > +**/ > +BOOLEAN > +AtRuntime ( > + VOID > + ) > +{ > + return EfiAtRuntime (); > +} > + > +/** > + Initialize the variable cache buffer as an empty variable store. > + > + @param[out] VariableCacheBuffer A pointer to pointer of a cach= e > variable store. > + @param[in,out] TotalVariableCacheSize On input, the minimum size > needed for the UEFI variable store cache > + buffer that is allocated. On o= utput, the actual size of > the buffer allocated. > + If TotalVariableCacheSize is z= ero, a buffer will not be > allocated and the > + function will return with EFI_= SUCCESS. > + > + @retval EFI_SUCCESS The variable cache was allocated and i= nitialized > successfully. > + @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid > variable store size was specified. > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available t= o > allocate the variable store cache buffer. > + > +**/ > +EFI_STATUS > +InitVariableCache ( > + OUT VARIABLE_STORE_HEADER **VariableCacheBuffer, > + IN OUT UINTN *TotalVariableCacheSize > + ) > +{ > + VARIABLE_STORE_HEADER *VariableCacheStorePtr; > + > + if (TotalVariableCacheSize =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (*TotalVariableCacheSize =3D=3D 0) { > + return EFI_SUCCESS; > + } > + if (VariableCacheBuffer =3D=3D NULL || *TotalVariableCacheSize < sizeo= f > (VARIABLE_STORE_HEADER)) { > + return EFI_INVALID_PARAMETER; > + } > + *TotalVariableCacheSize =3D ALIGN_VALUE (*TotalVariableCacheSize, size= of > (UINT32)); > + > + // > + // Allocate NV Storage Cache and initialize it to all 1's (like an era= sed FV) > + // > + *VariableCacheBuffer =3D (VARIABLE_STORE_HEADER *) > AllocateRuntimePages ( > + EFI_SIZE_TO_PAGES (*TotalVariableCacheSize) > + ); > + if (*VariableCacheBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + VariableCacheStorePtr =3D *VariableCacheBuffer; > + SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, > (UINT32) 0xFFFFFFFF); > + > + ZeroMem ((VOID *) VariableCacheStorePtr, sizeof > (VARIABLE_STORE_HEADER)); > + VariableCacheStorePtr->Size =3D (UINT32) *TotalVariableCacheSize; > + VariableCacheStorePtr->Format =3D VARIABLE_STORE_FORMATTED; > + VariableCacheStorePtr->State =3D VARIABLE_STORE_HEALTHY; > + > + return EFI_SUCCESS; > +} > + > /** > Initialize the communicate buffer using DataSize and Function. >=20 > @@ -425,7 +503,169 @@ Done: > } >=20 > /** > - This code finds variable in storage blocks (Volatile or Non-Volatile). > + Signals SMM to synchronize any pending variable updates with the > runtime cache(s). > + > +**/ > +VOID > +SyncRuntimeCache ( > + VOID > + ) > +{ > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. > + // > + InitCommunicateBuffer (NULL, 0, > SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE); > + > + // > + // Send data to SMM. > + // > + SendCommunicateBuffer (0); > +} > + > +/** > + Check whether a SMI must be triggered to retrieve pending cache update= s. > + > + If the variable HOB was finished being flushed since the last check fo= r a > runtime cache update, this function > + will prevent the HOB cache from being used for future runtime cache hi= ts. > + > +**/ > +VOID > +CheckForRuntimeCacheSync ( > + VOID > + ) > +{ > + if (mVariableRuntimeCachePendingUpdate) { > + SyncRuntimeCache (); > + } > + ASSERT (!mVariableRuntimeCachePendingUpdate); > + > + // > + // The HOB variable data may have finished being flushed in the runtim= e > cache sync update > + // > + if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer !=3D NULL) { > + if (!EfiAtRuntime ()) { > + FreePool (mVariableRuntimeHobCacheBuffer); > + } > + mVariableRuntimeHobCacheBuffer =3D NULL; > + } > +} > + > +/** > + Finds the given variable in a runtime cache variable store. > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully 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 fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be= found. > + > +**/ > +EFI_STATUS > +FindVariableInRuntimeCache ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + UINTN TempDataSize; > + VARIABLE_POINTER_TRACK RtPtrTrack; > + VARIABLE_STORE_TYPE StoreType; > + VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax]; > + > + Status =3D EFI_NOT_FOUND; > + > + if (VariableName =3D=3D NULL || VendorGuid =3D=3D NULL || DataSize =3D= =3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The UEFI specification restricts Runtime Services callers from invo= king > the same or certain other Runtime Service > + // functions prior to completion and return from a previous Runtime > Service call. These restrictions prevent > + // a GetVariable () or GetNextVariable () call from being issued until= a prior > call has returned. The runtime > + // cache read lock should always be free when entering this function. > + // > + ASSERT (!mVariableRuntimeCacheReadLock); > + > + mVariableRuntimeCacheReadLock =3D TRUE; > + CheckForRuntimeCacheSync (); > + > + if (!mVariableRuntimeCachePendingUpdate) { > + // > + // 0: Volatile, 1: HOB, 2: Non-Volatile. > + // The index and attributes mapping must be kept in this order as > FindVariable > + // makes use of this mapping to implement search algorithm. > + // > + VariableStoreList[VariableStoreTypeVolatile] =3D > mVariableRuntimeVolatileCacheBuffer; > + VariableStoreList[VariableStoreTypeHob] =3D > mVariableRuntimeHobCacheBuffer; > + VariableStoreList[VariableStoreTypeNv] =3D > mVariableRuntimeNvCacheBuffer; > + > + for (StoreType =3D (VARIABLE_STORE_TYPE) 0; StoreType < > VariableStoreTypeMax; StoreType++) { > + if (VariableStoreList[StoreType] =3D=3D NULL) { > + continue; > + } > + > + RtPtrTrack.StartPtr =3D GetStartPointer (VariableStoreList[StoreTy= pe]); > + RtPtrTrack.EndPtr =3D GetEndPointer (VariableStoreList[StoreTy= pe]); > + RtPtrTrack.Volatile =3D (BOOLEAN) (StoreType =3D=3D > VariableStoreTypeVolatile); > + > + Status =3D FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtr= Track, > mVariableAuthFormat); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // Get data size > + // > + TempDataSize =3D DataSizeOfVariable (RtPtrTrack.CurrPtr, > mVariableAuthFormat); > + 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, > mVariableAuthFormat), TempDataSize); > + if (Attributes !=3D NULL) { > + *Attributes =3D RtPtrTrack.CurrPtr->Attributes; > + } > + > + *DataSize =3D TempDataSize; > + > + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatil= e, > TRUE, FALSE, FALSE, TRUE, &mVariableInfo); > + > + Status =3D EFI_SUCCESS; > + goto Done; > + } else { > + *DataSize =3D TempDataSize; > + Status =3D EFI_BUFFER_TOO_SMALL; > + goto Done; > + } > + } > + } > + > +Done: > + mVariableRuntimeCacheReadLock =3D FALSE; > + > + return Status; > +} > + > +/** > + Finds the given variable in a variable store in SMM. >=20 > Caution: This function may receive untrusted input. > The data size is external input, so this function will validate it car= efully to > avoid buffer overflow. > @@ -437,20 +677,18 @@ Done: > data, this value contains the requi= red size. > @param[out] Data Data pointer. >=20 > + @retval EFI_SUCCESS Found the specified variable. > @retval EFI_INVALID_PARAMETER Invalid parameter. > - @retval EFI_SUCCESS Find the specified variable. > - @retval EFI_NOT_FOUND Not found. > - @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + @retval EFI_NOT_FOUND The specified variable could not be= found. >=20 > **/ > EFI_STATUS > -EFIAPI > -RuntimeServiceGetVariable ( > +FindVariableInSmm ( > IN CHAR16 *VariableName, > IN EFI_GUID *VendorGuid, > OUT UINT32 *Attributes OPTIONAL, > IN OUT UINTN *DataSize, > - OUT VOID *Data > + OUT VOID *Data OPTIONAL > ) > { > EFI_STATUS Status; > @@ -474,8 +712,6 @@ RuntimeServiceGetVariable ( > return EFI_INVALID_PARAMETER; > } >=20 > - AcquireLockOnlyAtBootTime(&mVariableServicesLock); > - > // > // Init the communicate buffer. The buffer data size is: > // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > @@ -488,7 +724,7 @@ RuntimeServiceGetVariable ( > } > PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > VariableNameSize + TempDataSize; >=20 > - Status =3D InitCommunicateBuffer ((VOID **)&SmmVariableHeader, > PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); > + Status =3D InitCommunicateBuffer ((VOID **) &SmmVariableHeader, > PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); > if (EFI_ERROR (Status)) { > goto Done; > } > @@ -534,11 +770,58 @@ RuntimeServiceGetVariable ( > } >=20 > Done: > + return Status; > +} > + > +/** > + This code finds variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully 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 fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Find the specified variable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + > +**/ > +EFI_STATUS > +EFIAPI > +RuntimeServiceGetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data > + ) > +{ > + EFI_STATUS Status; > + > + if (VariableName =3D=3D NULL || VendorGuid =3D=3D NULL || DataSize =3D= =3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (VariableName[0] =3D=3D 0) { > + return EFI_NOT_FOUND; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + Status =3D FindVariableInRuntimeCache (VariableName, VendorGuid, > Attributes, DataSize, Data); > + } else { > + Status =3D FindVariableInSmm (VariableName, VendorGuid, Attributes, > DataSize, Data); > + } > ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + > return Status; > } >=20 > - > /** > This code Finds the Next available variable. >=20 > @@ -870,6 +1153,17 @@ OnReadyToBoot ( > // > SendCommunicateBuffer (0); >=20 > + // > + // Install the system configuration table for variable info data captu= red > + // > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet > (PcdVariableCollectStatistics)) { > + if (mVariableAuthFormat) { > + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, > mVariableInfo); > + } else { > + gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo); > + } > + } > + > gBS->CloseEvent (Event); > } >=20 > @@ -893,6 +1187,9 @@ VariableAddressChangeEvent ( > { > EfiConvertPointer (0x0, (VOID **) &mVariableBuffer); > EfiConvertPointer (0x0, (VOID **) &mSmmCommunication); > + EfiConvertPointer (0x0, (VOID **) &mVariableRuntimeHobCacheBuffer); > + EfiConvertPointer (0x0, (VOID **) &mVariableRuntimeNvCacheBuffer); > + EfiConvertPointer (0x0, (VOID **) > &mVariableRuntimeVolatileCacheBuffer); > } >=20 > /** > @@ -969,6 +1266,159 @@ Done: > return Status; > } >=20 > +/** > + This code gets information needed from SMM for runtime cache > initialization. > + > + @param[out] TotalHobStorageSize Output pointer for the total H= OB > storage size in bytes. > + @param[out] TotalNvStorageSize Output pointer for the total n= on- > volatile storage size in bytes. > + @param[out] TotalVolatileStorageSize Output pointer for the total > volatile storage size in bytes. > + @param[out] AuthenticatedVariableUsage Output pointer that indicates = if > authenticated variables are to be used. > + > + @retval EFI_SUCCESS Retrieved the size successfull= y. > + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter i= s > NULL. > + @retval EFI_OUT_OF_RESOURCES The memory resources needed > for a CommBuffer are not available. > + @retval Others Could not retrieve the size su= ccessfully. > + > +**/ > +EFI_STATUS > +GetRuntimeCacheInfo ( > + OUT UINTN *TotalHobStorageSize, > + OUT UINTN *TotalNvStorageSize, > + OUT UINTN *TotalVolatileStorageSize, > + OUT BOOLEAN *AuthenticatedVariableUsage > + ) > +{ > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *SmmGetRuntimeCacheInfo; > + EFI_SMM_COMMUNICATE_HEADER > *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + UINTN CommSize; > + UINT8 *CommBuffer; > + > + SmmGetRuntimeCacheInfo =3D NULL; > + CommBuffer =3D mVariableBuffer; > + > + if (TotalHobStorageSize =3D=3D NULL || TotalNvStorageSize =3D=3D NULL = || > TotalVolatileStorageSize =3D=3D NULL || AuthenticatedVariableUsage =3D=3D= NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (CommBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + CommSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); > + ZeroMem (CommBuffer, CommSize); I would suggest to align with the approach of using the pre-alloacted communication buffer like those existing functions: VariableLockRequestToLock() VarCheckVariablePropertySet() VarCheckVariablePropertyGet() RuntimeServiceGetVariable() RuntimeServiceGetNextVariableName() RuntimeServiceSetVariable() RuntimeServiceQueryVariableInfo() OnExitBootServices() OnReadyToBoot() They will: 1. Use InitCommunicateBuffer() to get the communication buffer (a data size check will be performed in InitCommunicateBuffer); 2. Update the communication buffer content; 3. Use SendCommunicateBuffer() to send the data to SMM. There is a similar case for SendRuntimeVariableCacheContextToSmm() as well. Best Regards, Hao Wu > + > + SmmCommunicateHeader =3D (EFI_SMM_COMMUNICATE_HEADER *) > CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader- > >Data; > + SmmVariableFunctionHeader->Function =3D > SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO; > + SmmGetRuntimeCacheInfo =3D > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) > SmmVariableFunctionHeader->Data; > + > + // > + // Send data to SMM. > + // > + Status =3D mSmmCommunication->Communicate (mSmmCommunication, > CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <=3D SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status =3D EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status =3D SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data from SMM. > + // > + *TotalHobStorageSize =3D SmmGetRuntimeCacheInfo->TotalHobStorageSize; > + *TotalNvStorageSize =3D SmmGetRuntimeCacheInfo->TotalNvStorageSize; > + *TotalVolatileStorageSize =3D SmmGetRuntimeCacheInfo- > >TotalVolatileStorageSize; > + *AuthenticatedVariableUsage =3D SmmGetRuntimeCacheInfo- > >AuthenticatedVariableUsage; > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Sends the runtime variable cache context information to SMM. > + > + @retval EFI_SUCCESS Retrieved the size successfully. > + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is > NULL. > + @retval EFI_OUT_OF_RESOURCES The memory resources needed for a > CommBuffer are not available. > + @retval Others Could not retrieve the size successf= ully.; > + > +**/ > +EFI_STATUS > +SendRuntimeVariableCacheContextToSmm ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *SmmRuntimeVarCacheContext; > + EFI_SMM_COMMUNICATE_HEADER > *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + UINTN CommSize; > + UINT8 *CommBuffer; > + > + SmmRuntimeVarCacheContext =3D NULL; > + CommBuffer =3D mVariableBuffer; > + > + if (CommBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + // > + CommSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + ZeroMem (CommBuffer, CommSize); > + > + SmmCommunicateHeader =3D (EFI_SMM_COMMUNICATE_HEADER *) > CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader- > >Data; > + SmmVariableFunctionHeader->Function =3D > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT; > + SmmRuntimeVarCacheContext =3D > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *) SmmVariableFunctionHeader->Data; > + > + SmmRuntimeVarCacheContext->RuntimeHobCache =3D > mVariableRuntimeHobCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeVolatileCache =3D > mVariableRuntimeVolatileCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeNvCache =3D > mVariableRuntimeNvCacheBuffer; > + SmmRuntimeVarCacheContext->PendingUpdate =3D > &mVariableRuntimeCachePendingUpdate; > + SmmRuntimeVarCacheContext->ReadLock =3D > &mVariableRuntimeCacheReadLock; > + SmmRuntimeVarCacheContext->HobFlushComplete =3D > &mHobFlushComplete; > + > + // > + // Send data to SMM. > + // > + Status =3D mSmmCommunication->Communicate (mSmmCommunication, > CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <=3D SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status =3D EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status =3D SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > /** > Initialize variable service and install Variable Architectural protoco= l. >=20 > @@ -985,7 +1435,7 @@ SmmVariableReady ( > { > EFI_STATUS Status; >=20 > - Status =3D gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, > (VOID **)&mSmmVariable); > + Status =3D gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, > (VOID **) &mSmmVariable); > if (EFI_ERROR (Status)) { > return; > } > @@ -1007,6 +1457,42 @@ SmmVariableReady ( > // > mVariableBufferPhysical =3D mVariableBuffer; >=20 > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n")); > + // > + // Allocate runtime variable cache memory buffers. > + // > + Status =3D GetRuntimeCacheInfo ( > + &mVariableRuntimeHobCacheBufferSize, > + &mVariableRuntimeNvCacheBufferSize, > + &mVariableRuntimeVolatileCacheBufferSize, > + &mVariableAuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeHobCacheBuffer, > &mVariableRuntimeHobCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeNvCacheBuffer, > &mVariableRuntimeNvCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeVolatileCacheBu= ffer, > &mVariableRuntimeVolatileCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D SendRuntimeVariableCacheContextToSmm (); > + if (!EFI_ERROR (Status)) { > + SyncRuntimeCache (); > + } > + } > + } > + } > + if (EFI_ERROR (Status)) { > + mVariableRuntimeHobCacheBuffer =3D NULL; > + mVariableRuntimeNvCacheBuffer =3D NULL; > + mVariableRuntimeVolatileCacheBuffer =3D NULL; > + } > + } > + ASSERT_EFI_ERROR (Status); > + } else { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"))= ; > + } > + > gRT->GetVariable =3D RuntimeServiceGetVariable; > gRT->GetNextVariableName =3D RuntimeServiceGetNextVariableName; > gRT->SetVariable =3D RuntimeServiceSetVariable; > -- > 2.16.2.windows.1