From: "Wang, Jian J" <jian.j.wang@intel.com>
To: "Kubacki, Michael A" <michael.a.kubacki@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Bi, Dandan" <dandan.bi@intel.com>,
Ard Biesheuvel <ard.biesheuvel@linaro.org>,
"Dong, Eric" <eric.dong@intel.com>,
Laszlo Ersek <lersek@redhat.com>,
"Gao, Liming" <liming.gao@intel.com>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
"Ni, Ray" <ray.ni@intel.com>, "Wu, Hao A" <hao.a.wu@intel.com>,
"Yao, Jiewen" <jiewen.yao@intel.com>
Subject: Re: [PATCH V7 07/10] MdeModulePkg/Variable: Add RT GetVariable() cache support
Date: Sat, 2 Nov 2019 01:36:24 +0000 [thread overview]
Message-ID: <D827630B58408649ACB04F44C5100036259A75C9@SHSMSX107.ccr.corp.intel.com> (raw)
In-Reply-To: <20191101173457.11956-8-michael.a.kubacki@intel.com>
I've given R-b for other patches in this series. I just give R-b this one which is only changed
in v7.
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Kubacki, Michael A <michael.a.kubacki@intel.com>
> Sent: Saturday, November 02, 2019 1:35 AM
> To: devel@edk2.groups.io
> Cc: Bi, Dandan <dandan.bi@intel.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Dong, Eric <eric.dong@intel.com>; Laszlo Ersek
> <lersek@redhat.com>; Gao, Liming <liming.gao@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>
> Subject: [PATCH V7 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.bi@intel.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Signed-off-by: Michael Kubacki <michael.a.kubacki@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.inf |
> 18 +-
> 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 | 189
> +++++++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c |
> 512 +++++++++++++++++++-
> 12 files changed, 1011 insertions(+), 41 deletions(-)
>
> diff --git a/MdeModulePkg/MdeModulePkg.dec
> b/MdeModulePkg/MdeModulePkg.dec
> index d6bac974da..3ef8fe7644 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -641,6 +641,18 @@
> # @Prompt Enable Device Path From Text support.
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText
> |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|FALSE|B
> OOLEAN|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/VariableSmmRuntimeDxe.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> index 14894e6f13..a250533a53 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> @@ -13,7 +13,7 @@
> # may not be modified without authorization. If platform fails to protect these
> resources,
> # the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> #
> -# Copyright (c) 2010 - 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,8 @@
> VariableSmmRuntimeDxe.c
> PrivilegePolymorphic.h
> Measurement.c
> + VariableParsing.c
> + VariableParsing.h
>
> [Packages]
> MdePkg/MdePkg.dec
> @@ -65,7 +67,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.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> index f8a3742959..6e17f6cdf5 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> +++
> 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.VariableRuntimeVolatileCache,
> + 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.VariableRuntimeVolatileCache);
> + } 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.Stor
> e != NULL) {
> + Status = SynchronizeRuntimeVariableCache (
> + &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
> + 0,
> + mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor
> e->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..caca5c3241 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,154 @@ 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"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (mEndOfDxe) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init
> context after end of DXE!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> +
> + //
> + // Copy the input communicate buffer payload to the pre-allocated SMM
> variable payload buffer.
> + //
> + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data,
> CommBufferPayloadSize);
> + RuntimeVariableCacheContext =
> (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *)
> mVariableBufferPayload;
> +
> + //
> + // Verify required runtime cache buffers are provided.
> + //
> + if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL ||
> + RuntimeVariableCacheContext->RuntimeNvCache == NULL ||
> + RuntimeVariableCacheContext->PendingUpdate == NULL ||
> + RuntimeVariableCacheContext->ReadLock == NULL ||
> + RuntimeVariableCacheContext->HobFlushComplete == NULL) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required
> runtime cache buffer is NULL!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> +
> + //
> + // Verify minimum size requirements for the runtime variable store buffers.
> + //
> + if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
> + RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof
> (VARIABLE_STORE_HEADER)) ||
> + RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof
> (VARIABLE_STORE_HEADER) ||
> + RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof
> (VARIABLE_STORE_HEADER)) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime
> cache buffer size is invalid!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> +
> + //
> + // Verify runtime buffers do not overlap with SMRAM ranges.
> + //
> + if (RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
> + !VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->RuntimeHobCache,
> + (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> HOB cache buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (!VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache,
> + (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> volatile cache buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (!VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->RuntimeNvCache,
> + (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> non-volatile cache buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (!VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->PendingUpdate,
> + sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> cache pending update buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (!VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->ReadLock,
> + sizeof (*(RuntimeVariableCacheContext->ReadLock)))) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> cache read lock buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> + if (!VariableSmmIsBufferOutsideSmmValid (
> + (UINTN) RuntimeVariableCacheContext->HobFlushComplete,
> + sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) {
> + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime
> cache HOB flush complete buffer in SMRAM or overflow!\n"));
> + Status = EFI_ACCESS_DENIED;
> + goto EXIT;
> + }
> +
> + VariableCacheContext = &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext;
> + 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
> + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset =
> 0;
> + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength =
> 0;
> + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 &&
> + VariableCacheContext->VariableRuntimeHobCache.Store != NULL) {
> + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN)
> mVariableModuleGlobal->VariableGlobal.HobVariableBase;
> + 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/VariableSmmRuntimeDxe.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> index 0a1888e5ef..3dee05fded 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> @@ -13,7 +13,7 @@
>
> InitCommunicateBuffer() is really function to check the variable data size.
>
> -Copyright (c) 2010 - 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 ()) {
> + FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES
> (mVariableRuntimeHobCacheBufferSize));
> + }
> + 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 (EFI_OPTIONAL_PTR, (VOID **)
> &mVariableRuntimeHobCacheBuffer);
> + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)
> &mVariableRuntimeNvCacheBuffer);
> + EfiConvertPointer (EFI_OPTIONAL_PTR, (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);
> +
> + 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
next prev parent reply other threads:[~2019-11-02 1:36 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-01 17:34 [PATCH V7 00/10] UEFI Variable SMI Reduction Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 01/10] MdeModulePkg/Variable: Consolidate common parsing functions Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 02/10] MdeModulePkg/Variable: Parameterize GetNextVariableInternal () stores Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 03/10] MdeModulePkg/Variable: Parameterize VARIABLE_INFO_ENTRY buffer Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 04/10] MdeModulePkg/Variable: Parameterize auth status in VariableParsing Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 05/10] MdeModulePkg/Variable: Add a file for NV variable functions Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 06/10] MdeModulePkg VariableInfo: Always consider RT DXE and SMM stats Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 07/10] MdeModulePkg/Variable: Add RT GetVariable() cache support Kubacki, Michael A
2019-11-02 1:36 ` Wang, Jian J [this message]
2019-11-01 17:34 ` [PATCH V7 08/10] MdeModulePkg/Variable: Add RT GetNextVariableName() " Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 09/10] OvmfPkg: Disable variable runtime cache Kubacki, Michael A
2019-11-01 17:34 ` [PATCH V7 10/10] MdeModulePkg: Enable variable runtime cache by default Kubacki, Michael A
2019-11-01 22:19 ` [PATCH V7 00/10] UEFI Variable SMI Reduction Laszlo Ersek
2019-11-01 23:17 ` Kubacki, Michael A
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=D827630B58408649ACB04F44C5100036259A75C9@SHSMSX107.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox