Again, I would like to ask for help from other reviewers to look at this patch (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, could you help to double confirm? Another general level comment is that: Please help to update the MdeModulePkg.uni file as well for the introduce of the new PCD. Inline comments below: > -----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; Kinney, > Michael D; Ni, Ray; Wang, Jian J; Wu, Hao A; Yao, Jiewen > Subject: [PATCH V4 07/10] MdeModulePkg/Variable: Add RT GetVariable() > cache support > > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2220 > > 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. > > 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. > > The following are important points regarding the behavior of the > variable drivers when the variable runtime cache is enabled. > > 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. > > 2. SetVariable () requests will continue to always trigger an SMI. > This occurs regardless of whether the variable is volatile or > non-volatile. > > 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. > > 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. > > 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. > > 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 outside > SMRAM. > > 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 that > it is not expected a Runtime services call will interrupt SMM processing > since all CPU cores rendezvous in SMM. > > 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 number > of GetVariable () hits from the Runtime DXE variable driver (Runtime Cache > hits) and the SMM variable driver (SMM Cache hits). SMM Cache hits for > GetVariable () will occur when SMM modules invoke GetVariable (). > > Cc: Dandan Bi <dandan...@intel.com> > Cc: Ard Biesheuvel <ard.biesheu...@linaro.org> > Cc: Eric Dong <eric.d...@intel.com> > Cc: Laszlo Ersek <ler...@redhat.com> > Cc: Liming Gao <liming....@intel.com> > Cc: Michael D Kinney <michael.d.kin...@intel.com> > Cc: Ray Ni <ray...@intel.com> > Cc: Jian J Wang <jian.j.w...@intel.com> > Cc: Hao A Wu <hao.a...@intel.com> > Cc: Jiewen Yao <jiewen....@intel.com> > Signed-off-by: Michael Kubacki <michael.a.kuba...@intel.com> > --- > MdeModulePkg/MdeModulePkg.dec | 12 + > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf > | 2 + > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 2 > + > > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.i > nf | 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 | 114 > ++++- > > MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe. > c | 512 +++++++++++++++++++- > 12 files changed, 938 insertions(+), 41 deletions(-) > > 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. > > gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFrom > Text|TRUE|BOOLEAN|0x00010038 > > + ## Indicates if the UEFI variable runtime cache should be enabled. > + # This setting only applies if SMM variables are enabled. When enabled, > all > variable > + # data for Runtime Service GetVariable () and GetNextVariableName () > calls is retrieved > + # from a runtime data buffer referred to as the "runtime cache". An SMI is > not triggered > + # at all for these requests. Variables writes still trigger an SMI. This > can > greatly > + # reduce overall system SMM usage as most boots tend to issue far more > variable reads > + # than writes.<BR><BR> > + # TRUE - The UEFI variable runtime cache is enabled.<BR> > + # FALSE - The UEFI variable runtime cache is disabled.<BR> > + # @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 protect > these resources, > # the authentication service provided in this driver will be broken, and the > behavior is undefined. > # > -# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR> > +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR> > # 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 > > [Packages] > MdePkg/MdePkg.dec > @@ -65,7 +69,21 @@ > gEdkiiVariableLockProtocolGuid ## PRODUCES > gEdkiiVarCheckProtocolGuid ## PRODUCES > > +[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. > > -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -9,6 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #ifndef _SMM_VARIABLE_COMMON_H_ > #define _SMM_VARIABLE_COMMON_H_ > > +#include <Guid/VariableFormat.h> > #include <Protocol/VarCheck.h> > > #define EFI_SMM_VARIABLE_WRITE_GUID \ > @@ -66,6 +67,16 @@ typedef struct { > #define > SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 > > #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 > > /// > /// Size of SMM communicate header, without including the payload. > @@ -120,4 +131,20 @@ typedef struct { > UINTN VariablePayloadSize; > } SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE; > > +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; > > +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; > > 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; > > 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.<BR> > +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 not > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated > successfully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ); > + > +/** > + Synchronizes the runtime variable caches with all pending updates outside > 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 ReadLock > is available. Otherwise, the > + update is added as a pending update for the given variable store and it > 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 update > successfully. If the variable runtime > + cache ReadLock was available, the runtime > cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is not > 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" > > VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; > > @@ -332,6 +333,12 @@ RecordVarErrorFlag ( > // Update the data in NV cache. > // > *VarErrFlag = TempFlag; > + Status = SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) > mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, > + sizeof (TempFlag) > + ); > + ASSERT_EFI_ERROR (Status); > } > } > } > @@ -766,12 +773,24 @@ Reclaim ( > > Done: > if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + Status = 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, so > copy the data back. > // > - CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, > VariableStoreHeader->Size); > + CopyMem (mNvVariableCache, (UINT8 *) (UINTN) VariableBase, > VariableStoreHeader->Size); > + Status = SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + 0, > + VariableStoreHeader->Size > + ); > + ASSERT_EFI_ERROR (Status); > } > > 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 ( > } > > Done: > + if (!EFI_ERROR (Status)) { > + if (Variable->Volatile) { > + VolatileCacheInstance = &(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCach > e); > + } else { > + VolatileCacheInstance = &(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache); > + } > + > + if (VolatileCacheInstance->Store != NULL) { > + Status = SynchronizeRuntimeVariableCache ( > + VolatileCacheInstance, > + 0, > + VolatileCacheInstance->Store->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + } > + > return Status; > } > > @@ -3200,6 +3237,14 @@ FlushHobVariableToFlash ( > ErrorFlag = TRUE; > } > } > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.S > tore != NULL) { > + Status = 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 != NULL) > { > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = 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 file > 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 input in > SMM mode. > + This external input must be validated carefully to avoid security issue > like > + buffer overflow, integer overflow. > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> > +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 not > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated > successfully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ) > +{ > + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext; > + > + VariableRuntimeCacheContext = &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + > + if (VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == > NULL || > + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == > NULL || > + VariableRuntimeCacheContext->PendingUpdate == NULL) { > + return EFI_UNSUPPORTED; > + } > + > + if (*(VariableRuntimeCacheContext->PendingUpdate)) { > + if (VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != > 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 = 0; > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset = 0; > + } > + > + CopyMem ( > + (VOID *) ( > + ((UINT8 *) (UINTN) VariableRuntimeCacheContext- > >VariableRuntimeNvCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + (VOID *) ( > + ((UINT8 *) (UINTN) mNvVariableCache) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength = 0; > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset = 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 = 0; > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset = 0; > + *(VariableRuntimeCacheContext->PendingUpdate) = FALSE; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Synchronizes the runtime variable caches with all pending updates outside > 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 ReadLock > is available. Otherwise, the > + update is added as a pending update for the given variable store and it > 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 update > successfully. If the variable runtime > + cache ReadLock was available, the runtime > cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is not > initialized properly. > + > +**/ > +EFI_STATUS > +SynchronizeRuntimeVariableCache ( > + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, > + IN UINTN Offset, > + IN UINTN Length > + ) > +{ > + if (VariableRuntimeCache == NULL) { > + return EFI_INVALID_PARAMETER; > + } else if (VariableRuntimeCache->Store == NULL) { > + // The runtime cache may not be active or allocated yet. > + // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET. > + return EFI_SUCCESS; > + } > + > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL || > + mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL) { > + return EFI_UNSUPPORTED; > + } > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) && > + VariableRuntimeCache->PendingUpdateLength > 0) { > + VariableRuntimeCache->PendingUpdateLength = > + (UINT32) ( > + MAX ( > + (UINTN) (VariableRuntimeCache->PendingUpdateOffset + > VariableRuntimeCache->PendingUpdateLength), > + Offset + Length > + ) - MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset) > + ); > + VariableRuntimeCache->PendingUpdateOffset = > + (UINT32) MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, > Offset); > + } else { > + VariableRuntimeCache->PendingUpdateLength = (UINT32) Length; > + VariableRuntimeCache->PendingUpdateOffset = (UINT32) Offset; > + } > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE; > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock) == 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 <Guid/SmmVariableCommon.h> > #include "Variable.h" > #include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +extern VARIABLE_STORE_HEADER *mNvVariableCache; > > BOOLEAN mAtRuntime > = FALSE; > UINT8 *mVariableBufferPayload > = 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 *RegisterContext, > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommBufferSize > ) > { > - 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 > CommBufferPayloadSize; > + UINTN TempCommBufferSize; > > // > // 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 = > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *) SmmVariableFunctionHeader->Data; > + VariableCacheContext = &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + > + ASSERT (RuntimeVariableCacheContext->RuntimeVolatileCache != > NULL); > + ASSERT (RuntimeVariableCacheContext->RuntimeNvCache != NULL); > + ASSERT (RuntimeVariableCacheContext->PendingUpdate != NULL); > + ASSERT (RuntimeVariableCacheContext->ReadLock != NULL); > + ASSERT (RuntimeVariableCacheContext->HobFlushComplete != NULL); > + > + VariableCacheContext->VariableRuntimeHobCache.Store = > RuntimeVariableCacheContext->RuntimeHobCache; > + VariableCacheContext->VariableRuntimeVolatileCache.Store = > RuntimeVariableCacheContext->RuntimeVolatileCache; > + VariableCacheContext->VariableRuntimeNvCache.Store = > RuntimeVariableCacheContext->RuntimeNvCache; > + VariableCacheContext->PendingUpdate = > RuntimeVariableCacheContext->PendingUpdate; > + VariableCacheContext->ReadLock = > RuntimeVariableCacheContext->ReadLock; > + VariableCacheContext->HobFlushComplete = > RuntimeVariableCacheContext->HobFlushComplete; > + > + // Set up the intial pending request since the RT cache needs to be > in > sync with SMM cache > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset = 0; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength = 0; > + } else { > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset = 0; > + VariableCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext- > >VariableRuntimeHobCache.Store->Signature), &(VariableCache- > >Signature)); > + } > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset = 0; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext- > >VariableRuntimeVolatileCache.Store->Signature), &(VariableCache- > >Signature)); > + > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mNvVariableCache; > + VariableCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset = 0; > + VariableCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) > GetEndPointer (VariableCache) - (UINTN) VariableCache); > + CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store- > >Signature), &(VariableCache->Signature)); > + > + *(VariableCacheContext->PendingUpdate) = TRUE; > + *(VariableCacheContext->ReadLock) = FALSE; > + *(VariableCacheContext->HobFlushComplete) = FALSE; > + } > + Status = EFI_SUCCESS; > + break; > + case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE: > + Status = 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 = > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) > SmmVariableFunctionHeader->Data; > + > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size; > + } else { > + GetRuntimeCacheInfo->TotalHobStorageSize = 0; > + } > + > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size; > + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) > mNvVariableCache; > + GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache- > >Size; > + GetRuntimeCacheInfo->AuthenticatedVariableUsage = > mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + Status = EFI_SUCCESS; > + break; > > default: > Status = 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 @@ > > InitCommunicateBuffer() is really function to check the variable data size. > > -Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -39,6 +39,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #include <Guid/SmmVariableCommon.h> > > #include "PrivilegePolymorphic.h" > +#include "VariableParsing.h" > > EFI_HANDLE mHandle = NULL; > EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; > @@ -46,8 +47,19 @@ EFI_EVENT > mVirtualAddressChangeEvent = > NULL; > EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = > NULL; > UINT8 *mVariableBuffer = NULL; > UINT8 *mVariableBufferPhysical = NULL; > +VARIABLE_INFO_ENTRY *mVariableInfo = NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = > NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = > NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer > = 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 ( > } > } > > +/** > + 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 cache > variable store. > + @param[in,out] TotalVariableCacheSize On input, the minimum size > needed for the UEFI variable store cache > + buffer that is allocated. On > output, the actual size of > the buffer allocated. > + If TotalVariableCacheSize is zero, > a buffer will not be > allocated and the > + function will return with > EFI_SUCCESS. > + > + @retval EFI_SUCCESS The variable cache was allocated and > initialized > 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 to > allocate the variable store cache buffer. > + > +**/ > +EFI_STATUS > +InitVariableCache ( > + OUT VARIABLE_STORE_HEADER **VariableCacheBuffer, > + IN OUT UINTN *TotalVariableCacheSize > + ) > +{ > + VARIABLE_STORE_HEADER *VariableCacheStorePtr; > + > + if (TotalVariableCacheSize == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (*TotalVariableCacheSize == 0) { > + return EFI_SUCCESS; > + } > + if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof > (VARIABLE_STORE_HEADER)) { > + return EFI_INVALID_PARAMETER; > + } > + *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof > (UINT32)); > + > + // > + // Allocate NV Storage Cache and initialize it to all 1's (like an erased > FV) > + // > + *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) > AllocateRuntimePages ( > + EFI_SIZE_TO_PAGES (*TotalVariableCacheSize) > + ); > + if (*VariableCacheBuffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + VariableCacheStorePtr = *VariableCacheBuffer; > + SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, > (UINT32) 0xFFFFFFFF); > + > + ZeroMem ((VOID *) VariableCacheStorePtr, sizeof > (VARIABLE_STORE_HEADER)); > + VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize; > + VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED; > + VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY; > + > + return EFI_SUCCESS; > +} > + > /** > Initialize the communicate buffer using DataSize and Function. > > @@ -425,7 +503,169 @@ Done: > } > > /** > - 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 updates. > + > + If the variable HOB was finished being flushed since the last check for a > runtime cache update, this function > + will prevent the HOB cache from being used for future runtime cache hits. > + > +**/ > +VOID > +CheckForRuntimeCacheSync ( > + VOID > + ) > +{ > + if (mVariableRuntimeCachePendingUpdate) { > + SyncRuntimeCache (); > + } > + ASSERT (!mVariableRuntimeCachePendingUpdate); > + > + // > + // The HOB variable data may have finished being flushed in the runtime > cache sync update > + // > + if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) { > + if (!EfiAtRuntime ()) { > + FreePool (mVariableRuntimeHobCacheBuffer); > + } > + mVariableRuntimeHobCacheBuffer = 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 > carefully to > avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable found. > + @param[in, out] DataSize Size of Data found. If size is less > than the > + data, this value contains the required > size. > + @param[out] Data Data pointer. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be > found. > + > +**/ > +EFI_STATUS > +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 = EFI_NOT_FOUND; > + > + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The UEFI specification restricts Runtime Services callers from invoking > 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 = 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] = > mVariableRuntimeVolatileCacheBuffer; > + VariableStoreList[VariableStoreTypeHob] = > mVariableRuntimeHobCacheBuffer; > + VariableStoreList[VariableStoreTypeNv] = > mVariableRuntimeNvCacheBuffer; > + > + for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < > VariableStoreTypeMax; StoreType++) { > + if (VariableStoreList[StoreType] == NULL) { > + continue; > + } > + > + RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]); > + RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]); > + RtPtrTrack.Volatile = (BOOLEAN) (StoreType == > VariableStoreTypeVolatile); > + > + Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, > mVariableAuthFormat); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // Get data size > + // > + TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, > mVariableAuthFormat); > + ASSERT (TempDataSize != 0); > + > + if (*DataSize >= TempDataSize) { > + if (Data == NULL) { > + Status = EFI_INVALID_PARAMETER; > + goto Done; > + } > + > + CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, > mVariableAuthFormat), TempDataSize); > + if (Attributes != NULL) { > + *Attributes = RtPtrTrack.CurrPtr->Attributes; > + } > + > + *DataSize = TempDataSize; > + > + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, > TRUE, FALSE, FALSE, TRUE, &mVariableInfo); > + > + Status = EFI_SUCCESS; > + goto Done; > + } else { > + *DataSize = TempDataSize; > + Status = EFI_BUFFER_TOO_SMALL; > + goto Done; > + } > + } > + } > + > +Done: > + mVariableRuntimeCacheReadLock = FALSE; > + > + return Status; > +} > + > +/** > + Finds the given variable in a variable store in SMM. > > Caution: This function may receive untrusted input. > The data size is external input, so this function will validate it > carefully to > avoid buffer overflow. > @@ -437,20 +677,18 @@ Done: > data, this value contains the required > size. > @param[out] Data Data pointer. > > + @retval EFI_SUCCESS Found the specified variable. > @retval EFI_INVALID_PARAMETER Invalid parameter. > - @retval EFI_SUCCESS Find the specified variable. > - @retval EFI_NOT_FOUND Not found. > - @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. > + @retval EFI_NOT_FOUND The specified variable could not be > found. > > **/ > 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; > } > > - 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 = OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > VariableNameSize + TempDataSize; > > - Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, > PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); > + Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, > PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); > if (EFI_ERROR (Status)) { > goto Done; > } > @@ -534,11 +770,58 @@ RuntimeServiceGetVariable ( > } > > 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 > carefully to > avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable found. > + @param[in, out] DataSize Size of Data found. If size is less > than the > + data, this value contains the required > size. > + @param[out] Data Data pointer. > + > + @retval EFI_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 result. > + > +**/ > +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 == NULL || VendorGuid == NULL || DataSize == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (VariableName[0] == 0) { > + return EFI_NOT_FOUND; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + Status = FindVariableInRuntimeCache (VariableName, VendorGuid, > Attributes, DataSize, Data); > + } else { > + Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, > DataSize, Data); > + } > ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + > return Status; > } > > - > /** > This code Finds the Next available variable. > > @@ -870,6 +1153,17 @@ OnReadyToBoot ( > // > SendCommunicateBuffer (0); > > + // > + // Install the system configuration table for variable info data captured > + // > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet > (PcdVariableCollectStatistics)) { > + if (mVariableAuthFormat) { > + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, > mVariableInfo); > + } else { > + gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo); > + } > + } > + > gBS->CloseEvent (Event); > } > > @@ -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); > } > > /** > @@ -969,6 +1266,159 @@ Done: > return Status; > } > > +/** > + This code gets information needed from SMM for runtime cache > initialization. > + > + @param[out] TotalHobStorageSize Output pointer for the total HOB > storage size in bytes. > + @param[out] TotalNvStorageSize Output pointer for the total non- > 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 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 > successfully. > + > +**/ > +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 = NULL; > + CommBuffer = mVariableBuffer; > + > + if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || > TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (CommBuffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + CommSize = 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 = (EFI_SMM_COMMUNICATE_HEADER *) > CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength = > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); > + > + SmmVariableFunctionHeader = > (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader- > >Data; > + SmmVariableFunctionHeader->Function = > SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO; > + SmmGetRuntimeCacheInfo = > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) > SmmVariableFunctionHeader->Data; > + > + // > + // Send data to SMM. > + // > + Status = mSmmCommunication->Communicate (mSmmCommunication, > CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status = EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status = SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data from SMM. > + // > + *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize; > + *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize; > + *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo- > >TotalVolatileStorageSize; > + *AuthenticatedVariableUsage = 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 > successfully.; > + > +**/ > +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 = NULL; > + CommBuffer = mVariableBuffer; > + > + if (CommBuffer == 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 = SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + ZeroMem (CommBuffer, CommSize); > + > + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) > CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength = > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + > + SmmVariableFunctionHeader = > (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader- > >Data; > + SmmVariableFunctionHeader->Function = > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT; > + SmmRuntimeVarCacheContext = > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *) SmmVariableFunctionHeader->Data; > + > + SmmRuntimeVarCacheContext->RuntimeHobCache = > mVariableRuntimeHobCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeVolatileCache = > mVariableRuntimeVolatileCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeNvCache = > mVariableRuntimeNvCacheBuffer; > + SmmRuntimeVarCacheContext->PendingUpdate = > &mVariableRuntimeCachePendingUpdate; > + SmmRuntimeVarCacheContext->ReadLock = > &mVariableRuntimeCacheReadLock; > + SmmRuntimeVarCacheContext->HobFlushComplete = > &mHobFlushComplete; > + > + // > + // Send data to SMM. > + // > + Status = mSmmCommunication->Communicate (mSmmCommunication, > CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status = EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status = SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > /** > Initialize variable service and install Variable Architectural protocol. > > @@ -985,7 +1435,7 @@ SmmVariableReady ( > { > EFI_STATUS Status; > > - Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, > (VOID **)&mSmmVariable); > + Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, > (VOID **) &mSmmVariable); > if (EFI_ERROR (Status)) { > return; > } > @@ -1007,6 +1457,42 @@ SmmVariableReady ( > // > mVariableBufferPhysical = mVariableBuffer; > > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n")); > + // > + // Allocate runtime variable cache memory buffers. > + // > + Status = GetRuntimeCacheInfo ( > + &mVariableRuntimeHobCacheBufferSize, > + &mVariableRuntimeNvCacheBufferSize, > + &mVariableRuntimeVolatileCacheBufferSize, > + &mVariableAuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, > &mVariableRuntimeHobCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, > &mVariableRuntimeNvCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, > &mVariableRuntimeVolatileCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status = SendRuntimeVariableCacheContextToSmm (); > + if (!EFI_ERROR (Status)) { > + SyncRuntimeCache (); > + } > + } > + } > + } > + if (EFI_ERROR (Status)) { > + mVariableRuntimeHobCacheBuffer = NULL; > + mVariableRuntimeNvCacheBuffer = NULL; > + mVariableRuntimeVolatileCacheBuffer = NULL; > + } > + } > + ASSERT_EFI_ERROR (Status); > + } else { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n")); > + } > + > gRT->GetVariable = RuntimeServiceGetVariable; > gRT->GetNextVariableName = RuntimeServiceGetNextVariableName; > gRT->SetVariable = RuntimeServiceSetVariable; > -- > 2.16.2.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#49071): https://edk2.groups.io/g/devel/message/49071 Mute This Topic: https://groups.io/mt/34540094/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-