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]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to