]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
index 0a076ae4675ad6167869fff58aca7c51bcbb66d4..4aaeb5ba8806eb323582762f9cce6b0c280c8c3e 100644 (file)
 \r
   InitCommunicateBuffer() is really function to check the variable data size.\r
 \r
-Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) Microsoft Corporation.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 #include <PiDxe.h>\r
 #include <Protocol/VariableWrite.h>\r
 #include <Protocol/Variable.h>\r
-#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/MmCommunication2.h>\r
 #include <Protocol/SmmVariable.h>\r
 #include <Protocol/VariableLock.h>\r
 #include <Protocol/VarCheck.h>\r
@@ -40,34 +35,57 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/DebugLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/BaseLib.h>\r
+#include <Library/MmUnblockMemoryLib.h>\r
 \r
 #include <Guid/EventGroup.h>\r
 #include <Guid/SmmVariableCommon.h>\r
 \r
-EFI_HANDLE                       mHandle                    = NULL;\r
-EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;\r
-EFI_EVENT                        mVirtualAddressChangeEvent = NULL;\r
-EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;\r
-UINT8                           *mVariableBuffer            = NULL;\r
-UINT8                           *mVariableBufferPhysical    = NULL;\r
-UINTN                            mVariableBufferSize;\r
-UINTN                            mVariableBufferPayloadSize;\r
-EFI_LOCK                         mVariableServicesLock;\r
-EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;\r
-EDKII_VAR_CHECK_PROTOCOL         mVarCheck;\r
+#include "PrivilegePolymorphic.h"\r
+#include "VariableParsing.h"\r
+\r
+EFI_HANDLE                      mHandle                              = NULL;\r
+EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable                        = NULL;\r
+EFI_EVENT                       mVirtualAddressChangeEvent           = NULL;\r
+EFI_MM_COMMUNICATION2_PROTOCOL  *mMmCommunication2                   = NULL;\r
+UINT8                           *mVariableBuffer                     = NULL;\r
+UINT8                           *mVariableBufferPhysical             = NULL;\r
+VARIABLE_INFO_ENTRY             *mVariableInfo                       = NULL;\r
+VARIABLE_STORE_HEADER           *mVariableRuntimeHobCacheBuffer      = NULL;\r
+VARIABLE_STORE_HEADER           *mVariableRuntimeNvCacheBuffer       = NULL;\r
+VARIABLE_STORE_HEADER           *mVariableRuntimeVolatileCacheBuffer = NULL;\r
+UINTN                           mVariableBufferSize;\r
+UINTN                           mVariableRuntimeHobCacheBufferSize;\r
+UINTN                           mVariableRuntimeNvCacheBufferSize;\r
+UINTN                           mVariableRuntimeVolatileCacheBufferSize;\r
+UINTN                           mVariableBufferPayloadSize;\r
+BOOLEAN                         mVariableRuntimeCachePendingUpdate;\r
+BOOLEAN                         mVariableRuntimeCacheReadLock;\r
+BOOLEAN                         mVariableAuthFormat;\r
+BOOLEAN                         mHobFlushComplete;\r
+EFI_LOCK                        mVariableServicesLock;\r
+EDKII_VARIABLE_LOCK_PROTOCOL    mVariableLock;\r
+EDKII_VAR_CHECK_PROTOCOL        mVarCheck;\r
 \r
 /**\r
-  SecureBoot Hook for SetVariable.\r
+  The logic to initialize the VariablePolicy engine is in its own file.\r
 \r
-  @param[in] VariableName                 Name of Variable to be found.\r
-  @param[in] VendorGuid                   Variable vendor GUID.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariablePolicySmmDxeMain (\r
+  IN    EFI_HANDLE        ImageHandle,\r
+  IN    EFI_SYSTEM_TABLE  *SystemTable\r
+  );\r
+\r
+/**\r
+  Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).\r
+  Record their initial State when variable write service is ready.\r
 \r
 **/\r
 VOID\r
 EFIAPI\r
-SecureBootHook (\r
-  IN CHAR16                                 *VariableName,\r
-  IN EFI_GUID                               *VendorGuid\r
+RecordSecureBootPolicyVarData (\r
+  VOID\r
   );\r
 \r
 /**\r
@@ -84,7 +102,7 @@ SecureBootHook (
 **/\r
 VOID\r
 AcquireLockOnlyAtBootTime (\r
-  IN EFI_LOCK                             *Lock\r
+  IN EFI_LOCK  *Lock\r
   )\r
 {\r
   if (!EfiAtRuntime ()) {\r
@@ -106,7 +124,7 @@ AcquireLockOnlyAtBootTime (
 **/\r
 VOID\r
 ReleaseLockOnlyAtBootTime (\r
-  IN EFI_LOCK                             *Lock\r
+  IN EFI_LOCK  *Lock\r
   )\r
 {\r
   if (!EfiAtRuntime ()) {\r
@@ -114,6 +132,88 @@ ReleaseLockOnlyAtBootTime (
   }\r
 }\r
 \r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+\r
+  @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  )\r
+{\r
+  return EfiAtRuntime ();\r
+}\r
+\r
+/**\r
+  Initialize the variable cache buffer as an empty variable store.\r
+\r
+  @param[out]     VariableCacheBuffer     A pointer to pointer of a cache variable store.\r
+  @param[in,out]  TotalVariableCacheSize  On input, the minimum size needed for the UEFI variable store cache\r
+                                          buffer that is allocated. On output, the actual size of the buffer allocated.\r
+                                          If TotalVariableCacheSize is zero, a buffer will not be allocated and the\r
+                                          function will return with EFI_SUCCESS.\r
+\r
+  @retval EFI_SUCCESS             The variable cache was allocated and initialized successfully.\r
+  @retval EFI_INVALID_PARAMETER   A given pointer is NULL or an invalid variable store size was specified.\r
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available to allocate the variable store cache buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+InitVariableCache (\r
+  OUT    VARIABLE_STORE_HEADER  **VariableCacheBuffer,\r
+  IN OUT UINTN                  *TotalVariableCacheSize\r
+  )\r
+{\r
+  VARIABLE_STORE_HEADER  *VariableCacheStorePtr;\r
+  EFI_STATUS             Status;\r
+\r
+  if (TotalVariableCacheSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*TotalVariableCacheSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((VariableCacheBuffer == NULL) || (*TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));\r
+\r
+  //\r
+  // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)\r
+  //\r
+  *VariableCacheBuffer =  (VARIABLE_STORE_HEADER *)AllocateRuntimePages (\r
+                                                     EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)\r
+                                                     );\r
+  if (*VariableCacheBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Request to unblock the newly allocated cache region to be accessible from inside MM\r
+  //\r
+  Status = MmUnblockMemoryRequest (\r
+             (EFI_PHYSICAL_ADDRESS)(UINTN)*VariableCacheBuffer,\r
+             EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)\r
+             );\r
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  VariableCacheStorePtr = *VariableCacheBuffer;\r
+  SetMem32 ((VOID *)VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32)0xFFFFFFFF);\r
+\r
+  ZeroMem ((VOID *)VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));\r
+  VariableCacheStorePtr->Size   = (UINT32)*TotalVariableCacheSize;\r
+  VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;\r
+  VariableCacheStorePtr->State  = VARIABLE_STORE_HEALTHY;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Initialize the communicate buffer using DataSize and Function.\r
 \r
@@ -133,24 +233,23 @@ ReleaseLockOnlyAtBootTime (
 **/\r
 EFI_STATUS\r
 InitCommunicateBuffer (\r
-  OUT     VOID                              **DataPtr OPTIONAL,\r
-  IN      UINTN                             DataSize,\r
-  IN      UINTN                             Function\r
+  OUT     VOID   **DataPtr OPTIONAL,\r
+  IN      UINTN  DataSize,\r
+  IN      UINTN  Function\r
   )\r
 {\r
-  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
-  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
-\r
+  EFI_MM_COMMUNICATE_HEADER        *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER  *SmmVariableFunctionHeader;\r
 \r
   if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)mVariableBuffer;\r
   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
   SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
 \r
-  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
   SmmVariableFunctionHeader->Function = Function;\r
   if (DataPtr != NULL) {\r
     *DataPtr = SmmVariableFunctionHeader->Data;\r
@@ -159,7 +258,6 @@ InitCommunicateBuffer (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
   Send the data in communicate buffer to SMM.\r
 \r
@@ -171,21 +269,26 @@ InitCommunicateBuffer (
 **/\r
 EFI_STATUS\r
 SendCommunicateBuffer (\r
-  IN      UINTN                             DataSize\r
+  IN      UINTN  DataSize\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  UINTN                                     CommSize;\r
-  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
-  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
+  EFI_STATUS                       Status;\r
+  UINTN                            CommSize;\r
+  EFI_MM_COMMUNICATE_HEADER        *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER  *SmmVariableFunctionHeader;\r
 \r
   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
-  Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
+  Status   = mMmCommunication2->Communicate (\r
+                                  mMmCommunication2,\r
+                                  mVariableBufferPhysical,\r
+                                  mVariableBuffer,\r
+                                  &CommSize\r
+                                  );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  SmmCommunicateHeader      = (EFI_MM_COMMUNICATE_HEADER *)mVariableBuffer;\r
   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
-  return  SmmVariableFunctionHeader->ReturnStatus;\r
+  return SmmVariableFunctionHeader->ReturnStatus;\r
 }\r
 \r
 /**\r
@@ -206,17 +309,17 @@ SendCommunicateBuffer (
 EFI_STATUS\r
 EFIAPI\r
 VariableLockRequestToLock (\r
-  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
-  IN       CHAR16                       *VariableName,\r
-  IN       EFI_GUID                     *VendorGuid\r
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,\r
+  IN       CHAR16                        *VariableName,\r
+  IN       EFI_GUID                      *VendorGuid\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  UINTN                                     VariableNameSize;\r
-  UINTN                                     PayloadSize;\r
-  SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE    *VariableToLock;\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   VariableNameSize;\r
+  UINTN                                   PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE  *VariableToLock;\r
 \r
-  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+  if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -230,17 +333,18 @@ VariableLockRequestToLock (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
 \r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
   //\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
-  Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
+  Status      = InitCommunicateBuffer ((VOID **)&VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (VariableToLock != NULL);\r
 \r
   CopyGuid (&VariableToLock->Guid, VendorGuid);\r
@@ -274,7 +378,7 @@ Done:
 EFI_STATUS\r
 EFIAPI\r
 VarCheckRegisterSetVariableCheckHandler (\r
-  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler\r
+  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER  Handler\r
   )\r
 {\r
   return EFI_UNSUPPORTED;\r
@@ -298,17 +402,17 @@ VarCheckRegisterSetVariableCheckHandler (
 EFI_STATUS\r
 EFIAPI\r
 VarCheckVariablePropertySet (\r
-  IN CHAR16                         *Name,\r
-  IN EFI_GUID                       *Guid,\r
-  IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty\r
+  IN CHAR16                       *Name,\r
+  IN EFI_GUID                     *Guid,\r
+  IN VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  UINTN                                     VariableNameSize;\r
-  UINTN                                     PayloadSize;\r
-  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
+  EFI_STATUS                                            Status;\r
+  UINTN                                                 VariableNameSize;\r
+  UINTN                                                 PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY  *CommVariableProperty;\r
 \r
-  if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+  if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -320,7 +424,7 @@ VarCheckVariablePropertySet (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  VariableNameSize = StrSize (Name);\r
+  VariableNameSize     = StrSize (Name);\r
   CommVariableProperty = NULL;\r
 \r
   //\r
@@ -337,10 +441,11 @@ VarCheckVariablePropertySet (
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
   //\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
-  Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);\r
+  Status      = InitCommunicateBuffer ((VOID **)&CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (CommVariableProperty != NULL);\r
 \r
   CopyGuid (&CommVariableProperty->Guid, Guid);\r
@@ -373,17 +478,17 @@ Done:
 EFI_STATUS\r
 EFIAPI\r
 VarCheckVariablePropertyGet (\r
-  IN CHAR16                         *Name,\r
-  IN EFI_GUID                       *Guid,\r
-  OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty\r
+  IN CHAR16                        *Name,\r
+  IN EFI_GUID                      *Guid,\r
+  OUT VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  UINTN                                     VariableNameSize;\r
-  UINTN                                     PayloadSize;\r
-  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
+  EFI_STATUS                                            Status;\r
+  UINTN                                                 VariableNameSize;\r
+  UINTN                                                 PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY  *CommVariableProperty;\r
 \r
-  if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+  if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -391,7 +496,7 @@ VarCheckVariablePropertyGet (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  VariableNameSize = StrSize (Name);\r
+  VariableNameSize     = StrSize (Name);\r
   CommVariableProperty = NULL;\r
 \r
   //\r
@@ -408,10 +513,11 @@ VarCheckVariablePropertyGet (
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
   //\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
-  Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);\r
+  Status      = InitCommunicateBuffer ((VOID **)&CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (CommVariableProperty != NULL);\r
 \r
   CopyGuid (&CommVariableProperty->Guid, Guid);\r
@@ -432,7 +538,58 @@ Done:
 }\r
 \r
 /**\r
-  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+  Signals SMM to synchronize any pending variable updates with the runtime cache(s).\r
+\r
+**/\r
+VOID\r
+SyncRuntimeCache (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+  //\r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  SendCommunicateBuffer (0);\r
+}\r
+\r
+/**\r
+  Check whether a SMI must be triggered to retrieve pending cache updates.\r
+\r
+  If the variable HOB was finished being flushed since the last check for a runtime cache update, this function\r
+  will prevent the HOB cache from being used for future runtime cache hits.\r
+\r
+**/\r
+VOID\r
+CheckForRuntimeCacheSync (\r
+  VOID\r
+  )\r
+{\r
+  if (mVariableRuntimeCachePendingUpdate) {\r
+    SyncRuntimeCache ();\r
+  }\r
+\r
+  ASSERT (!mVariableRuntimeCachePendingUpdate);\r
+\r
+  //\r
+  // The HOB variable data may have finished being flushed in the runtime cache sync update\r
+  //\r
+  if (mHobFlushComplete && (mVariableRuntimeHobCacheBuffer != NULL)) {\r
+    if (!EfiAtRuntime ()) {\r
+      FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));\r
+    }\r
+\r
+    mVariableRuntimeHobCacheBuffer = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+  Finds the given variable in a runtime cache variable store.\r
 \r
   Caution: This function may receive untrusted input.\r
   The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
@@ -444,20 +601,135 @@ Done:
                                      data, this value contains the required size.\r
   @param[out]     Data               Data pointer.\r
 \r
+  @retval EFI_SUCCESS                Found the specified variable.\r
   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
-  @retval EFI_SUCCESS                Find the specified variable.\r
-  @retval EFI_NOT_FOUND              Not found.\r
-  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+  @retval EFI_NOT_FOUND              The specified variable could not be found.\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-RuntimeServiceGetVariable (\r
-  IN      CHAR16                            *VariableName,\r
-  IN      EFI_GUID                          *VendorGuid,\r
-  OUT     UINT32                            *Attributes OPTIONAL,\r
-  IN OUT  UINTN                             *DataSize,\r
-  OUT     VOID                              *Data\r
+FindVariableInRuntimeCache (\r
+  IN      CHAR16    *VariableName,\r
+  IN      EFI_GUID  *VendorGuid,\r
+  OUT     UINT32    *Attributes OPTIONAL,\r
+  IN OUT  UINTN     *DataSize,\r
+  OUT     VOID      *Data OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   TempDataSize;\r
+  VARIABLE_POINTER_TRACK  RtPtrTrack;\r
+  VARIABLE_STORE_TYPE     StoreType;\r
+  VARIABLE_STORE_HEADER   *VariableStoreList[VariableStoreTypeMax];\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));\r
+\r
+  //\r
+  // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
+  // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
+  // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
+  // cache read lock should always be free when entering this function.\r
+  //\r
+  ASSERT (!mVariableRuntimeCacheReadLock);\r
+\r
+  mVariableRuntimeCacheReadLock = TRUE;\r
+  CheckForRuntimeCacheSync ();\r
+\r
+  if (!mVariableRuntimeCachePendingUpdate) {\r
+    //\r
+    // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
+    // The index and attributes mapping must be kept in this order as FindVariable\r
+    // makes use of this mapping to implement search algorithm.\r
+    //\r
+    VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
+    VariableStoreList[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;\r
+    VariableStoreList[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;\r
+\r
+    for (StoreType = (VARIABLE_STORE_TYPE)0; StoreType < VariableStoreTypeMax; StoreType++) {\r
+      if (VariableStoreList[StoreType] == NULL) {\r
+        continue;\r
+      }\r
+\r
+      RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);\r
+      RtPtrTrack.EndPtr   = GetEndPointer (VariableStoreList[StoreType]);\r
+      RtPtrTrack.Volatile = (BOOLEAN)(StoreType == VariableStoreTypeVolatile);\r
+\r
+      Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Get data size\r
+      //\r
+      TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);\r
+      ASSERT (TempDataSize != 0);\r
+\r
+      if (*DataSize >= TempDataSize) {\r
+        if (Data == NULL) {\r
+          Status = EFI_INVALID_PARAMETER;\r
+          goto Done;\r
+        }\r
+\r
+        CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);\r
+        *DataSize = TempDataSize;\r
+\r
+        UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);\r
+\r
+        Status = EFI_SUCCESS;\r
+        goto Done;\r
+      } else {\r
+        *DataSize = TempDataSize;\r
+        Status    = EFI_BUFFER_TOO_SMALL;\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {\r
+    if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {\r
+      *Attributes = RtPtrTrack.CurrPtr->Attributes;\r
+    }\r
+  }\r
+\r
+  mVariableRuntimeCacheReadLock = FALSE;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Finds the given variable in a variable store in SMM.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
+  @param[in]      VariableName       Name of Variable to be found.\r
+  @param[in]      VendorGuid         Variable vendor GUID.\r
+  @param[out]     Attributes         Attribute value of the variable found.\r
+  @param[in, out] DataSize           Size of Data found. If size is less than the\r
+                                     data, this value contains the required size.\r
+  @param[out]     Data               Data pointer.\r
+\r
+  @retval EFI_SUCCESS                Found the specified variable.\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_NOT_FOUND              The specified variable could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariableInSmm (\r
+  IN      CHAR16    *VariableName,\r
+  IN      EFI_GUID  *VendorGuid,\r
+  OUT     UINT32    *Attributes OPTIONAL,\r
+  IN OUT  UINTN     *DataSize,\r
+  OUT     VOID      *Data OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                                Status;\r
@@ -466,13 +738,13 @@ RuntimeServiceGetVariable (
   UINTN                                     TempDataSize;\r
   UINTN                                     VariableNameSize;\r
 \r
-  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  TempDataSize          = *DataSize;\r
-  VariableNameSize      = StrSize (VariableName);\r
-  SmmVariableHeader     = NULL;\r
+  TempDataSize      = *DataSize;\r
+  VariableNameSize  = StrSize (VariableName);\r
+  SmmVariableHeader = NULL;\r
 \r
   //\r
   // If VariableName exceeds SMM payload limit. Return failure\r
@@ -481,8 +753,6 @@ RuntimeServiceGetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
-\r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
@@ -493,22 +763,25 @@ RuntimeServiceGetVariable (
     //\r
     TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
   }\r
+\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
 \r
   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (SmmVariableHeader != NULL);\r
 \r
   CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
-  SmmVariableHeader->DataSize   = TempDataSize;\r
-  SmmVariableHeader->NameSize   = VariableNameSize;\r
+  SmmVariableHeader->DataSize = TempDataSize;\r
+  SmmVariableHeader->NameSize = VariableNameSize;\r
   if (Attributes == NULL) {\r
     SmmVariableHeader->Attributes = 0;\r
   } else {\r
     SmmVariableHeader->Attributes = *Attributes;\r
   }\r
+\r
   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
 \r
   //\r
@@ -519,13 +792,14 @@ RuntimeServiceGetVariable (
   //\r
   // Get data from SMM.\r
   //\r
-  if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {\r
     //\r
     // SMM CommBuffer DataSize can be a trimed value\r
     // Only update DataSize when needed\r
     //\r
     *DataSize = SmmVariableHeader->DataSize;\r
   }\r
+\r
   if (Attributes != NULL) {\r
     *Attributes = SmmVariableHeader->Attributes;\r
   }\r
@@ -541,13 +815,62 @@ RuntimeServiceGetVariable (
   }\r
 \r
 Done:\r
-  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
   return Status;\r
 }\r
 \r
+/**\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  Caution: This function may receive untrusted input.\r
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
+  @param[in]      VariableName       Name of Variable to be found.\r
+  @param[in]      VendorGuid         Variable vendor GUID.\r
+  @param[out]     Attributes         Attribute value of the variable found.\r
+  @param[in, out] DataSize           Size of Data found. If size is less than the\r
+                                     data, this value contains the required size.\r
+  @param[out]     Data               Data pointer.\r
+\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetVariable (\r
+  IN      CHAR16    *VariableName,\r
+  IN      EFI_GUID  *VendorGuid,\r
+  OUT     UINT32    *Attributes OPTIONAL,\r
+  IN OUT  UINTN     *DataSize,\r
+  OUT     VOID      *Data\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (VariableName[0] == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
+    Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+  } else {\r
+    Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+  }\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
-  This code Finds the Next available variable.\r
+  Finds the next available variable in a runtime cache variable store.\r
 \r
   @param[in, out] VariableNameSize   Size of the variable name.\r
   @param[in, out] VariableName       Pointer to variable name.\r
@@ -560,25 +883,95 @@ Done:
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-RuntimeServiceGetNextVariableName (\r
-  IN OUT  UINTN                             *VariableNameSize,\r
-  IN OUT  CHAR16                            *VariableName,\r
-  IN OUT  EFI_GUID                          *VendorGuid\r
+GetNextVariableNameInRuntimeCache (\r
+  IN OUT  UINTN     *VariableNameSize,\r
+  IN OUT  CHAR16    *VariableName,\r
+  IN OUT  EFI_GUID  *VendorGuid\r
   )\r
 {\r
-  EFI_STATUS                                      Status;\r
-  UINTN                                           PayloadSize;\r
-  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
-  UINTN                                           OutVariableNameSize;\r
-  UINTN                                           InVariableNameSize;\r
+  EFI_STATUS             Status;\r
+  UINTN                  VarNameSize;\r
+  VARIABLE_HEADER        *VariablePtr;\r
+  VARIABLE_STORE_HEADER  *VariableStoreHeader[VariableStoreTypeMax];\r
 \r
-  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  //\r
+  // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
+  // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
+  // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
+  // cache read lock should always be free when entering this function.\r
+  //\r
+  ASSERT (!mVariableRuntimeCacheReadLock);\r
+\r
+  CheckForRuntimeCacheSync ();\r
+\r
+  mVariableRuntimeCacheReadLock = TRUE;\r
+  if (!mVariableRuntimeCachePendingUpdate) {\r
+    //\r
+    // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
+    // The index and attributes mapping must be kept in this order as FindVariable\r
+    // makes use of this mapping to implement search algorithm.\r
+    //\r
+    VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
+    VariableStoreHeader[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;\r
+    VariableStoreHeader[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;\r
+\r
+    Status =  VariableServiceGetNextVariableInternal (\r
+                VariableName,\r
+                VendorGuid,\r
+                VariableStoreHeader,\r
+                &VariablePtr,\r
+                mVariableAuthFormat\r
+                );\r
+    if (!EFI_ERROR (Status)) {\r
+      VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);\r
+      ASSERT (VarNameSize != 0);\r
+      if (VarNameSize <= *VariableNameSize) {\r
+        CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);\r
+        CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));\r
+        Status = EFI_SUCCESS;\r
+      } else {\r
+        Status = EFI_BUFFER_TOO_SMALL;\r
+      }\r
+\r
+      *VariableNameSize = VarNameSize;\r
+    }\r
   }\r
 \r
-  OutVariableNameSize   = *VariableNameSize;\r
-  InVariableNameSize    = StrSize (VariableName);\r
+  mVariableRuntimeCacheReadLock = FALSE;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Finds the next available variable in a SMM variable store.\r
+\r
+  @param[in, out] VariableNameSize   Size of the variable name.\r
+  @param[in, out] VariableName       Pointer to variable name.\r
+  @param[in, out] VendorGuid         Variable Vendor Guid.\r
+\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+GetNextVariableNameInSmm (\r
+  IN OUT  UINTN     *VariableNameSize,\r
+  IN OUT  CHAR16    *VariableName,\r
+  IN OUT  EFI_GUID  *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS                                       Status;\r
+  UINTN                                            PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME  *SmmGetNextVariableName;\r
+  UINTN                                            OutVariableNameSize;\r
+  UINTN                                            InVariableNameSize;\r
+\r
+  OutVariableNameSize    = *VariableNameSize;\r
+  InVariableNameSize     = StrSize (VariableName);\r
   SmmGetNextVariableName = NULL;\r
 \r
   //\r
@@ -588,8 +981,6 @@ RuntimeServiceGetNextVariableName (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
-\r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
@@ -600,6 +991,7 @@ RuntimeServiceGetNextVariableName (
     //\r
     OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
   }\r
+\r
   //\r
   // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
   //\r
@@ -609,6 +1001,7 @@ RuntimeServiceGetNextVariableName (
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (SmmGetNextVariableName != NULL);\r
 \r
   //\r
@@ -622,7 +1015,7 @@ RuntimeServiceGetNextVariableName (
   //\r
   CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
   if (OutVariableNameSize > InVariableNameSize) {\r
-    ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
+    ZeroMem ((UINT8 *)SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
   }\r
 \r
   //\r
@@ -633,13 +1026,14 @@ RuntimeServiceGetNextVariableName (
   //\r
   // Get data from SMM.\r
   //\r
-  if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {\r
     //\r
     // SMM CommBuffer NameSize can be a trimed value\r
     // Only update VariableNameSize when needed\r
     //\r
     *VariableNameSize = SmmGetNextVariableName->NameSize;\r
   }\r
+\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -648,7 +1042,60 @@ RuntimeServiceGetNextVariableName (
   CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);\r
 \r
 Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This code Finds the Next available variable.\r
+\r
+  @param[in, out] VariableNameSize   Size of the variable name.\r
+  @param[in, out] VariableName       Pointer to variable name.\r
+  @param[in, out] VendorGuid         Variable Vendor Guid.\r
+\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetNextVariableName (\r
+  IN OUT  UINTN     *VariableNameSize,\r
+  IN OUT  CHAR16    *VariableName,\r
+  IN OUT  EFI_GUID  *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       MaxLen;\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Calculate the possible maximum length of name string, including the Null terminator.\r
+  //\r
+  MaxLen = *VariableNameSize / sizeof (CHAR16);\r
+  if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
+    //\r
+    // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
+    // follow spec to return EFI_INVALID_PARAMETER.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
+    Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);\r
+  } else {\r
+    Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);\r
+  }\r
+\r
   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
   return Status;\r
 }\r
 \r
@@ -675,11 +1122,11 @@ Done:
 EFI_STATUS\r
 EFIAPI\r
 RuntimeServiceSetVariable (\r
-  IN CHAR16                                 *VariableName,\r
-  IN EFI_GUID                               *VendorGuid,\r
-  IN UINT32                                 Attributes,\r
-  IN UINTN                                  DataSize,\r
-  IN VOID                                   *Data\r
+  IN CHAR16    *VariableName,\r
+  IN EFI_GUID  *VendorGuid,\r
+  IN UINT32    Attributes,\r
+  IN UINTN     DataSize,\r
+  IN VOID      *Data\r
   )\r
 {\r
   EFI_STATUS                                Status;\r
@@ -690,44 +1137,46 @@ RuntimeServiceSetVariable (
   //\r
   // Check input parameters.\r
   //\r
-  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+  if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (DataSize != 0 && Data == NULL) {\r
+  if ((DataSize != 0) && (Data == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  VariableNameSize      = StrSize (VariableName);\r
-  SmmVariableHeader     = NULL;\r
+  VariableNameSize  = StrSize (VariableName);\r
+  SmmVariableHeader = NULL;\r
 \r
   //\r
   // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
   //\r
   if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
-      (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
+      (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize))\r
+  {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
 \r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
   //\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
-  Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
+  Status      = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (SmmVariableHeader != NULL);\r
 \r
-  CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
+  CopyGuid ((EFI_GUID *)&SmmVariableHeader->Guid, VendorGuid);\r
   SmmVariableHeader->DataSize   = DataSize;\r
   SmmVariableHeader->NameSize   = VariableNameSize;\r
   SmmVariableHeader->Attributes = Attributes;\r
   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
-  CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
+  CopyMem ((UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
 \r
   //\r
   // Send data to SMM.\r
@@ -745,10 +1194,10 @@ Done:
         );\r
     }\r
   }\r
+\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
   This code returns information about the EFI variables.\r
 \r
@@ -769,36 +1218,37 @@ Done:
 EFI_STATUS\r
 EFIAPI\r
 RuntimeServiceQueryVariableInfo (\r
-  IN  UINT32                                Attributes,\r
-  OUT UINT64                                *MaximumVariableStorageSize,\r
-  OUT UINT64                                *RemainingVariableStorageSize,\r
-  OUT UINT64                                *MaximumVariableSize\r
+  IN  UINT32  Attributes,\r
+  OUT UINT64  *MaximumVariableStorageSize,\r
+  OUT UINT64  *RemainingVariableStorageSize,\r
+  OUT UINT64  *MaximumVariableSize\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  UINTN                                     PayloadSize;\r
-  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
+  EFI_STATUS                                    Status;\r
+  UINTN                                         PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO  *SmmQueryVariableInfo;\r
 \r
   SmmQueryVariableInfo = NULL;\r
 \r
-  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+  if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
 \r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
   //\r
   PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
-  Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
+  Status      = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
+\r
   ASSERT (SmmQueryVariableInfo != NULL);\r
 \r
-  SmmQueryVariableInfo->Attributes  = Attributes;\r
+  SmmQueryVariableInfo->Attributes = Attributes;\r
 \r
   //\r
   // Send data to SMM.\r
@@ -820,7 +1270,6 @@ Done:
   return Status;\r
 }\r
 \r
-\r
 /**\r
   Exit Boot Services Event notification handler.\r
 \r
@@ -833,8 +1282,8 @@ Done:
 VOID\r
 EFIAPI\r
 OnExitBootServices (\r
-  IN      EFI_EVENT                         Event,\r
-  IN      VOID                              *Context\r
+  IN      EFI_EVENT  Event,\r
+  IN      VOID       *Context\r
   )\r
 {\r
   //\r
@@ -849,7 +1298,6 @@ OnExitBootServices (
   SendCommunicateBuffer (0);\r
 }\r
 \r
-\r
 /**\r
   On Ready To Boot Services Event notification handler.\r
 \r
@@ -862,8 +1310,8 @@ OnExitBootServices (
 VOID\r
 EFIAPI\r
 OnReadyToBoot (\r
-  IN      EFI_EVENT                         Event,\r
-  IN      VOID                              *Context\r
+  IN      EFI_EVENT  Event,\r
+  IN      VOID       *Context\r
   )\r
 {\r
   //\r
@@ -877,10 +1325,20 @@ OnReadyToBoot (
   //\r
   SendCommunicateBuffer (0);\r
 \r
+  //\r
+  // Install the system configuration table for variable info data captured\r
+  //\r
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+    if (mVariableAuthFormat) {\r
+      gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);\r
+    } else {\r
+      gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);\r
+    }\r
+  }\r
+\r
   gBS->CloseEvent (Event);\r
 }\r
 \r
-\r
 /**\r
   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
 \r
@@ -894,12 +1352,15 @@ OnReadyToBoot (
 VOID\r
 EFIAPI\r
 VariableAddressChangeEvent (\r
-  IN EFI_EVENT                              Event,\r
-  IN VOID                                   *Context\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
   )\r
 {\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
-  EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
+  EfiConvertPointer (0x0, (VOID **)&mVariableBuffer);\r
+  EfiConvertPointer (0x0, (VOID **)&mMmCommunication2);\r
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeHobCacheBuffer);\r
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeNvCacheBuffer);\r
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeVolatileCacheBuffer);\r
 }\r
 \r
 /**\r
@@ -914,48 +1375,48 @@ VariableAddressChangeEvent (
 EFI_STATUS\r
 EFIAPI\r
 GetVariablePayloadSize (\r
-  OUT UINTN                         *VariablePayloadSize\r
+  OUT UINTN  *VariablePayloadSize\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;\r
-  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
-  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
-  UINTN                                     CommSize;\r
-  UINT8                                     *CommBuffer;\r
+  EFI_STATUS                                 Status;\r
+  SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE  *SmmGetPayloadSize;\r
+  EFI_MM_COMMUNICATE_HEADER                  *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER            *SmmVariableFunctionHeader;\r
+  UINTN                                      CommSize;\r
+  UINT8                                      *CommBuffer;\r
 \r
   SmmGetPayloadSize = NULL;\r
-  CommBuffer = NULL;\r
+  CommBuffer        = NULL;\r
 \r
-  if(VariablePayloadSize == NULL) {\r
+  if (VariablePayloadSize == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
 \r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
   //\r
-  CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
+  CommSize   = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
   CommBuffer = AllocateZeroPool (CommSize);\r
   if (CommBuffer == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Done;\r
   }\r
 \r
-  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;\r
   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
 \r
-  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\r
-  SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
+  SmmGetPayloadSize                   = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *)SmmVariableFunctionHeader->Data;\r
 \r
   //\r
   // Send data to SMM.\r
   //\r
-  Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   Status = SmmVariableFunctionHeader->ReturnStatus;\r
@@ -972,6 +1433,188 @@ Done:
   if (CommBuffer != NULL) {\r
     FreePool (CommBuffer);\r
   }\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This code gets information needed from SMM for runtime cache initialization.\r
+\r
+  @param[out] TotalHobStorageSize         Output pointer for the total HOB storage size in bytes.\r
+  @param[out] TotalNvStorageSize          Output pointer for the total non-volatile storage size in bytes.\r
+  @param[out] TotalVolatileStorageSize    Output pointer for the total volatile storage size in bytes.\r
+  @param[out] AuthenticatedVariableUsage  Output pointer that indicates if authenticated variables are to be used.\r
+\r
+  @retval EFI_SUCCESS                     Retrieved the size successfully.\r
+  @retval EFI_INVALID_PARAMETER           TotalNvStorageSize parameter is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES            The memory resources needed for a CommBuffer are not available.\r
+  @retval Others                          Could not retrieve the size successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetRuntimeCacheInfo (\r
+  OUT UINTN    *TotalHobStorageSize,\r
+  OUT UINTN    *TotalNvStorageSize,\r
+  OUT UINTN    *TotalVolatileStorageSize,\r
+  OUT BOOLEAN  *AuthenticatedVariableUsage\r
+  )\r
+{\r
+  EFI_STATUS                                       Status;\r
+  SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO  *SmmGetRuntimeCacheInfo;\r
+  EFI_MM_COMMUNICATE_HEADER                        *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER                  *SmmVariableFunctionHeader;\r
+  UINTN                                            CommSize;\r
+  UINT8                                            *CommBuffer;\r
+\r
+  SmmGetRuntimeCacheInfo = NULL;\r
+  CommBuffer             = mVariableBuffer;\r
+\r
+  if ((TotalHobStorageSize == NULL) || (TotalNvStorageSize == NULL) || (TotalVolatileStorageSize == NULL) || (AuthenticatedVariableUsage == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (CommBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+  CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
+  ZeroMem (CommBuffer, CommSize);\r
+\r
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;\r
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+  SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
+\r
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;\r
+  SmmGetRuntimeCacheInfo              = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *)SmmVariableFunctionHeader->Data;\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+    goto Done;\r
+  }\r
+\r
+  Status = SmmVariableFunctionHeader->ReturnStatus;\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *TotalHobStorageSize        = SmmGetRuntimeCacheInfo->TotalHobStorageSize;\r
+  *TotalNvStorageSize         = SmmGetRuntimeCacheInfo->TotalNvStorageSize;\r
+  *TotalVolatileStorageSize   = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;\r
+  *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends the runtime variable cache context information to SMM.\r
+\r
+  @retval EFI_SUCCESS               Retrieved the size successfully.\r
+  @retval EFI_INVALID_PARAMETER     TotalNvStorageSize parameter is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES      The memory resources needed for a CommBuffer are not available.\r
+  @retval Others                    Could not retrieve the size successfully.;\r
+\r
+**/\r
+EFI_STATUS\r
+SendRuntimeVariableCacheContextToSmm (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                                               Status;\r
+  SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT  *SmmRuntimeVarCacheContext;\r
+  EFI_MM_COMMUNICATE_HEADER                                *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER                          *SmmVariableFunctionHeader;\r
+  UINTN                                                    CommSize;\r
+  UINT8                                                    *CommBuffer;\r
+\r
+  SmmRuntimeVarCacheContext = NULL;\r
+  CommBuffer                = mVariableBuffer;\r
+\r
+  if (CommBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+  //\r
+  CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+  ZeroMem (CommBuffer, CommSize);\r
+\r
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;\r
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+  SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+\r
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;\r
+  SmmRuntimeVarCacheContext           = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *)SmmVariableFunctionHeader->Data;\r
+\r
+  SmmRuntimeVarCacheContext->RuntimeHobCache      = mVariableRuntimeHobCacheBuffer;\r
+  SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;\r
+  SmmRuntimeVarCacheContext->RuntimeNvCache       = mVariableRuntimeNvCacheBuffer;\r
+  SmmRuntimeVarCacheContext->PendingUpdate        = &mVariableRuntimeCachePendingUpdate;\r
+  SmmRuntimeVarCacheContext->ReadLock             = &mVariableRuntimeCacheReadLock;\r
+  SmmRuntimeVarCacheContext->HobFlushComplete     = &mHobFlushComplete;\r
+\r
+  //\r
+  // Request to unblock this region to be accessible from inside MM environment\r
+  // These fields "should" be all on the same page, but just to be on the safe side...\r
+  //\r
+  Status = MmUnblockMemoryRequest (\r
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->PendingUpdate - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),\r
+             EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCachePendingUpdate))\r
+             );\r
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = MmUnblockMemoryRequest (\r
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->ReadLock - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),\r
+             EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCacheReadLock))\r
+             );\r
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = MmUnblockMemoryRequest (\r
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->HobFlushComplete - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),\r
+             EFI_SIZE_TO_PAGES (sizeof (mHobFlushComplete))\r
+             );\r
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+    goto Done;\r
+  }\r
+\r
+  Status = SmmVariableFunctionHeader->ReturnStatus;\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
   return Status;\r
 }\r
@@ -986,18 +1629,18 @@ Done:
 VOID\r
 EFIAPI\r
 SmmVariableReady (\r
-  IN  EFI_EVENT                             Event,\r
-  IN  VOID                                  *Context\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
+  EFI_STATUS  Status;\r
 \r
   Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
   if (EFI_ERROR (Status)) {\r
     return;\r
   }\r
 \r
-  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
+  Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **)&mMmCommunication2);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
@@ -1005,8 +1648,8 @@ SmmVariableReady (
   //\r
   Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);\r
   ASSERT_EFI_ERROR (Status);\r
-  mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
-  mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);\r
+  mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
+  mVariableBuffer     = AllocateRuntimePool (mVariableBufferSize);\r
   ASSERT (mVariableBuffer != NULL);\r
 \r
   //\r
@@ -1014,6 +1657,44 @@ SmmVariableReady (
   //\r
   mVariableBufferPhysical = mVariableBuffer;\r
 \r
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
+    DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));\r
+    //\r
+    // Allocate runtime variable cache memory buffers.\r
+    //\r
+    Status =  GetRuntimeCacheInfo (\r
+                &mVariableRuntimeHobCacheBufferSize,\r
+                &mVariableRuntimeNvCacheBufferSize,\r
+                &mVariableRuntimeVolatileCacheBufferSize,\r
+                &mVariableAuthFormat\r
+                );\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);\r
+          if (!EFI_ERROR (Status)) {\r
+            Status = SendRuntimeVariableCacheContextToSmm ();\r
+            if (!EFI_ERROR (Status)) {\r
+              SyncRuntimeCache ();\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        mVariableRuntimeHobCacheBuffer      = NULL;\r
+        mVariableRuntimeNvCacheBuffer       = NULL;\r
+        mVariableRuntimeVolatileCacheBuffer = NULL;\r
+      }\r
+    }\r
+\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));\r
+  }\r
+\r
   gRT->GetVariable         = RuntimeServiceGetVariable;\r
   gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
   gRT->SetVariable         = RuntimeServiceSetVariable;\r
@@ -1031,29 +1712,28 @@ SmmVariableReady (
   ASSERT_EFI_ERROR (Status);\r
 \r
   mVariableLock.RequestToLock = VariableLockRequestToLock;\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mHandle,\r
-                  &gEdkiiVariableLockProtocolGuid,\r
-                  &mVariableLock,\r
-                  NULL\r
-                  );\r
+  Status                      = gBS->InstallMultipleProtocolInterfaces (\r
+                                       &mHandle,\r
+                                       &gEdkiiVariableLockProtocolGuid,\r
+                                       &mVariableLock,\r
+                                       NULL\r
+                                       );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;\r
-  mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;\r
-  mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mHandle,\r
-                  &gEdkiiVarCheckProtocolGuid,\r
-                  &mVarCheck,\r
-                  NULL\r
-                  );\r
+  mVarCheck.VariablePropertySet             = VarCheckVariablePropertySet;\r
+  mVarCheck.VariablePropertyGet             = VarCheckVariablePropertyGet;\r
+  Status                                    = gBS->InstallMultipleProtocolInterfaces (\r
+                                                     &mHandle,\r
+                                                     &gEdkiiVarCheckProtocolGuid,\r
+                                                     &mVarCheck,\r
+                                                     NULL\r
+                                                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   gBS->CloseEvent (Event);\r
 }\r
 \r
-\r
 /**\r
   SMM Non-Volatile variable write service is ready notify event handler.\r
 \r
@@ -1064,21 +1744,27 @@ SmmVariableReady (
 VOID\r
 EFIAPI\r
 SmmVariableWriteReady (\r
-  IN  EFI_EVENT                             Event,\r
-  IN  VOID                                  *Context\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
   )\r
 {\r
-  EFI_STATUS                                Status;\r
-  VOID                                      *ProtocolOps;\r
+  EFI_STATUS  Status;\r
+  VOID        *ProtocolOps;\r
 \r
   //\r
   // Check whether the protocol is installed or not.\r
   //\r
-  Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
+  Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **)&ProtocolOps);\r
   if (EFI_ERROR (Status)) {\r
     return;\r
   }\r
 \r
+  //\r
+  // Some Secure Boot Policy Var (SecureBoot, etc) updates following other\r
+  // Secure Boot Policy Variable change.  Record their initial value.\r
+  //\r
+  RecordSecureBootPolicyVarData ();\r
+\r
   Status = gBS->InstallProtocolInterface (\r
                   &mHandle,\r
                   &gEfiVariableWriteArchProtocolGuid,\r
@@ -1090,7 +1776,6 @@ SmmVariableWriteReady (
   gBS->CloseEvent (Event);\r
 }\r
 \r
-\r
 /**\r
   Variable Driver main entry point. The Variable driver places the 4 EFI\r
   runtime services in the EFI System Table and installs arch protocols\r
@@ -1106,15 +1791,15 @@ SmmVariableWriteReady (
 EFI_STATUS\r
 EFIAPI\r
 VariableSmmRuntimeInitialize (\r
-  IN EFI_HANDLE                             ImageHandle,\r
-  IN EFI_SYSTEM_TABLE                       *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  VOID                                      *SmmVariableRegistration;\r
-  VOID                                      *SmmVariableWriteRegistration;\r
-  EFI_EVENT                                 OnReadyToBootEvent;\r
-  EFI_EVENT                                 ExitBootServiceEvent;\r
-  EFI_EVENT                                 LegacyBootEvent;\r
+  VOID       *SmmVariableRegistration;\r
+  VOID       *SmmVariableWriteRegistration;\r
+  EFI_EVENT  OnReadyToBootEvent;\r
+  EFI_EVENT  ExitBootServiceEvent;\r
+  EFI_EVENT  LegacyBootEvent;\r
 \r
   EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
 \r
@@ -1166,7 +1851,7 @@ VariableSmmRuntimeInitialize (
   // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
   // Reuse OnExitBootServices() here.\r
   //\r
-  EfiCreateEventLegacyBootEx(\r
+  EfiCreateEventLegacyBootEx (\r
     TPL_NOTIFY,\r
     OnExitBootServices,\r
     NULL,\r
@@ -1185,6 +1870,8 @@ VariableSmmRuntimeInitialize (
          &mVirtualAddressChangeEvent\r
          );\r
 \r
+  // Initialize the VariablePolicy protocol and engine.\r
+  VariablePolicySmmDxeMain (ImageHandle, SystemTable);\r
+\r
   return EFI_SUCCESS;\r
 }\r
-\r