]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Fix potential overflow for SetVariable interface
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index 14d5d9c1286dd3ddf89021485e47ca0a99f18c73..cd3f5ef475dd21022ca1b9b60961f3bf0337869f 100644 (file)
@@ -1,9 +1,9 @@
 /** @file\r
 \r
-  The common variable operation routines shared by DXE_RINTIME variable \r
+  The common variable operation routines shared by DXE_RUNTIME variable \r
   module and DXE_SMM variable module.\r
   \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 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
@@ -504,7 +504,8 @@ GetEndPointer (
   @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 UpdatingPtrTrack        Pointer to updating variable pointer track structure.\r
+  @param ReclaimAnyway           If TRUE, do reclaim anyway.\r
 \r
   @return EFI_OUT_OF_RESOURCES\r
   @return EFI_SUCCESS\r
@@ -516,7 +517,8 @@ Reclaim (
   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               ReclaimAnyway\r
   )\r
 {\r
   VARIABLE_HEADER       *Variable;\r
@@ -537,15 +539,21 @@ Reclaim (
   EFI_STATUS            Status;\r
   CHAR16                *VariableNamePtr;\r
   CHAR16                *UpdatingVariableNamePtr;\r
+  UINTN                 CommonVariableTotalSize;\r
+  UINTN                 HwErrVariableTotalSize;\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
-  // 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
-  }\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize  = 0;\r
 \r
   //\r
   // Start Pointers for the variable.\r
@@ -560,11 +568,18 @@ Reclaim (
        ) {\r
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
       MaximumBufferSize += VariableSize;\r
+    } else {\r
+      NeedDoReclaim = TRUE;\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
@@ -612,9 +627,9 @@ Reclaim (
       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
+        HwErrVariableTotalSize += VariableSize;\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
     Variable = NextVariable;\r
@@ -626,11 +641,13 @@ Reclaim (
   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
-        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+        HwErrVariableTotalSize += VariableSize;\r
     } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+        CommonVariableTotalSize += VariableSize;\r
     }\r
   }\r
 \r
@@ -658,7 +675,7 @@ Reclaim (
            ) {\r
           Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
           Point1 = (VOID *) GetVariableNamePtr (Variable);\r
-          if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
+          if (CompareMem (Point0, Point1, NameSize) == 0) {\r
             FoundAdded = TRUE;\r
             break;\r
           }\r
@@ -674,9 +691,9 @@ Reclaim (
         ((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
-          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+          HwErrVariableTotalSize += VariableSize;\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
@@ -704,8 +721,23 @@ Reclaim (
   }\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
-    *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
   FreePool (ValidBuffer);\r
@@ -718,6 +750,8 @@ Reclaim (
 \r
   @param  VariableName        Name of the variable to be found\r
   @param  VendorGuid          Vendor GUID to be found.\r
+  @param  IgnoreRtCheck       Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
+                              check at runtime when searching variable.\r
   @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.\r
 \r
   @retval  EFI_SUCCESS            Variable found successfully\r
@@ -727,12 +761,15 @@ EFI_STATUS
 FindVariableEx (\r
   IN     CHAR16                  *VariableName,\r
   IN     EFI_GUID                *VendorGuid,\r
+  IN     BOOLEAN                 IgnoreRtCheck,\r
   IN OUT VARIABLE_POINTER_TRACK  *PtrTrack\r
   )\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
@@ -745,11 +782,12 @@ FindVariableEx (
     if (PtrTrack->CurrPtr->State == VAR_ADDED || \r
         PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
        ) {\r
-      if (!AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+      if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
         if (VariableName[0] == 0) {\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
@@ -761,6 +799,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
@@ -781,7 +820,9 @@ FindVariableEx (
   This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
   If VariableName is an empty string, then we just return the first\r
   qualified variable without comparing VariableName and VendorGuid.\r
-  Otherwise, VariableName and VendorGuid are compared.\r
+  If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
+  at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
+  Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
 \r
   @param  VariableName                Name of the variable to be found.\r
   @param  VendorGuid                  Vendor GUID to be found.\r
@@ -790,6 +831,8 @@ FindVariableEx (
   @param  Global                      Pointer to VARIABLE_GLOBAL structure, including\r
                                       base of volatile variable storage area, base of\r
                                       NV variable storage area, and a lock.\r
+  @param  IgnoreRtCheck               Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
+                                      check at runtime when searching variable.\r
 \r
   @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
                                       VendorGuid is NULL.\r
@@ -802,7 +845,8 @@ FindVariable (
   IN  CHAR16                  *VariableName,\r
   IN  EFI_GUID                *VendorGuid,\r
   OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
-  IN  VARIABLE_GLOBAL         *Global\r
+  IN  VARIABLE_GLOBAL         *Global,\r
+  IN  BOOLEAN                 IgnoreRtCheck\r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -834,7 +878,7 @@ FindVariable (
     PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);\r
     PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);\r
 \r
-    Status = FindVariableEx (VariableName, VendorGuid, PtrTrack);\r
+    Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);\r
     if (!EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
@@ -1153,7 +1197,7 @@ VariableGetBestLanguage (
 \r
 **/\r
 VOID\r
-AutoUpdateLangVariable(\r
+AutoUpdateLangVariable (\r
   IN  CHAR16             *VariableName,\r
   IN  VOID               *Data,\r
   IN  UINTN              DataSize\r
@@ -1234,7 +1278,7 @@ 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);\r
+    Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update Lang\r
@@ -1243,7 +1287,7 @@ AutoUpdateLangVariable(
       Data         = GetVariableDataPtr (Variable.CurrPtr);\r
       DataSize     = Variable.CurrPtr->DataSize;\r
     } else {\r
-      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
       if (!EFI_ERROR (Status)) {\r
         //\r
         // Update PlatformLang\r
@@ -1288,7 +1332,7 @@ AutoUpdateLangVariable(
         //\r
         // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
         //\r
-        FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
+        FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
         Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
                                  ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
@@ -1322,7 +1366,7 @@ 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);\r
+        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
         Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, \r
                                  AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
@@ -1343,7 +1387,7 @@ AutoUpdateLangVariable(
   @param[in] Data               Variable data.\r
   @param[in] DataSize           Size of data. 0 means delete.\r
   @param[in] Attributes         Attribues of the variable.\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
   \r
   @retval EFI_SUCCESS           The update operation is success.\r
   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
@@ -1356,7 +1400,7 @@ UpdateVariable (
   IN      VOID                        *Data,\r
   IN      UINTN                       DataSize,\r
   IN      UINT32                      Attributes      OPTIONAL,\r
-  IN      VARIABLE_POINTER_TRACK      *CacheVariable\r
+  IN OUT  VARIABLE_POINTER_TRACK      *CacheVariable\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
@@ -1370,7 +1414,6 @@ 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
@@ -1397,11 +1440,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
   if (Variable->CurrPtr != NULL) {\r
     //\r
@@ -1418,9 +1465,9 @@ UpdateVariable (
         goto Done;\r
       }\r
       //\r
-      // Only variable that have NV attributes can be updated/deleted in Runtime.\r
+      // Only variable that have NV|RT attributes can be updated/deleted in Runtime.\r
       //\r
-      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+      if (((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;      \r
       }\r
@@ -1431,6 +1478,32 @@ UpdateVariable (
     // causes it to be deleted.\r
     //\r
     if (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
@@ -1447,6 +1520,7 @@ UpdateVariable (
         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
@@ -1574,7 +1648,7 @@ UpdateVariable (
       // Perform garbage collection & reclaim operation.\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
-                        &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
+                        &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable, FALSE);\r
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1588,7 +1662,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
@@ -1689,7 +1766,7 @@ UpdateVariable (
       // Perform garbage collection & reclaim operation.\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
-                          &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
+                          &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable, FALSE);\r
       if (EFI_ERROR (Status)) {\r
         goto Done;\r
       }\r
@@ -1702,7 +1779,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
@@ -1726,7 +1806,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
@@ -1746,12 +1852,72 @@ UpdateVariable (
 \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
   return Status;\r
 }\r
 \r
+/**\r
+  Check if a Unicode character is a hexadecimal character.\r
+\r
+  This function checks if a Unicode character is a \r
+  hexadecimal character.  The valid hexadecimal character is \r
+  L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+  @param Char           The character to check against.\r
+\r
+  @retval TRUE          If the Char is a hexadecmial character.\r
+  @retval FALSE         If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHexaDecimalDigitCharacter (\r
+  IN CHAR16             Char\r
+  )\r
+{\r
+  return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
+\r
+/**\r
+\r
+  This code checks if variable is hardware error record variable or not.\r
+\r
+  According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
+  and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
+\r
+  @param VariableName   Pointer to variable name.\r
+  @param VendorGuid     Variable Vendor Guid.\r
+\r
+  @retval TRUE          Variable is hardware error record variable.\r
+  @retval FALSE         Variable is not hardware error record variable.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHwErrRecVariable (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid\r
+  )\r
+{\r
+  if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
+      (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
+      (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
 /**\r
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
@@ -1789,7 +1955,7 @@ VariableServiceGetVariable (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
   \r
-  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -1854,6 +2020,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
@@ -1864,7 +2031,7 @@ VariableServiceGetNextVariableName (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
-  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -1927,8 +2094,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
@@ -1941,6 +2127,7 @@ VariableServiceGetNextVariableName (
           Status = FindVariableEx (\r
                      GetVariableNamePtr (Variable.CurrPtr),\r
                      &Variable.CurrPtr->VendorGuid,\r
+                     FALSE,\r
                      &VariableInHob\r
                      );\r
           if (!EFI_ERROR (Status)) {\r
@@ -2031,20 +2218,23 @@ VariableServiceSetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if ((UINTN)(~0) - DataSize < 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 ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
+    if ( StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
-    //\r
-    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
-    //\r
-    if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+    if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
   } else {\r
@@ -2052,11 +2242,20 @@ 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 ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||\r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
+    if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
       return EFI_INVALID_PARAMETER;\r
     }  \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
+  }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
@@ -2079,7 +2278,12 @@ VariableServiceSetVariable (
   //\r
   // Check whether the input variable is already existed.\r
   //\r
-  FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\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
+    }\r
+  }\r
 \r
   //\r
   // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
@@ -2292,12 +2496,102 @@ ReclaimForOS(
             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
             &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
             FALSE,\r
-            NULL\r
+            NULL,\r
+            FALSE\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
@@ -2316,8 +2610,6 @@ VariableWriteServiceInitialize (
   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
@@ -2335,7 +2627,8 @@ VariableWriteServiceInitialize (
                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
-                 NULL\r
+                 NULL,\r
+                 TRUE\r
                  );\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
@@ -2344,33 +2637,8 @@ VariableWriteServiceInitialize (
     }\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
+  FlushHobVariableToFlash (NULL, NULL);\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
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -2422,8 +2690,12 @@ VariableCommonInitialize (
   GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\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
-      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
@@ -2463,6 +2735,17 @@ VariableCommonInitialize (
   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
@@ -2477,6 +2760,11 @@ VariableCommonInitialize (
   }  \r
   ASSERT(VariableStoreHeader->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