]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
Check the input VaraibleName for db/dbx when appending variables with formatted as...
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
index bae5f7bc45bdfa1361e659b5e7377d05c9675a02..ce4f6e813ef833b800ac3223b8f6459cd6746bd0 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
   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
 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
@@ -511,20 +511,157 @@ GetEndPointer (
   return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
 }\r
 \r
   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
 \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
+/**\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
+  Filter the useless key in public key store.\r
 \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_OUT_OF_RESOURCES         No enough memory resources.\r
+  @return EFI_SUCCESS                  Reclaim operation has finished successfully.\r
+  @return Others                       Unexpect error happened during reclaim operation.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -532,7 +669,9 @@ Reclaim (
   IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
   OUT UINTN                 *LastVariableOffset,\r
   IN  BOOLEAN               IsVolatile,\r
   IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
   OUT UINTN                 *LastVariableOffset,\r
   IN  BOOLEAN               IsVolatile,\r
-  IN  VARIABLE_HEADER       *UpdatingVariable\r
+  IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
+  IN  BOOLEAN               ReclaimPubKeyStore,\r
+  IN  BOOLEAN               ReclaimAnyway\r
   )\r
 {\r
   VARIABLE_HEADER       *Variable;\r
   )\r
 {\r
   VARIABLE_HEADER       *Variable;\r
@@ -553,16 +692,30 @@ Reclaim (
   EFI_STATUS            Status;\r
   CHAR16                *VariableNamePtr;\r
   CHAR16                *UpdatingVariableNamePtr;\r
   EFI_STATUS            Status;\r
   CHAR16                *VariableNamePtr;\r
   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
 \r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
-  //\r
-  // Recalculate the total size of Common/HwErr type variables in non-volatile area.\r
-  //\r
-  if (!IsVolatile) {\r
-    mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
-    mVariableModuleGlobal->HwErrVariableTotalSize  = 0;\r
+  UpdatingVariable = NULL;\r
+  if (UpdatingPtrTrack != NULL) {\r
+    UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
   }\r
 \r
   }\r
 \r
+  NeedDoReclaim = FALSE;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize  = 0;\r
+  NewPubKeyIndex = NULL;\r
+  NewPubKeyStore = NULL;\r
+  NewPubKeySize  = 0;\r
+  PubKeyHeader   = NULL;\r
+  \r
   //\r
   // Start Pointers for the variable.\r
   //\r
   //\r
   // Start Pointers for the variable.\r
   //\r
@@ -576,11 +729,18 @@ Reclaim (
        ) {\r
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
       MaximumBufferSize += VariableSize;\r
        ) {\r
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
       MaximumBufferSize += VariableSize;\r
+    } else {\r
+      NeedDoReclaim = TRUE;\r
     }\r
 \r
     Variable = NextVariable;\r
   }\r
 \r
     }\r
 \r
     Variable = NextVariable;\r
   }\r
 \r
+  if (!ReclaimAnyway && !NeedDoReclaim) {\r
+    DEBUG ((EFI_D_INFO, "Variable driver: no DELETED variable found, so no variable space could be reclaimed.\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   //\r
   // Reserve the 1 Bytes with Oxff to identify the\r
   // end of the variable buffer.\r
   //\r
   // Reserve the 1 Bytes with Oxff to identify the\r
   // end of the variable buffer.\r
@@ -599,105 +759,166 @@ Reclaim (
   CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
 \r
   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
 \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
           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
       }\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
-        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
-      } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
-      }\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
-        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
-    } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+      Variable = NextVariable;\r
     }\r
     }\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
+    // Reinstall the new public key database.\r
+    //\r
+    ASSERT (PubKeyHeader != NULL);\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
-      //\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
 \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
           }\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
         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
         CurrPtr += VariableSize;\r
         if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+          HwErrVariableTotalSize += VariableSize;\r
         } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
         } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-          mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+          CommonVariableTotalSize += VariableSize;\r
         }\r
       }\r
         }\r
       }\r
+      Variable = NextVariable;\r
     }\r
 \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
   }\r
 \r
   if (IsVolatile) {\r
@@ -720,10 +941,33 @@ Reclaim (
   }\r
   if (!EFI_ERROR (Status)) {\r
     *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
   }\r
   if (!EFI_ERROR (Status)) {\r
     *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+    if (!IsVolatile) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+      mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+    }\r
   } else {\r
   } else {\r
-    *LastVariableOffset = 0;\r
+    NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
+    while (IsValidVariableHeader (NextVariable)) {\r
+      VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+      if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+      } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+      }\r
+\r
+      NextVariable = GetNextVariablePtr (NextVariable);\r
+    }\r
+    *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
   }\r
 \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
   FreePool (ValidBuffer);\r
 \r
   return Status;\r
@@ -752,6 +996,8 @@ FindVariableEx (
   VARIABLE_HEADER                *InDeletedVariable;\r
   VOID                           *Point;\r
 \r
   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
   //\r
   // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
   //\r
@@ -769,6 +1015,7 @@ FindVariableEx (
           if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
             InDeletedVariable   = PtrTrack->CurrPtr;\r
           } else {\r
           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
             return EFI_SUCCESS;\r
           }\r
         } else {\r
@@ -780,6 +1027,7 @@ FindVariableEx (
               if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
                 InDeletedVariable     = PtrTrack->CurrPtr;\r
               } else {\r
               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
                 return EFI_SUCCESS;\r
               }\r
             }\r
@@ -1371,7 +1619,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] 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
   @param[in] TimeStamp          Value of associated TimeStamp.\r
 \r
   @retval EFI_SUCCESS           The update operation is success.\r
@@ -1387,7 +1635,7 @@ UpdateVariable (
   IN      UINT32                      Attributes      OPTIONAL,\r
   IN      UINT32                      KeyIndex        OPTIONAL,\r
   IN      UINT64                      MonotonicCount  OPTIONAL,\r
   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
   IN      EFI_TIME                    *TimeStamp      OPTIONAL\r
   )\r
 {\r
@@ -1403,7 +1651,6 @@ UpdateVariable (
   BOOLEAN                             Volatile;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   UINT8                               State;\r
   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
   VARIABLE_POINTER_TRACK              *Variable;\r
   VARIABLE_POINTER_TRACK              NvVariable;\r
   VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
@@ -1443,11 +1690,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
     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
     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
 \r
   //\r
   // Tricky part: Use scratch data area at the end of volatile variable store\r
@@ -1495,6 +1746,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
     // 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
       State = Variable->CurrPtr->State;\r
       State &= VAR_DELETED;\r
 \r
@@ -1511,6 +1788,7 @@ UpdateVariable (
         UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
         if (!Variable->Volatile) {\r
           CacheVariable->CurrPtr->State = State;\r
         UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
         if (!Variable->Volatile) {\r
           CacheVariable->CurrPtr->State = State;\r
+          FlushHobVariableToFlash (VariableName, VendorGuid);\r
         }\r
       }\r
       goto Done;\r
         }\r
       }\r
       goto Done;\r
@@ -1542,11 +1820,11 @@ 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
         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
+        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
           // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
           //\r
           BufSize = AppendSignatureList (mStorageArea, Variable->CurrPtr->DataSize, Data, DataSize);\r
@@ -1719,8 +1997,14 @@ UpdateVariable (
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
-      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
-                        &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\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
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1734,7 +2018,10 @@ UpdateVariable (
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
         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
     }\r
     //\r
     // Four steps\r
@@ -1834,8 +2121,14 @@ UpdateVariable (
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
       //\r
       // Perform garbage collection & reclaim operation.\r
       //\r
-      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
-                          &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\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
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1848,7 +2141,10 @@ UpdateVariable (
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
         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
     }\r
 \r
     NextVariable->State = VAR_ADDED;\r
@@ -1872,7 +2168,33 @@ UpdateVariable (
   //\r
   // Mark the old variable as deleted.\r
   //\r
   //\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
     State = Variable->CurrPtr->State;\r
     State &= VAR_DELETED;\r
 \r
@@ -1892,6 +2214,9 @@ UpdateVariable (
 \r
   if (!EFI_ERROR (Status)) {\r
     UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
 \r
   if (!EFI_ERROR (Status)) {\r
     UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+    if (!Volatile) {\r
+      FlushHobVariableToFlash (VariableName, VendorGuid);\r
+    }\r
   }\r
 \r
 Done:\r
   }\r
 \r
 Done:\r
@@ -1955,6 +2280,33 @@ IsHwErrRecVariable (
   return TRUE;\r
 }\r
 \r
   return TRUE;\r
 }\r
 \r
+/**\r
+  This code checks if variable should be treated as read-only variable.\r
+\r
+  @param[in]      VariableName            Name of the Variable.\r
+  @param[in]      VendorGuid              GUID of the Variable.\r
+\r
+  @retval TRUE      This variable is read-only variable.\r
+  @retval FALSE     This variable is NOT read-only variable.\r
+  \r
+**/\r
+BOOLEAN\r
+IsReadOnlyVariable (\r
+  IN     CHAR16         *VariableName,\r
+  IN     EFI_GUID       *VendorGuid\r
+  )\r
+{\r
+  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
+      return TRUE;\r
+    }\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\r
 /**\r
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
 /**\r
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
@@ -2064,6 +2416,7 @@ VariableServiceGetNextVariableName (
   VARIABLE_STORE_TYPE     Type;\r
   VARIABLE_POINTER_TRACK  Variable;\r
   VARIABLE_POINTER_TRACK  VariableInHob;\r
   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
   UINTN                   VarNameSize;\r
   EFI_STATUS              Status;\r
   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];\r
@@ -2137,8 +2490,27 @@ VariableServiceGetNextVariableName (
     //\r
     // Variable is found\r
     //\r
     //\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
 \r
         //\r
         // Don't return NV variable when HOB overrides it\r
@@ -2232,10 +2604,21 @@ VariableServiceSetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (IsReadOnlyVariable (VariableName, VendorGuid)) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+\r
   if (DataSize != 0 && Data == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   if (DataSize != 0 && Data == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // Check for reserverd bit in variable attribute.\r
+  //\r
+  if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   //\r
   //  Make sure if runtime bit is set, boot service bit is set also.\r
   //\r
   //\r
   //  Make sure if runtime bit is set, boot service bit is set also.\r
   //\r
@@ -2349,7 +2732,10 @@ VariableServiceSetVariable (
     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
   } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
           ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
   } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
           ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
-    Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+    }\r
   } else {\r
     Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
   }\r
   } else {\r
     Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
   }\r
@@ -2559,12 +2945,103 @@ ReclaimForOS(
             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
             &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
             FALSE,\r
             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
             &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
             FALSE,\r
-            NULL\r
+            NULL,\r
+            FALSE,\r
+            FALSE\r
             );\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 }\r
 \r
             );\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 }\r
 \r
+/**\r
+  Flush the HOB variable to flash.\r
+\r
+  @param[in] VariableName       Name of variable has been updated or deleted.\r
+  @param[in] VendorGuid         Guid of variable has been updated or deleted.\r
+\r
+**/\r
+VOID\r
+FlushHobVariableToFlash (\r
+  IN CHAR16                     *VariableName,\r
+  IN EFI_GUID                   *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;\r
+  VARIABLE_HEADER               *Variable;\r
+  VOID                          *VariableData;\r
+  BOOLEAN                       ErrorFlag;\r
+\r
+  ErrorFlag = FALSE;\r
+\r
+  //\r
+  // Flush the HOB variable to flash.\r
+  //\r
+  if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
+    //\r
+    // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
+    //\r
+    mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
+    for ( Variable = GetStartPointer (VariableStoreHeader)\r
+        ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
+        ; Variable = GetNextVariablePtr (Variable)\r
+        ) {\r
+      if (Variable->State != VAR_ADDED) {\r
+        //\r
+        // The HOB variable has been set to DELETED state in local.\r
+        //\r
+        continue;\r
+      }\r
+      ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
+      if (VendorGuid == NULL || VariableName == NULL ||\r
+          !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
+          StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
+        VariableData = GetVariableDataPtr (Variable);\r
+        Status = VariableServiceSetVariable (\r
+                   GetVariableNamePtr (Variable),\r
+                   &Variable->VendorGuid,\r
+                   Variable->Attributes,\r
+                   Variable->DataSize,\r
+                   VariableData\r
+                   );\r
+        DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
+      } else {\r
+        //\r
+        // The updated or deleted variable is matched with the HOB variable.\r
+        // Don't break here because we will try to set other HOB variables\r
+        // since this variable could be set successfully.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+      }\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
+        // set the HOB variable to DELETED state in local.\r
+        //\r
+        DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
+        Variable->State &= VAR_DELETED;\r
+      } else {\r
+        ErrorFlag = TRUE;\r
+      }\r
+    }\r
+    if (ErrorFlag) {\r
+      //\r
+      // We still have HOB variable(s) not flushed in flash.\r
+      //\r
+      mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+    } else {\r
+      //\r
+      // All HOB variables have been flushed in flash.\r
+      //\r
+      DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
+      if (!AtRuntime ()) {\r
+        FreePool ((VOID *) VariableStoreHeader);\r
+      }\r
+    }\r
+  }\r
+\r
+}\r
 \r
 /**\r
   Initializes variable write service after FVB was ready.\r
 \r
 /**\r
   Initializes variable write service after FVB was ready.\r
@@ -2583,8 +3060,6 @@ VariableWriteServiceInitialize (
   UINTN                           Index;\r
   UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINTN                           Index;\r
   UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
-  VARIABLE_HEADER                 *Variable;\r
-  VOID                            *VariableData;\r
 \r
   VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
 \r
   VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
@@ -2602,7 +3077,9 @@ VariableWriteServiceInitialize (
                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
-                 NULL\r
+                 NULL,\r
+                 FALSE,\r
+                 TRUE\r
                  );\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
                  );\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
@@ -2611,34 +3088,7 @@ VariableWriteServiceInitialize (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
-\r
-  //\r
-  // Flush the HOB variable to flash and invalidate HOB variable.\r
-  //\r
-  if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
-    //\r
-    // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB\r
-    //\r
-    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
-    mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
-\r
-    for ( Variable = GetStartPointer (VariableStoreHeader)\r
-        ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
-        ; Variable = GetNextVariablePtr (Variable)\r
-        ) {\r
-      ASSERT (Variable->State == VAR_ADDED);\r
-      ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
-      VariableData = GetVariableDataPtr (Variable);\r
-      Status = VariableServiceSetVariable (\r
-                 GetVariableNamePtr (Variable),\r
-                 &Variable->VendorGuid,\r
-                 Variable->Attributes,\r
-                 Variable->DataSize,\r
-                 VariableData\r
-                 );\r
-      ASSERT_EFI_ERROR (Status);\r
-    }\r
-  }\r
+  FlushHobVariableToFlash (NULL, NULL);\r
 \r
   //\r
   // Authenticated variable initialize.\r
 \r
   //\r
   // Authenticated variable initialize.\r
@@ -2696,8 +3146,12 @@ VariableCommonInitialize (
   GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
   if (GuidHob != NULL) {\r
     VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
   GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
   if (GuidHob != NULL) {\r
     VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+    VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
     if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
     if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
-      mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+      mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
+      if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
     } else {\r
       DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
     }\r
     } else {\r
       DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
     }\r