]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
Return EFI_WRITE_PROTECTED when setting KEKDefault, PKDefault, dbDefault, dbxDefault...
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
index 5f023dfdeef6ab2f28eb2d59db5a585b922c71b7..c99cd2310eefb2bed1f056232943f470a1c900f2 100644 (file)
@@ -16,7 +16,7 @@
   VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
   integer overflow. It should also check attribute to avoid authentication bypass.\r
 \r
-Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 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
@@ -35,13 +35,74 @@ VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
 ///\r
 /// Define a memory cache that improves the search performance for a variable.\r
 ///\r
-VARIABLE_STORE_HEADER  *mNvVariableCache = NULL;\r
+VARIABLE_STORE_HEADER  *mNvVariableCache      = NULL;\r
 \r
 ///\r
 /// The memory entry used for variable statistics data.\r
 ///\r
-VARIABLE_INFO_ENTRY    *gVariableInfo    = NULL;\r
+VARIABLE_INFO_ENTRY    *gVariableInfo         = NULL;\r
 \r
+///\r
+/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID\r
+/// or EVT_GROUP_READY_TO_BOOT event.\r
+///\r
+LIST_ENTRY             mLockedVariableList    = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
+\r
+///\r
+/// The flag to indicate whether the platform has left the DXE phase of execution.\r
+///\r
+BOOLEAN                mEndOfDxe              = FALSE;\r
+\r
+///\r
+/// The flag to indicate whether the variable storage locking is enabled.\r
+///\r
+BOOLEAN                mEnableLocking         = TRUE;\r
+\r
+//\r
+// To prevent name collisions with possible future globally defined variables,\r
+// other internal firmware data variables that are not defined here must be\r
+// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or\r
+// any other GUID defined by the UEFI Specification. Implementations must\r
+// only permit the creation of variables with a UEFI Specification-defined\r
+// VendorGuid when these variables are documented in the UEFI Specification.\r
+//\r
+GLOBAL_VARIABLE_ENTRY mGlobalVariableList[] = {\r
+  {EFI_LANG_CODES_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_LANG_VARIABLE_NAME,                   VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_TIME_OUT_VARIABLE_NAME,               VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,    VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_PLATFORM_LANG_VARIABLE_NAME,          VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_CON_IN_VARIABLE_NAME,                 VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_CON_OUT_VARIABLE_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_ERR_OUT_VARIABLE_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_CON_IN_DEV_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_CON_OUT_DEV_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_ERR_OUT_DEV_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_BOOT_ORDER_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_BOOT_NEXT_VARIABLE_NAME,              VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_BOOT_CURRENT_VARIABLE_NAME,           VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,    VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_DRIVER_ORDER_VARIABLE_NAME,           VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,     VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_SETUP_MODE_NAME,                      VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_KEY_EXCHANGE_KEY_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT_AT},\r
+  {EFI_PLATFORM_KEY_NAME,                    VARIABLE_ATTRIBUTE_NV_BS_RT_AT},\r
+  {EFI_SIGNATURE_SUPPORT_NAME,               VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_SECURE_BOOT_MODE_NAME,                VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_KEK_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_PK_DEFAULT_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_DB_DEFAULT_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_DBX_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_DBT_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, VARIABLE_ATTRIBUTE_BS_RT},\r
+  {EFI_OS_INDICATIONS_VARIABLE_NAME,         VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {EFI_VENDOR_KEYS_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
+};\r
+GLOBAL_VARIABLE_ENTRY mGlobalVariableList2[] = {\r
+  {L"Boot####",                              VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {L"Driver####",                            VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+  {L"Key####",                               VARIABLE_ATTRIBUTE_NV_BS_RT},\r
+};\r
 \r
 /**\r
   Routine used to track statistical information about variable usage.\r
@@ -511,30 +572,168 @@ GetEndPointer (
   return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
 }\r
 \r
+/**\r
+\r
+  Check the PubKeyIndex is a valid key or not.\r
+\r
+  This function will iterate the NV storage to see if this PubKeyIndex is still referenced \r
+  by any valid count-based auth variabe.\r
+  \r
+  @param[in]  PubKeyIndex     Index of the public key in public key store.\r
+\r
+  @retval     TRUE            The PubKeyIndex is still in use.\r
+  @retval     FALSE           The PubKeyIndex is not referenced by any count-based auth variabe.\r
+  \r
+**/\r
+BOOLEAN\r
+IsValidPubKeyIndex (\r
+  IN   UINT32      PubKeyIndex\r
+  )\r
+{\r
+  VARIABLE_HEADER          *Variable;\r
+\r
+  if (PubKeyIndex > mPubKeyNumber) {\r
+    return FALSE;\r
+  }\r
+  \r
+  Variable = GetStartPointer (mNvVariableCache);\r
+  \r
+  while (IsValidVariableHeader (Variable)) {\r
+    if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) && \r
+        Variable->PubKeyIndex == PubKeyIndex) {\r
+      return TRUE;\r
+    }\r
+    Variable = GetNextVariablePtr (Variable);\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
 \r
 /**\r
 \r
-  Variable store garbage collection and reclaim operation.\r
+  Get the number of valid public key in PubKeyStore.\r
+  \r
+  @param[in]  PubKeyNumber     Number of the public key in public key store.\r
+\r
+  @return     Number of valid public key in PubKeyStore.\r
+\r
+**/\r
+UINT32\r
+GetValidPubKeyNumber (\r
+  IN   UINT32       PubKeyNumber\r
+  )\r
+{\r
+  UINT32       PubKeyIndex;\r
+  UINT32       Counter;\r
+\r
+  Counter = 0;\r
+  \r
+  for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
+    if (IsValidPubKeyIndex (PubKeyIndex)) {\r
+      Counter++;\r
+    }\r
+  }\r
+  \r
+  return Counter;\r
+}\r
 \r
-  @param VariableBase            Base address of variable store.\r
-  @param LastVariableOffset      Offset of last variable.\r
-  @param IsVolatile              The variable store is volatile or not;\r
-                                 if it is non-volatile, need FTW.\r
-  @param UpdatingVariable        Pointer to updating variable.\r
-  @param ReclaimAnyway           If TRUE, do reclaim anyway.\r
+/**\r
+\r
+  Filter the useless key in public key store.\r
 \r
-  @return EFI_OUT_OF_RESOURCES\r
-  @return EFI_SUCCESS\r
-  @return Others\r
+  This function will find out all valid public keys in public key database, save them in new allocated \r
+  buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer\r
+  NewPubKeyIndex and NewPubKeyStore with FreePool().\r
+\r
+  @param[in]   PubKeyStore          Point to the public key database.\r
+  @param[in]   PubKeyNumber         Number of the public key in PubKeyStore.\r
+  @param[out]  NewPubKeyIndex       Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.\r
+  @param[out]  NewPubKeyStore       Saved all valid public keys in PubKeyStore.\r
+  @param[out]  NewPubKeySize        Buffer size of the NewPubKeyStore.\r
+  \r
+  @retval  EFI_SUCCESS              Trim operation is complete successfully.\r
+  @retval  EFI_OUT_OF_RESOURCES     No enough memory resources, or no useless key in PubKeyStore.\r
+  \r
+**/\r
+EFI_STATUS\r
+PubKeyStoreFilter (\r
+  IN   UINT8         *PubKeyStore,\r
+  IN   UINT32        PubKeyNumber,\r
+  OUT  UINT32        **NewPubKeyIndex,\r
+  OUT  UINT8         **NewPubKeyStore,\r
+  OUT  UINT32        *NewPubKeySize\r
+  )\r
+{\r
+  UINT32        PubKeyIndex;\r
+  UINT32        CopiedKey;\r
+  UINT32        NewPubKeyNumber;\r
+  \r
+  NewPubKeyNumber = GetValidPubKeyNumber (PubKeyNumber);\r
+  if (NewPubKeyNumber == PubKeyNumber) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (NewPubKeyNumber != 0) {\r
+    *NewPubKeySize = NewPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE;\r
+  } else {\r
+    *NewPubKeySize = sizeof (UINT8);\r
+  }\r
+\r
+  *NewPubKeyStore = AllocatePool (*NewPubKeySize);\r
+  if (*NewPubKeyStore == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *NewPubKeyIndex = AllocateZeroPool ((PubKeyNumber + 1) * sizeof (UINT32));\r
+  if (*NewPubKeyIndex == NULL) {\r
+    FreePool (*NewPubKeyStore);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopiedKey = 0;\r
+  for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
+    if (IsValidPubKeyIndex (PubKeyIndex)) {\r
+      CopyMem (\r
+        *NewPubKeyStore + CopiedKey * EFI_CERT_TYPE_RSA2048_SIZE,\r
+        PubKeyStore + (PubKeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE,\r
+        EFI_CERT_TYPE_RSA2048_SIZE\r
+        );\r
+      (*NewPubKeyIndex)[PubKeyIndex] = ++CopiedKey;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Variable store garbage collection and reclaim operation.\r
+\r
+  If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.\r
+  If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex\r
+  for all the count-based authenticate variable in NV storage.\r
+\r
+  @param[in]      VariableBase            Base address of variable store.\r
+  @param[out]     LastVariableOffset      Offset of last variable.\r
+  @param[in]      IsVolatile              The variable store is volatile or not;\r
+                                          if it is non-volatile, need FTW.\r
+  @param[in, out] UpdatingPtrTrack        Pointer to updating variable pointer track structure.\r
+  @param[in]      ReclaimPubKeyStore      Reclaim for public key database or not.\r
+  @param[in]      ReclaimAnyway           If TRUE, do reclaim anyway.\r
+  \r
+  @return EFI_SUCCESS                  Reclaim operation has finished successfully.\r
+  @return EFI_OUT_OF_RESOURCES         No enough memory resources.\r
+  @return EFI_DEVICE_ERROR             The public key database doesn't exist.\r
+  @return Others                       Unexpect error happened during reclaim operation.\r
 \r
 **/\r
 EFI_STATUS\r
 Reclaim (\r
-  IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
-  OUT UINTN                 *LastVariableOffset,\r
-  IN  BOOLEAN               IsVolatile,\r
-  IN  VARIABLE_HEADER       *UpdatingVariable,\r
-  IN  BOOLEAN               ReclaimAnyway\r
+  IN     EFI_PHYSICAL_ADDRESS         VariableBase,\r
+  OUT    UINTN                        *LastVariableOffset,\r
+  IN     BOOLEAN                      IsVolatile,\r
+  IN OUT VARIABLE_POINTER_TRACK       *UpdatingPtrTrack,\r
+  IN     BOOLEAN                      ReclaimPubKeyStore,\r
+  IN     BOOLEAN                      ReclaimAnyway\r
   )\r
 {\r
   VARIABLE_HEADER       *Variable;\r
@@ -557,14 +756,28 @@ Reclaim (
   CHAR16                *UpdatingVariableNamePtr;\r
   UINTN                 CommonVariableTotalSize;\r
   UINTN                 HwErrVariableTotalSize;\r
+  UINT32                *NewPubKeyIndex;\r
+  UINT8                 *NewPubKeyStore;\r
+  UINT32                NewPubKeySize;\r
+  VARIABLE_HEADER       *PubKeyHeader;\r
   BOOLEAN               NeedDoReclaim;\r
+  VARIABLE_HEADER       *UpdatingVariable;\r
+\r
+  UpdatingVariable = NULL;\r
+  if (UpdatingPtrTrack != NULL) {\r
+    UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
+  }\r
 \r
   NeedDoReclaim = FALSE;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
 \r
   CommonVariableTotalSize = 0;\r
   HwErrVariableTotalSize  = 0;\r
-\r
+  NewPubKeyIndex = NULL;\r
+  NewPubKeyStore = NULL;\r
+  NewPubKeySize  = 0;\r
+  PubKeyHeader   = NULL;\r
+  \r
   //\r
   // Start Pointers for the variable.\r
   //\r
@@ -608,95 +821,97 @@ Reclaim (
   CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
 \r
-  //\r
-  // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
-  //\r
-  Variable = GetStartPointer (VariableStoreHeader);\r
-  while (IsValidVariableHeader (Variable)) {\r
-    NextVariable = GetNextVariablePtr (Variable);\r
-    if (Variable->State == VAR_ADDED) {\r
-      if (UpdatingVariable != NULL) {\r
-        if (UpdatingVariable == Variable) {\r
-          Variable = NextVariable;\r
-          continue;\r
-        }\r
-\r
-        VariableNameSize         = NameSizeOfVariable(Variable);\r
-        UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
+  if (ReclaimPubKeyStore) {\r
+    //\r
+    // Trim the PubKeyStore and get new PubKeyIndex.\r
+    //\r
+    Status = PubKeyStoreFilter (\r
+               mPubKeyStore,\r
+               mPubKeyNumber,\r
+               &NewPubKeyIndex,\r
+               &NewPubKeyStore,\r
+               &NewPubKeySize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (ValidBuffer);\r
+      return Status;\r
+    }\r
 \r
-        VariableNamePtr         = GetVariableNamePtr (Variable);\r
-        UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
-        if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid)    &&\r
-            VariableNameSize == UpdatingVariableNameSize &&\r
-            CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+    //\r
+    // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).\r
+    //\r
+    Variable = GetStartPointer (mNvVariableCache);\r
+    while (IsValidVariableHeader (Variable)) {\r
+      NextVariable = GetNextVariablePtr (Variable);\r
+      if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+        if ((StrCmp (GetVariableNamePtr (Variable), AUTHVAR_KEYDB_NAME) == 0) && \r
+            (CompareGuid (&Variable->VendorGuid, &gEfiAuthenticatedVariableGuid))) {\r
+          //\r
+          // Skip the public key database, it will be reinstalled later.\r
+          //\r
+          PubKeyHeader = Variable;\r
           Variable = NextVariable;\r
           continue;\r
         }\r
+        \r
+        VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+        CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+        ((VARIABLE_HEADER*) CurrPtr)->PubKeyIndex = NewPubKeyIndex[Variable->PubKeyIndex];\r
+        CurrPtr += VariableSize;\r
+        if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          HwErrVariableTotalSize += VariableSize;\r
+        } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          CommonVariableTotalSize += VariableSize;\r
+        }\r
       }\r
-      VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
-      CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
-      CurrPtr += VariableSize;\r
-      if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        HwErrVariableTotalSize += VariableSize;\r
-      } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        CommonVariableTotalSize += VariableSize;\r
-      }\r
+      Variable = NextVariable;\r
     }\r
-    Variable = NextVariable;\r
-  }\r
 \r
-  //\r
-  // Reinstall the variable being updated if it is not NULL.\r
-  //\r
-  if (UpdatingVariable != NULL) {\r
-    VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
-    CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
-    CurrPtr += VariableSize;\r
-    if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        HwErrVariableTotalSize += VariableSize;\r
-    } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        CommonVariableTotalSize += VariableSize;\r
+    //\r
+    // Reinstall the new public key database.\r
+    //\r
+    ASSERT (PubKeyHeader != NULL);\r
+    if (PubKeyHeader == NULL) {\r
+      FreePool (ValidBuffer);\r
+      FreePool (NewPubKeyIndex);\r
+      FreePool (NewPubKeyStore);\r
+      return EFI_DEVICE_ERROR;\r
     }\r
-  }\r
-\r
-  //\r
-  // Reinstall all in delete transition variables.\r
-  //\r
-  Variable      = GetStartPointer (VariableStoreHeader);\r
-  while (IsValidVariableHeader (Variable)) {\r
-    NextVariable = GetNextVariablePtr (Variable);\r
-    if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+    CopyMem (CurrPtr, (UINT8*) PubKeyHeader, sizeof (VARIABLE_HEADER));\r
+    Variable = (VARIABLE_HEADER*) CurrPtr;\r
+    Variable->DataSize = NewPubKeySize;\r
+    StrCpy (GetVariableNamePtr (Variable), GetVariableNamePtr (PubKeyHeader));\r
+    CopyMem (GetVariableDataPtr (Variable), NewPubKeyStore, NewPubKeySize);\r
+    CurrPtr = (UINT8*) GetNextVariablePtr (Variable); \r
+    CommonVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
+  } else {\r
+    //\r
+    // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
+    //\r
+    Variable = GetStartPointer (VariableStoreHeader);\r
+    while (IsValidVariableHeader (Variable)) {\r
+      NextVariable = GetNextVariablePtr (Variable);\r
+      if (Variable->State == VAR_ADDED) {\r
+        if (UpdatingVariable != NULL) {\r
+          if (UpdatingVariable == Variable) {\r
+            Variable = NextVariable;\r
+            continue;\r
+          }\r
 \r
-      //\r
-      // Buffer has cached all ADDED variable.\r
-      // Per IN_DELETED variable, we have to guarantee that\r
-      // no ADDED one in previous buffer.\r
-      //\r
+          VariableNameSize         = NameSizeOfVariable(Variable);\r
+          UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
 \r
-      FoundAdded = FALSE;\r
-      AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
-      while (IsValidVariableHeader (AddedVariable)) {\r
-        NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
-        NameSize = NameSizeOfVariable (AddedVariable);\r
-        if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
-            NameSize == NameSizeOfVariable (Variable)\r
-           ) {\r
-          Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
-          Point1 = (VOID *) GetVariableNamePtr (Variable);\r
-          if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
-            FoundAdded = TRUE;\r
-            break;\r
+          VariableNamePtr         = GetVariableNamePtr (Variable);\r
+          UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
+          if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid)    &&\r
+              VariableNameSize == UpdatingVariableNameSize &&\r
+              CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+            Variable = NextVariable;\r
+            continue;\r
           }\r
         }\r
-        AddedVariable = NextAddedVariable;\r
-      }\r
-      if (!FoundAdded) {\r
-        //\r
-        // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
-        //\r
         VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
-        ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
         CurrPtr += VariableSize;\r
         if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
           HwErrVariableTotalSize += VariableSize;\r
@@ -704,9 +919,74 @@ Reclaim (
           CommonVariableTotalSize += VariableSize;\r
         }\r
       }\r
+      Variable = NextVariable;\r
     }\r
 \r
-    Variable = NextVariable;\r
+    //\r
+    // Reinstall the variable being updated if it is not NULL.\r
+    //\r
+    if (UpdatingVariable != NULL) {\r
+      VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
+      CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
+      UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));\r
+      UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
+      CurrPtr += VariableSize;\r
+      if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          HwErrVariableTotalSize += VariableSize;\r
+      } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          CommonVariableTotalSize += VariableSize;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Reinstall all in delete transition variables.\r
+    //\r
+    Variable      = GetStartPointer (VariableStoreHeader);\r
+    while (IsValidVariableHeader (Variable)) {\r
+      NextVariable = GetNextVariablePtr (Variable);\r
+      if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+\r
+        //\r
+        // Buffer has cached all ADDED variable.\r
+        // Per IN_DELETED variable, we have to guarantee that\r
+        // no ADDED one in previous buffer.\r
+        //\r
+\r
+        FoundAdded = FALSE;\r
+        AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+        while (IsValidVariableHeader (AddedVariable)) {\r
+          NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
+          NameSize = NameSizeOfVariable (AddedVariable);\r
+          if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
+              NameSize == NameSizeOfVariable (Variable)\r
+             ) {\r
+            Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
+            Point1 = (VOID *) GetVariableNamePtr (Variable);\r
+            if (CompareMem (Point0, Point1, NameSize) == 0) {\r
+              FoundAdded = TRUE;\r
+              break;\r
+            }\r
+          }\r
+          AddedVariable = NextAddedVariable;\r
+        }\r
+        if (!FoundAdded) {\r
+          //\r
+          // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
+          //\r
+          VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+          CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+          ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+          CurrPtr += VariableSize;\r
+          if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+            HwErrVariableTotalSize += VariableSize;\r
+          } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+            CommonVariableTotalSize += VariableSize;\r
+          }\r
+        }\r
+      }\r
+\r
+      Variable = NextVariable;\r
+    }\r
   }\r
 \r
   if (IsVolatile) {\r
@@ -748,6 +1028,14 @@ Reclaim (
     *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
   }\r
 \r
+  if (NewPubKeyStore != NULL) {\r
+    FreePool (NewPubKeyStore);\r
+  }\r
+\r
+  if (NewPubKeyIndex != NULL) {\r
+    FreePool (NewPubKeyIndex);\r
+  }\r
+  \r
   FreePool (ValidBuffer);\r
 \r
   return Status;\r
@@ -776,6 +1064,8 @@ FindVariableEx (
   VARIABLE_HEADER                *InDeletedVariable;\r
   VOID                           *Point;\r
 \r
+  PtrTrack->InDeletedTransitionPtr = NULL;\r
+\r
   //\r
   // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
   //\r
@@ -793,6 +1083,7 @@ FindVariableEx (
           if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
             InDeletedVariable   = PtrTrack->CurrPtr;\r
           } else {\r
+            PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
             return EFI_SUCCESS;\r
           }\r
         } else {\r
@@ -804,6 +1095,7 @@ FindVariableEx (
               if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
                 InDeletedVariable     = PtrTrack->CurrPtr;\r
               } else {\r
+                PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
                 return EFI_SUCCESS;\r
               }\r
             }\r
@@ -1226,7 +1518,7 @@ AutoUpdateLangVariable (
 \r
   SetLanguageCodes = FALSE;\r
 \r
-  if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
+  if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {\r
     //\r
     // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
@@ -1256,7 +1548,7 @@ AutoUpdateLangVariable (
     mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
     ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
 \r
-  } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
+  } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {\r
     //\r
     // LangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
@@ -1284,21 +1576,21 @@ AutoUpdateLangVariable (
     // Update Lang if PlatformLang is already set\r
     // Update PlatformLang if Lang is already set\r
     //\r
-    Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+    Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update Lang\r
       //\r
-      VariableName = L"PlatformLang";\r
+      VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
       Data         = GetVariableDataPtr (Variable.CurrPtr);\r
       DataSize     = Variable.CurrPtr->DataSize;\r
     } else {\r
-      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+      Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
       if (!EFI_ERROR (Status)) {\r
         //\r
         // Update PlatformLang\r
         //\r
-        VariableName = L"Lang";\r
+        VariableName = EFI_LANG_VARIABLE_NAME;\r
         Data         = GetVariableDataPtr (Variable.CurrPtr);\r
         DataSize     = Variable.CurrPtr->DataSize;\r
       } else {\r
@@ -1315,7 +1607,7 @@ AutoUpdateLangVariable (
   //\r
   Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
 \r
-  if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
+  if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {\r
     //\r
     // Update Lang when PlatformLangCodes/LangCodes were set.\r
     //\r
@@ -1338,9 +1630,9 @@ AutoUpdateLangVariable (
         //\r
         // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
         //\r
-        FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
+        Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
                                  ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);\r
 \r
         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
@@ -1349,7 +1641,7 @@ AutoUpdateLangVariable (
       }\r
     }\r
 \r
-  } else if (StrCmp (VariableName, L"Lang") == 0) {\r
+  } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {\r
     //\r
     // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
     //\r
@@ -1372,9 +1664,9 @@ AutoUpdateLangVariable (
         //\r
         // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
         //\r
-        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang,\r
+        Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,\r
                                  AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);\r
 \r
         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
@@ -1395,7 +1687,7 @@ AutoUpdateLangVariable (
   @param[in] Attributes         Attributes of the variable.\r
   @param[in] KeyIndex           Index of associated public key.\r
   @param[in] MonotonicCount     Value of associated monotonic count.\r
-  @param[in] CacheVariable      The variable information which is used to keep track of variable usage.\r
+  @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
   @param[in] TimeStamp          Value of associated TimeStamp.\r
 \r
   @retval EFI_SUCCESS           The update operation is success.\r
@@ -1411,14 +1703,14 @@ UpdateVariable (
   IN      UINT32                      Attributes      OPTIONAL,\r
   IN      UINT32                      KeyIndex        OPTIONAL,\r
   IN      UINT64                      MonotonicCount  OPTIONAL,\r
-  IN      VARIABLE_POINTER_TRACK      *CacheVariable,\r
+  IN OUT  VARIABLE_POINTER_TRACK      *CacheVariable,\r
   IN      EFI_TIME                    *TimeStamp      OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
   VARIABLE_HEADER                     *NextVariable;\r
   UINTN                               ScratchSize;\r
-  UINTN                               ScratchDataSize;\r
+  UINTN                               MaxDataSize;\r
   UINTN                               NonVolatileVarableStoreSize;\r
   UINTN                               VarNameOffset;\r
   UINTN                               VarDataOffset;\r
@@ -1427,14 +1719,12 @@ UpdateVariable (
   BOOLEAN                             Volatile;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   UINT8                               State;\r
-  BOOLEAN                             Reclaimed;\r
   VARIABLE_POINTER_TRACK              *Variable;\r
   VARIABLE_POINTER_TRACK              NvVariable;\r
   VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
   UINTN                               CacheOffset;\r
   UINTN                               BufSize;\r
   UINTN                               DataOffset;\r
-  UINTN                               RevBufSize;\r
 \r
   if (mVariableModuleGlobal->FvbInstance == NULL) {\r
     //\r
@@ -1467,11 +1757,15 @@ UpdateVariable (
     Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
     Variable->EndPtr   = GetEndPointer (VariableStoreHeader);\r
     Variable->CurrPtr  = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
+    if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
+      Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
+    } else {\r
+      Variable->InDeletedTransitionPtr = NULL;\r
+    }\r
     Variable->Volatile = FALSE;\r
   }\r
 \r
   Fvb       = mVariableModuleGlobal->FvbInstance;\r
-  Reclaimed = FALSE;\r
 \r
   //\r
   // Tricky part: Use scratch data area at the end of volatile variable store\r
@@ -1479,7 +1773,7 @@ UpdateVariable (
   //\r
   NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
   ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
-  ScratchDataSize = ScratchSize - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));\r
+\r
 \r
   if (Variable->CurrPtr != NULL) {\r
     //\r
@@ -1519,6 +1813,32 @@ UpdateVariable (
     // not delete the variable.\r
     //\r
     if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {\r
+      if (Variable->InDeletedTransitionPtr != NULL) {\r
+        //\r
+        // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
+        // set IN_DELETED_TRANSITION one to DELETED state first.\r
+        //\r
+        State = Variable->InDeletedTransitionPtr->State;\r
+        State &= VAR_DELETED;\r
+        Status = UpdateVariableStore (\r
+                   &mVariableModuleGlobal->VariableGlobal,\r
+                   Variable->Volatile,\r
+                   FALSE,\r
+                   Fvb,\r
+                   (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+                   sizeof (UINT8),\r
+                   &State\r
+                   );\r
+        if (!EFI_ERROR (Status)) {\r
+          if (!Variable->Volatile) {\r
+            ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+            CacheVariable->InDeletedTransitionPtr->State = State;\r
+          }\r
+        } else {\r
+          goto Done;\r
+        }\r
+      }\r
+\r
       State = Variable->CurrPtr->State;\r
       State &= VAR_DELETED;\r
 \r
@@ -1567,14 +1887,36 @@ UpdateVariable (
         DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize);\r
         CopyMem (mStorageArea, (UINT8*)((UINTN) Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize);\r
 \r
-        if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) ||\r
-               (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
+        //\r
+        // Set Max Common Variable Data Size as default MaxDataSize \r
+        //\r
+        MaxDataSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));\r
+\r
+\r
+        if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
+            ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) ||\r
+            (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
+\r
           //\r
-          // For variables with the GUID EFI_IMAGE_SECURITY_DATABASE_GUID (i.e. where the data\r
-          // buffer is formatted as EFI_SIGNATURE_LIST), the driver shall not perform an append of\r
+          // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r
           // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
           //\r
-          BufSize = AppendSignatureList (mStorageArea, Variable->CurrPtr->DataSize, Data, DataSize);\r
+          Status = AppendSignatureList (\r
+                     mStorageArea, \r
+                     Variable->CurrPtr->DataSize, \r
+                     MaxDataSize - Variable->CurrPtr->DataSize,\r
+                     Data, \r
+                     DataSize, \r
+                     &BufSize\r
+                     );\r
+          if (Status == EFI_BUFFER_TOO_SMALL) {\r
+            //\r
+            // Signture List is too long, Failed to Append\r
+            //\r
+            Status = EFI_INVALID_PARAMETER;\r
+            goto Done;\r
+          }\r
+\r
           if (BufSize == Variable->CurrPtr->DataSize) {\r
             if ((TimeStamp == NULL) || CompareTimeStamp (TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
               //\r
@@ -1589,20 +1931,23 @@ UpdateVariable (
         } else {\r
           //\r
           // For other Variables, append the new data to the end of previous data.\r
+          // Max Harware error record variable data size is different from common variable\r
           //\r
+          if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+            MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));\r
+          }\r
+\r
+          if (Variable->CurrPtr->DataSize + DataSize > MaxDataSize) {\r
+            //\r
+            // Exsiting data + Appended data exceed maximum variable size limitation \r
+            //\r
+            Status = EFI_INVALID_PARAMETER;\r
+            goto Done;\r
+          }\r
           CopyMem ((UINT8*)((UINTN) mStorageArea + Variable->CurrPtr->DataSize), Data, DataSize);\r
           BufSize = Variable->CurrPtr->DataSize + DataSize;\r
         }\r
 \r
-        RevBufSize = MIN (PcdGet32 (PcdMaxVariableSize), ScratchDataSize);\r
-        if (BufSize > RevBufSize) {\r
-          //\r
-          // If variable size (previous + current) is bigger than reserved buffer in runtime,\r
-          // return EFI_OUT_OF_RESOURCES.\r
-          //\r
-          return EFI_OUT_OF_RESOURCES;\r
-        }\r
-\r
         //\r
         // Override Data and DataSize which are used for combined data area including previous and new data.\r
         //\r
@@ -1744,8 +2089,14 @@ UpdateVariable (
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
-      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
-                        &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr, FALSE);\r
+      Status = Reclaim (\r
+                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 FALSE,\r
+                 Variable,\r
+                 FALSE,\r
+                 FALSE\r
+                 );\r
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1759,7 +2110,10 @@ UpdateVariable (
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
-      Reclaimed = TRUE;\r
+      if (Variable->CurrPtr != NULL) {\r
+        CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+        CacheVariable->InDeletedTransitionPtr = NULL;\r
+      }\r
     }\r
     //\r
     // Four steps\r
@@ -1859,8 +2213,14 @@ UpdateVariable (
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
-      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
-                          &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr, FALSE);\r
+      Status = Reclaim (\r
+                 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
+                 &mVariableModuleGlobal->VolatileLastVariableOffset,\r
+                 TRUE,\r
+                 Variable,\r
+                 FALSE,\r
+                 FALSE\r
+                 );\r
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1873,7 +2233,10 @@ UpdateVariable (
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
-      Reclaimed = TRUE;\r
+      if (Variable->CurrPtr != NULL) {\r
+        CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+        CacheVariable->InDeletedTransitionPtr = NULL;\r
+      }\r
     }\r
 \r
     NextVariable->State = VAR_ADDED;\r
@@ -1897,7 +2260,33 @@ UpdateVariable (
   //\r
   // Mark the old variable as deleted.\r
   //\r
-  if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+  if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+    if (Variable->InDeletedTransitionPtr != NULL) {\r
+      //\r
+      // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
+      // set IN_DELETED_TRANSITION one to DELETED state first.\r
+      //\r
+      State = Variable->InDeletedTransitionPtr->State;\r
+      State &= VAR_DELETED;\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 Variable->Volatile,\r
+                 FALSE,\r
+                 Fvb,\r
+                 (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+                 sizeof (UINT8),\r
+                 &State\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        if (!Variable->Volatile) {\r
+          ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+          CacheVariable->InDeletedTransitionPtr->State = State;\r
+        }\r
+      } else {\r
+        goto Done;\r
+      }\r
+    }\r
+\r
     State = Variable->CurrPtr->State;\r
     State &= VAR_DELETED;\r
 \r
@@ -1983,6 +2372,115 @@ IsHwErrRecVariable (
   return TRUE;\r
 }\r
 \r
+/**\r
+  This code checks if variable guid is global variable guid first.\r
+  If yes, further check if variable name is in mGlobalVariableList or mGlobalVariableList2 and attributes matched.\r
+\r
+  @param[in] VariableName       Pointer to variable name.\r
+  @param[in] VendorGuid         Variable Vendor Guid.\r
+  @param[in] Attributes         Attributes of the variable.\r
+\r
+  @retval EFI_SUCCESS           Variable is not global variable, or Variable is global variable, variable name is in the lists and attributes matched.\r
+  @retval EFI_INVALID_PARAMETER Variable is global variable, but variable name is not in the lists or attributes unmatched.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CheckEfiGlobalVariable (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid,\r
+  IN UINT32             Attributes\r
+  )\r
+{\r
+  UINTN     Index;\r
+  UINTN     NameLength;\r
+\r
+  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)){\r
+    //\r
+    // Try list 1, exactly match.\r
+    //\r
+    for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {\r
+      if ((StrCmp (mGlobalVariableList[Index].Name, VariableName) == 0) &&\r
+          (Attributes == 0 || (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) == mGlobalVariableList[Index].Attributes)) {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Try list 2.\r
+    //\r
+    NameLength = StrLen (VariableName) - 4;\r
+    for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {\r
+      if ((StrLen (VariableName) == StrLen (mGlobalVariableList2[Index].Name)) &&\r
+          (StrnCmp (mGlobalVariableList2[Index].Name, VariableName, NameLength) == 0) &&\r
+          IsHexaDecimalDigitCharacter (VariableName[NameLength]) &&\r
+          IsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&\r
+          IsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&\r
+          IsHexaDecimalDigitCharacter (VariableName[NameLength + 3]) &&\r
+          (Attributes == 0 || (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) == mGlobalVariableList2[Index].Attributes)) {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "[Variable]: set global variable with invalid variable name or attributes - %g:%s:%x\n", VendorGuid, VariableName, Attributes));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Mark a variable that will become read-only after leaving the DXE phase of execution.\r
+\r
+  @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.\r
+  @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.\r
+  @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.\r
+\r
+  @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked\r
+                                as pending to be read-only.\r
+  @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
+                                Or VariableName is an empty string.\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 to hold the lock request.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableLockRequestToLock (\r
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
+  IN       CHAR16                       *VariableName,\r
+  IN       EFI_GUID                     *VendorGuid\r
+  )\r
+{\r
+  VARIABLE_ENTRY                  *Entry;\r
+\r
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mEndOfDxe) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));\r
+  if (Entry == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  Entry->Name = (CHAR16 *) (Entry + 1);\r
+  StrCpy   (Entry->Name, VariableName);\r
+  CopyGuid (&Entry->Guid, VendorGuid);\r
+  InsertTailList (&mLockedVariableList, &Entry->Link);\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   This code checks if variable should be treated as read-only variable.\r
 \r
@@ -2002,7 +2500,13 @@ IsReadOnlyVariable (
   if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {\r
     if ((StrCmp (VariableName, EFI_SETUP_MODE_NAME) == 0) ||\r
         (StrCmp (VariableName, EFI_SIGNATURE_SUPPORT_NAME) == 0) ||\r
-        (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0)) {\r
+        (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_VENDOR_KEYS_VARIABLE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_KEK_DEFAULT_VARIABLE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_PK_DEFAULT_VARIABLE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_DB_DEFAULT_VARIABLE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_DBX_DEFAULT_VARIABLE_NAME) == 0) ||\r
+        (StrCmp (VariableName, EFI_DBT_DEFAULT_VARIABLE_NAME) == 0)) {\r
       return TRUE;\r
     }\r
   }\r
@@ -2119,6 +2623,7 @@ VariableServiceGetNextVariableName (
   VARIABLE_STORE_TYPE     Type;\r
   VARIABLE_POINTER_TRACK  Variable;\r
   VARIABLE_POINTER_TRACK  VariableInHob;\r
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;\r
   UINTN                   VarNameSize;\r
   EFI_STATUS              Status;\r
   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];\r
@@ -2192,8 +2697,27 @@ VariableServiceGetNextVariableName (
     //\r
     // Variable is found\r
     //\r
-    if (Variable.CurrPtr->State == VAR_ADDED) {\r
-      if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
+    if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+      if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+        if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+          //\r
+          // If it is a IN_DELETED_TRANSITION variable,\r
+          // and there is also a same ADDED one at the same time,\r
+          // don't return it.\r
+          //\r
+          VariablePtrTrack.StartPtr = Variable.StartPtr;\r
+          VariablePtrTrack.EndPtr = Variable.EndPtr;\r
+          Status = FindVariableEx (\r
+                     GetVariableNamePtr (Variable.CurrPtr),\r
+                     &Variable.CurrPtr->VendorGuid,\r
+                     FALSE,\r
+                     &VariablePtrTrack\r
+                     );\r
+          if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {\r
+            Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+            continue;\r
+          }\r
+        }\r
 \r
         //\r
         // Don't return NV variable when HOB overrides it\r
@@ -2279,6 +2803,8 @@ VariableServiceSetVariable (
   VARIABLE_HEADER                     *NextVariable;\r
   EFI_PHYSICAL_ADDRESS                Point;\r
   UINTN                               PayloadSize;\r
+  LIST_ENTRY                          *Link;\r
+  VARIABLE_ENTRY                      *Entry;\r
 \r
   //\r
   // Check input parameters.\r
@@ -2340,14 +2866,20 @@ VariableServiceSetVariable (
     PayloadSize = DataSize;\r
   }\r
 \r
+  if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){\r
+    //\r
+    // Prevent whole variable size overflow \r
+    // \r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   //\r
   //  The size of the VariableName, including the Unicode Null in bytes plus\r
   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
   //  bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
   //\r
   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-    if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
+    if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
     if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
@@ -2358,20 +2890,14 @@ VariableServiceSetVariable (
     //  The size of the VariableName, including the Unicode Null in bytes plus\r
     //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
     //\r
-    if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) ||\r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) {\r
+    if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
   }\r
 \r
-  if (AtRuntime ()) {\r
-    //\r
-    // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
-    // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
-    //\r
-    if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
-      return EFI_WRITE_PROTECTED;\r
-    }\r
+  Status = CheckEfiGlobalVariable (VariableName, VendorGuid, Attributes);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
@@ -2392,13 +2918,41 @@ VariableServiceSetVariable (
     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
   }\r
 \r
+  if (mEndOfDxe && mEnableLocking) {\r
+    //\r
+    // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.\r
+    //\r
+    for ( Link = GetFirstNode (&mLockedVariableList)\r
+        ; !IsNull (&mLockedVariableList, Link)\r
+        ; Link = GetNextNode (&mLockedVariableList, Link)\r
+        ) {\r
+      Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
+      if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {\r
+        Status = EFI_WRITE_PROTECTED;\r
+        DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
   //\r
   // Check whether the input variable is already existed.\r
   //\r
   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
   if (!EFI_ERROR (Status)) {\r
     if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
-      return EFI_WRITE_PROTECTED;\r
+      Status = EFI_WRITE_PROTECTED;\r
+      goto Done;\r
+    }\r
+    if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {\r
+      //\r
+      // If a preexisting variable is rewritten with different attributes, SetVariable() shall not\r
+      // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:\r
+      // 1. No access attributes specified\r
+      // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE\r
+      //\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
     }\r
   }\r
   \r
@@ -2423,6 +2977,7 @@ VariableServiceSetVariable (
     Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
   }\r
 \r
+Done:\r
   InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
@@ -2629,12 +3184,142 @@ ReclaimForOS(
             &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
             FALSE,\r
             NULL,\r
+            FALSE,\r
             FALSE\r
             );\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 }\r
 \r
+/**\r
+  Init non-volatile variable store.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.\r
+\r
+**/\r
+EFI_STATUS\r
+InitNonVolatileVariableStore (\r
+  VOID\r
+  )\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
+  VARIABLE_HEADER                       *NextVariable;\r
+  EFI_PHYSICAL_ADDRESS                  VariableStoreBase;\r
+  UINT64                                VariableStoreLength;\r
+  UINTN                                 VariableSize;\r
+  EFI_HOB_GUID_TYPE                     *GuidHob;\r
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;\r
+  UINT8                                 *NvStorageData;\r
+  UINT32                                NvStorageSize;\r
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;\r
+  UINT32                                BackUpOffset;\r
+  UINT32                                BackUpSize;\r
+\r
+  mVariableModuleGlobal->FvbInstance = NULL;\r
+\r
+  //\r
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+  // is stored with common variable in the same NV region. So the platform integrator should\r
+  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
+  // PcdFlashNvStorageVariableSize.\r
+  //\r
+  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
+\r
+  //\r
+  // Allocate runtime memory used for a memory copy of the FLASH region.\r
+  // Keep the memory and the FLASH in sync as updates occur.\r
+  //\r
+  NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
+  NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
+  if (NvStorageData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageBase == 0) {\r
+    NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  //\r
+  // Copy NV storage data to the memory buffer.\r
+  //\r
+  CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
+\r
+  //\r
+  // Check the FTW last write data hob.\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+  if (GuidHob != NULL) {\r
+    FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+    if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+      DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+      //\r
+      // Copy the backed up NV storage data to the memory buffer from spare block.\r
+      //\r
+      CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
+    } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
+               (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+      //\r
+      // Flash NV storage from the Offset is backed up in spare block.\r
+      //\r
+      BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+      BackUpSize = NvStorageSize - BackUpOffset;\r
+      DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+      //\r
+      // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
+      //\r
+      CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+    }\r
+  }\r
+\r
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r
+\r
+  //\r
+  // Check if the Firmware Volume is not corrupted\r
+  //\r
+  if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
+    FreePool (NvStorageData);\r
+    DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
+  VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
+\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+  mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
+  if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
+    FreePool (NvStorageData);\r
+    DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
+\r
+  //\r
+  // The max variable or hardware error variable size should be < variable store size.\r
+  //\r
+  ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
+\r
+  //\r
+  // Parse non-volatile variable data and get last variable offset.\r
+  //\r
+  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+  while (IsValidVariableHeader (NextVariable)) {\r
+    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    }\r
+\r
+    NextVariable = GetNextVariablePtr (NextVariable);\r
+  }\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Flush the HOB variable to flash.\r
 \r
@@ -2726,7 +3411,7 @@ FlushHobVariableToFlash (
 }\r
 \r
 /**\r
-  Initializes variable write service after FVB was ready.\r
+  Initializes variable write service after FTW was ready.\r
 \r
   @retval EFI_SUCCESS          Function successfully executed.\r
   @retval Others               Fail to initialize the variable service.\r
@@ -2742,8 +3427,18 @@ VariableWriteServiceInitialize (
   UINTN                           Index;\r
   UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  EFI_PHYSICAL_ADDRESS            NvStorageBase;\r
+\r
+  NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageBase == 0) {\r
+    NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
 \r
-  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+  //\r
+  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
 \r
   //\r
@@ -2760,6 +3455,7 @@ VariableWriteServiceInitialize (
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
                  NULL,\r
+                 FALSE,\r
                  TRUE\r
                  );\r
       if (EFI_ERROR (Status)) {\r
@@ -2795,12 +3491,8 @@ VariableCommonInitialize (
   EFI_STATUS                      Status;\r
   VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
-  VARIABLE_HEADER                 *NextVariable;\r
-  EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
-  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINT64                          VariableStoreLength;\r
   UINTN                           ScratchSize;\r
-  UINTN                           VariableSize;\r
   EFI_HOB_GUID_TYPE               *GuidHob;\r
 \r
   //\r
@@ -2813,14 +3505,6 @@ VariableCommonInitialize (
 \r
   InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
 \r
-  //\r
-  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
-  // is stored with common variable in the same NV region. So the platform integrator should\r
-  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
-  // PcdFlashNvStorageVariableSize.\r
-  //\r
-  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
-\r
   //\r
   // Get HOB variable store.\r
   //\r
@@ -2831,6 +3515,7 @@ VariableCommonInitialize (
     if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
       mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
       if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+        FreePool (mVariableModuleGlobal);\r
         return EFI_OUT_OF_RESOURCES;\r
       }\r
     } else {\r
@@ -2844,6 +3529,9 @@ VariableCommonInitialize (
   ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
   VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
   if (VolatileVariableStore == NULL) {\r
+    if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+      FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+    }\r
     FreePool (mVariableModuleGlobal);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -2855,7 +3543,6 @@ VariableCommonInitialize (
   //\r
   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
-  mVariableModuleGlobal->FvbInstance = NULL;\r
 \r
   CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
   VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);\r
@@ -2865,69 +3552,13 @@ VariableCommonInitialize (
   VolatileVariableStore->Reserved1   = 0;\r
 \r
   //\r
-  // Get non-volatile variable store.\r
-  //\r
-\r
-  TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
-  if (TempVariableStoreHeader == 0) {\r
-    TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
-  }\r
-  \r
-  //\r
-  // Check if the Firmware Volume is not corrupted\r
-  //\r
-  if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
-      (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
-    Status = EFI_VOLUME_CORRUPTED;\r
-    DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
-    goto Done;\r
-  }\r
-\r
-  VariableStoreBase       = TempVariableStoreHeader + \\r
-                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-  VariableStoreLength     = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
-                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-\r
-  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
-  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
-    Status = EFI_VOLUME_CORRUPTED;\r
-    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
-    goto Done;\r
-  }\r
-  ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
-\r
-  //\r
-  // Parse non-volatile variable data and get last variable offset.\r
-  //\r
-  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
-  while (IsValidVariableHeader (NextVariable)) {\r
-    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
-    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-    } else {\r
-      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-    }\r
-\r
-    NextVariable = GetNextVariablePtr (NextVariable);\r
-  }\r
-\r
-  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
-\r
-  //\r
-  // Allocate runtime memory used for a memory copy of the FLASH region.\r
-  // Keep the memory and the FLASH in sync as updates occur\r
+  // Init non-volatile variable store.\r
   //\r
-  mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
-  if (mNvVariableCache == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
-  }\r
-  CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
-  Status = EFI_SUCCESS;\r
-\r
-Done:\r
+  Status = InitNonVolatileVariableStore ();\r
   if (EFI_ERROR (Status)) {\r
+    if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+      FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+    }\r
     FreePool (mVariableModuleGlobal);\r
     FreePool (VolatileVariableStore);\r
   }\r