]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg/Variable: Initialize local variable "RtPtrTrack"
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
index e7b10149fb15fc791577dff78e521c87e3eaa2e6..2cf0ed32ae55bea2094e7bb578a60810c242dbc1 100644 (file)
@@ -1,17 +1,20 @@
 /** @file\r
-\r
   Implement all four UEFI Runtime Variable services for the nonvolatile\r
   and volatile storage space and install variable architecture protocol\r
   based on SMM variable module.\r
 \r
-Copyright (c) 2010 - 2013, 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
+  Caution: This module requires additional review when modified.\r
+  This driver will have external input - variable data.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API\r
+  to receive data buffer. The size should be checked carefully.\r
+\r
+  InitCommunicateBuffer() is really function to check the variable data size.\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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 #include <PiDxe.h>\r
@@ -20,6 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SmmCommunication.h>\r
 #include <Protocol/SmmVariable.h>\r
 #include <Protocol/VariableLock.h>\r
+#include <Protocol/VarCheck.h>\r
 \r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/UefiRuntimeServicesTableLib.h>\r
@@ -28,24 +32,48 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/UefiRuntimeLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
-#include <Library/PcdLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/BaseLib.h>\r
 \r
 #include <Guid/EventGroup.h>\r
-#include <Guid/VariableFormat.h>\r
 #include <Guid/SmmVariableCommon.h>\r
 \r
-EFI_HANDLE                       mHandle                    = NULL; \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_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = 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
+  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
+RecordSecureBootPolicyVarData(\r
+  VOID\r
+  );\r
 \r
 /**\r
   Acquires lock only at boot time. Simply returns at runtime.\r
@@ -91,16 +119,85 @@ 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
+\r
+  if (TotalVariableCacheSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (*TotalVariableCacheSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {\r
+    return EFI_INVALID_PARAMETER;\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
+  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
   The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
   DataSize.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  The data size external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
   @param[out]      DataPtr          Points to the data in the communicate buffer.\r
   @param[in]       DataSize         The data size to send to SMM.\r
   @param[in]       Function         The function number to initialize the communicate header.\r
-                      \r
+\r
   @retval EFI_INVALID_PARAMETER     The data size is too big.\r
   @retval EFI_SUCCESS               Find the specified variable.\r
 \r
@@ -112,10 +209,10 @@ InitCommunicateBuffer (
   IN      UINTN                             Function\r
   )\r
 {\r
-  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
-  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader; \r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
+\r
 \r
\r
   if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -123,7 +220,7 @@ InitCommunicateBuffer (
   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
   SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
-   \r
+\r
   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
   SmmVariableFunctionHeader->Function = Function;\r
   if (DataPtr != NULL) {\r
@@ -140,8 +237,8 @@ InitCommunicateBuffer (
   @param[in]   DataSize               This size of the function header and the data.\r
 \r
   @retval      EFI_SUCCESS            Success is returned from the functin in SMM.\r
-  @retval      Others                 Failure is returned from the function in SMM. \r
-  \r
+  @retval      Others                 Failure is returned from the function in SMM.\r
+\r
 **/\r
 EFI_STATUS\r
 SendCommunicateBuffer (\r
@@ -150,9 +247,9 @@ SendCommunicateBuffer (
 {\r
   EFI_STATUS                                Status;\r
   UINTN                                     CommSize;\r
-  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
-  \r
+\r
   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
   Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
   ASSERT_EFI_ERROR (Status);\r
@@ -195,6 +292,7 @@ VariableLockRequestToLock (
   }\r
 \r
   VariableNameSize = StrSize (VariableName);\r
+  VariableToLock   = NULL;\r
 \r
   //\r
   // If VariableName exceeds SMM payload limit. Return failure\r
@@ -231,7 +329,233 @@ Done:
 }\r
 \r
 /**\r
-  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+  Register SetVariable check handler.\r
+\r
+  @param[in] Handler            Pointer to check handler.\r
+\r
+  @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.\r
+  @retval EFI_INVALID_PARAMETER Handler is NULL.\r
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+                                already been signaled.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.\r
+  @retval EFI_UNSUPPORTED       This interface is not implemented.\r
+                                For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckRegisterSetVariableCheckHandler (\r
+  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Variable property set.\r
+\r
+  @param[in] Name               Pointer to the variable name.\r
+  @param[in] Guid               Pointer to the vendor GUID.\r
+  @param[in] VariableProperty   Pointer to the input variable property.\r
+\r
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.\r
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,\r
+                                or the fields of VariableProperty are not valid.\r
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+                                already been signaled.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckVariablePropertySet (\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
+\r
+  if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (VariableProperty == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  VariableNameSize = StrSize (Name);\r
+  CommVariableProperty = NULL;\r
+\r
+  //\r
+  // If VariableName exceeds SMM payload limit. Return failure\r
+  //\r
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
+    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
+  //\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
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  ASSERT (CommVariableProperty != NULL);\r
+\r
+  CopyGuid (&CommVariableProperty->Guid, Guid);\r
+  CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));\r
+  CommVariableProperty->NameSize = VariableNameSize;\r
+  CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Variable property get.\r
+\r
+  @param[in]  Name              Pointer to the variable name.\r
+  @param[in]  Guid              Pointer to the vendor GUID.\r
+  @param[out] VariableProperty  Pointer to the output variable property.\r
+\r
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.\r
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.\r
+  @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckVariablePropertyGet (\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
+\r
+  if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (VariableProperty == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  VariableNameSize = StrSize (Name);\r
+  CommVariableProperty = NULL;\r
+\r
+  //\r
+  // If VariableName exceeds SMM payload limit. Return failure\r
+  //\r
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
+    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
+  //\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
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  ASSERT (CommVariableProperty != NULL);\r
+\r
+  CopyGuid (&CommVariableProperty->Guid, Guid);\r
+  CommVariableProperty->NameSize = VariableNameSize;\r
+  CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+  if (Status == EFI_SUCCESS) {\r
+    CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));\r
+  }\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\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
+  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
+    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
 \r
   @param[in]      VariableName       Name of Variable to be found.\r
   @param[in]      VendorGuid         Variable vendor GUID.\r
@@ -239,21 +563,134 @@ Done:
   @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
+\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
+FindVariableInRuntimeCache (\r
   IN      CHAR16                            *VariableName,\r
   IN      EFI_GUID                          *VendorGuid,\r
   OUT     UINT32                            *Attributes OPTIONAL,\r
   IN OUT  UINTN                             *DataSize,\r
-  OUT     VOID                              *Data\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
+        if (Attributes != NULL) {\r
+          *Attributes = RtPtrTrack.CurrPtr->Attributes;\r
+        }\r
+\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
+  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
@@ -266,12 +703,9 @@ RuntimeServiceGetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((*DataSize != 0) && (Data == NULL)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
   TempDataSize          = *DataSize;\r
   VariableNameSize      = StrSize (VariableName);\r
+  SmmVariableHeader     = NULL;\r
 \r
   //\r
   // If VariableName exceeds SMM payload limit. Return failure\r
@@ -280,8 +714,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
@@ -294,7 +726,7 @@ RuntimeServiceGetVariable (
   }\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
+  Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -320,29 +752,154 @@ RuntimeServiceGetVariable (
   //\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
+    // SMM CommBuffer DataSize can be a trimed value\r
+    // Only update DataSize when needed\r
+    //\r
+    *DataSize = SmmVariableHeader->DataSize;\r
+  }\r
+  if (Attributes != NULL) {\r
+    *Attributes = SmmVariableHeader->Attributes;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  if (Data != NULL) {\r
+    CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
+  } else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+Done:\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
+  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
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\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
+  @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
+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                   VarNameSize;\r
+  VARIABLE_HEADER         *VariablePtr;\r
+  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];\r
+\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
-    *DataSize = SmmVariableHeader->DataSize;\r
-  }\r
-  if (Attributes != NULL) {\r
-    *Attributes = SmmVariableHeader->Attributes;\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
+  mVariableRuntimeCacheReadLock = FALSE;\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto Done;\r
-  }\r
-\r
-  CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
-\r
-Done:\r
-  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  This code Finds the Next available variable.\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
@@ -355,8 +912,7 @@ Done:
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-RuntimeServiceGetNextVariableName (\r
+GetNextVariableNameInSmm (\r
   IN OUT  UINTN                             *VariableNameSize,\r
   IN OUT  CHAR16                            *VariableName,\r
   IN OUT  EFI_GUID                          *VendorGuid\r
@@ -368,12 +924,9 @@ RuntimeServiceGetNextVariableName (
   UINTN                                           OutVariableNameSize;\r
   UINTN                                           InVariableNameSize;\r
 \r
-  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
   OutVariableNameSize   = *VariableNameSize;\r
   InVariableNameSize    = StrSize (VariableName);\r
+  SmmGetNextVariableName = NULL;\r
 \r
   //\r
   // If input string exceeds SMM payload limit. Return failure\r
@@ -382,8 +935,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
@@ -399,7 +950,6 @@ RuntimeServiceGetNextVariableName (
   //\r
   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
 \r
-\r
   Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
@@ -438,18 +988,73 @@ RuntimeServiceGetNextVariableName (
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
-  \r
+\r
   CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
-  CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);  \r
+  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
   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
   return Status;\r
 }\r
 \r
 /**\r
   This code sets variable in storage blocks (Volatile or Non-Volatile).\r
 \r
+  Caution: This function may receive untrusted input.\r
+  The data size and data are 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[in] Attributes                   Attribute value of the variable found\r
@@ -475,22 +1080,23 @@ RuntimeServiceSetVariable (
   )\r
 {\r
   EFI_STATUS                                Status;\r
-  UINTN                                     PayloadSize; \r
+  UINTN                                     PayloadSize;\r
   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
   UINTN                                     VariableNameSize;\r
-    \r
+\r
   //\r
   // Check input parameters.\r
   //\r
   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
-  } \r
+  }\r
 \r
   if (DataSize != 0 && Data == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   VariableNameSize      = StrSize (VariableName);\r
+  SmmVariableHeader     = NULL;\r
 \r
   //\r
   // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
@@ -501,7 +1107,7 @@ RuntimeServiceSetVariable (
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
\r
+\r
   //\r
   // Init the communicate buffer. The buffer data size is:\r
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
@@ -527,6 +1133,15 @@ RuntimeServiceSetVariable (
 \r
 Done:\r
   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+  if (!EfiAtRuntime ()) {\r
+    if (!EFI_ERROR (Status)) {\r
+      SecureBootHook (\r
+        VariableName,\r
+        VendorGuid\r
+        );\r
+    }\r
+  }\r
   return Status;\r
 }\r
 \r
@@ -561,6 +1176,8 @@ RuntimeServiceQueryVariableInfo (
   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
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -593,7 +1210,7 @@ RuntimeServiceQueryVariableInfo (
   //\r
   *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;\r
   *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
-  *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
+  *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;\r
 \r
 Done:\r
   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
@@ -621,7 +1238,7 @@ OnExitBootServices (
   // 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_EXIT_BOOT_SERVICE); \r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);\r
 \r
   //\r
   // Send data to SMM.\r
@@ -651,11 +1268,24 @@ OnReadyToBoot (
   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
   //\r
   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
-  \r
+\r
   //\r
   // Send data to SMM.\r
   //\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
@@ -678,15 +1308,244 @@ VariableAddressChangeEvent (
 {\r
   EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
   EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\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
+  This code gets variable payload size.\r
+\r
+  @param[out] VariablePayloadSize   Output pointer to variable payload size.\r
+\r
+  @retval EFI_SUCCESS               Get successfully.\r
+  @retval Others                    Get unsuccessfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetVariablePayloadSize (\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
+\r
+  SmmGetPayloadSize = NULL;\r
+  CommBuffer = NULL;\r
+\r
+  if(VariablePayloadSize == NULL) {\r
+    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 + 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
+  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
+  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->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\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
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SmmVariableFunctionHeader->ReturnStatus;\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;\r
+\r
+Done:\r
+  if (CommBuffer != NULL) {\r
+    FreePool (CommBuffer);\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_SMM_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_SMM_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 = mSmmCommunication->Communicate (mSmmCommunication, 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_SMM_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_SMM_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
+  // Send data to SMM.\r
+  //\r
+  Status = mSmmCommunication->Communicate (mSmmCommunication, 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
 \r
 /**\r
   Initialize variable service and install Variable Architectural protocol.\r
 \r
   @param[in] Event    Event whose notification function is being invoked.\r
   @param[in] Context  Pointer to the notification function's context.\r
\r
+\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -697,19 +1556,19 @@ SmmVariableReady (
 {\r
   EFI_STATUS                                Status;\r
 \r
-  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
+  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);\r
   if (EFI_ERROR (Status)) {\r
     return;\r
   }\r
-  \r
+\r
   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
   ASSERT_EFI_ERROR (Status);\r
-  \r
+\r
   //\r
   // Allocate memory for variable communicate buffer.\r
   //\r
-  mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
-                               OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\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
   ASSERT (mVariableBuffer != NULL);\r
@@ -719,21 +1578,79 @@ 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
+      if (EFI_ERROR (Status)) {\r
+        mVariableRuntimeHobCacheBuffer = NULL;\r
+        mVariableRuntimeNvCacheBuffer = NULL;\r
+        mVariableRuntimeVolatileCacheBuffer = NULL;\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
   gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
\r
+\r
   //\r
   // Install the Variable Architectural Protocol on a new handle.\r
   //\r
   Status = gBS->InstallProtocolInterface (\r
                   &mHandle,\r
-                  &gEfiVariableArchProtocolGuid, \r
+                  &gEfiVariableArchProtocolGuid,\r
                   EFI_NATIVE_INTERFACE,\r
                   NULL\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
+\r
+  mVariableLock.RequestToLock = VariableLockRequestToLock;\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
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  gBS->CloseEvent (Event);\r
 }\r
 \r
 \r
@@ -742,7 +1659,7 @@ SmmVariableReady (
 \r
   @param[in] Event    Event whose notification function is being invoked.\r
   @param[in] Context  Pointer to the notification function's context.\r
-  \r
+\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -761,26 +1678,34 @@ SmmVariableWriteReady (
   if (EFI_ERROR (Status)) {\r
     return;\r
   }\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
+                  &gEfiVariableWriteArchProtocolGuid,\r
                   EFI_NATIVE_INTERFACE,\r
                   NULL\r
                   );\r
-  ASSERT_EFI_ERROR (Status);  \r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  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
+  runtime services in the EFI System Table and installs arch protocols\r
   for variable read and write services being available. It also registers\r
   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
   @param[in] SystemTable    A pointer to the EFI System Table.\r
-  \r
+\r
   @retval EFI_SUCCESS       Variable service successfully initialized.\r
 \r
 **/\r
@@ -791,31 +1716,22 @@ VariableSmmRuntimeInitialize (
   IN EFI_SYSTEM_TABLE                       *SystemTable\r
   )\r
 {\r
-  EFI_STATUS                                Status;\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
-  mVariableLock.RequestToLock = VariableLockRequestToLock;\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mHandle,\r
-                  &gEdkiiVariableLockProtocolGuid,\r
-                  &mVariableLock,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   //\r
   // Smm variable service is ready\r
   //\r
   EfiCreateProtocolNotifyEvent (\r
-    &gEfiSmmVariableProtocolGuid, \r
-    TPL_CALLBACK, \r
-    SmmVariableReady, \r
-    NULL, \r
+    &gEfiSmmVariableProtocolGuid,\r
+    TPL_CALLBACK,\r
+    SmmVariableReady,\r
+    NULL,\r
     &SmmVariableRegistration\r
     );\r
 \r
@@ -823,10 +1739,10 @@ VariableSmmRuntimeInitialize (
   // Smm Non-Volatile variable write service is ready\r
   //\r
   EfiCreateProtocolNotifyEvent (\r
-    &gSmmVariableWriteGuid, \r
-    TPL_CALLBACK, \r
-    SmmVariableWriteReady, \r
-    NULL, \r
+    &gSmmVariableWriteGuid,\r
+    TPL_CALLBACK,\r
+    SmmVariableWriteReady,\r
+    NULL,\r
     &SmmVariableWriteRegistration\r
     );\r
 \r
@@ -834,11 +1750,11 @@ VariableSmmRuntimeInitialize (
   // Register the event to reclaim variable for OS usage.\r
   //\r
   EfiCreateEventReadyToBootEx (\r
-    TPL_NOTIFY, \r
-    OnReadyToBoot, \r
-    NULL, \r
+    TPL_NOTIFY,\r
+    OnReadyToBoot,\r
+    NULL,\r
     &OnReadyToBootEvent\r
-    );             \r
+    );\r
 \r
   //\r
   // Register the event to inform SMM variable that it is at runtime.\r
@@ -850,7 +1766,18 @@ VariableSmmRuntimeInitialize (
          NULL,\r
          &gEfiEventExitBootServicesGuid,\r
          &ExitBootServiceEvent\r
-         ); \r
+         );\r
+\r
+  //\r
+  // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
+  // Reuse OnExitBootServices() here.\r
+  //\r
+  EfiCreateEventLegacyBootEx(\r
+    TPL_NOTIFY,\r
+    OnExitBootServices,\r
+    NULL,\r
+    &LegacyBootEvent\r
+    );\r
 \r
   //\r
   // Register the event to convert the pointer for runtime.\r
@@ -863,7 +1790,7 @@ VariableSmmRuntimeInitialize (
          &gEfiEventVirtualAddressChangeGuid,\r
          &mVirtualAddressChangeEvent\r
          );\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r