]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
Vlv2TbltDevicePkg: Use the merged Variable driver
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
index 576623e88bea49d046eab7650cbce4cf88e78078..15d053186cb0a85b15b8d6ec7acda001a99eccf2 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 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -58,6 +58,24 @@ BOOLEAN                mEndOfDxe              = FALSE;
 ///\r
 BOOLEAN                mEnableLocking         = TRUE;\r
 \r
+//\r
+// It will record the current boot error flag before EndOfDxe.\r
+//\r
+VAR_ERROR_FLAG         mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;\r
+\r
+/**\r
+\r
+  SecureBoot Hook for auth variable update.\r
+\r
+  @param[in] VariableName                 Name of Variable to be found.\r
+  @param[in] VendorGuid                   Variable vendor GUID.\r
+**/\r
+VOID\r
+EFIAPI\r
+SecureBootHook (\r
+  IN CHAR16                                 *VariableName,\r
+  IN EFI_GUID                               *VendorGuid\r
+  );\r
 \r
 /**\r
   Routine used to track statistical information about variable usage.\r
@@ -159,18 +177,24 @@ UpdateVariableInfo (
 \r
   This code checks if variable header is valid or not.\r
 \r
-  @param Variable        Pointer to the Variable Header.\r
+  @param Variable           Pointer to the Variable Header.\r
+  @param VariableStoreEnd   Pointer to the Variable Store End.\r
 \r
-  @retval TRUE           Variable header is valid.\r
-  @retval FALSE          Variable header is not valid.\r
+  @retval TRUE              Variable header is valid.\r
+  @retval FALSE             Variable header is not valid.\r
 \r
 **/\r
 BOOLEAN\r
 IsValidVariableHeader (\r
-  IN  VARIABLE_HEADER   *Variable\r
+  IN  VARIABLE_HEADER       *Variable,\r
+  IN  VARIABLE_HEADER       *VariableStoreEnd\r
   )\r
 {\r
-  if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
+  if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {\r
+    //\r
+    // Variable is NULL or has reached the end of variable store,\r
+    // or the StartId is not correct.\r
+    //\r
     return FALSE;\r
   }\r
 \r
@@ -470,10 +494,6 @@ GetNextVariablePtr (
 {\r
   UINTN Value;\r
 \r
-  if (!IsValidVariableHeader (Variable)) {\r
-    return NULL;\r
-  }\r
-\r
   Value =  (UINTN) GetVariableDataPtr (Variable);\r
   Value += DataSizeOfVariable (Variable);\r
   Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
@@ -527,18 +547,241 @@ GetEndPointer (
   return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
 }\r
 \r
+/**\r
+  Record variable error flag.\r
+\r
+  @param[in] Flag               Variable error flag to record.\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Attributes         Attributes of the variable.\r
+  @param[in] VariableSize       Size of the variable.\r
+\r
+**/\r
+VOID\r
+RecordVarErrorFlag (\r
+  IN VAR_ERROR_FLAG         Flag,\r
+  IN CHAR16                 *VariableName,\r
+  IN EFI_GUID               *VendorGuid,\r
+  IN UINT32                 Attributes,\r
+  IN UINTN                  VariableSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POINTER_TRACK    Variable;\r
+  VAR_ERROR_FLAG            *VarErrFlag;\r
+  VAR_ERROR_FLAG            TempFlag;\r
+\r
+  DEBUG_CODE (\r
+    DEBUG ((EFI_D_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));\r
+    if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {\r
+      if (AtRuntime ()) {\r
+        DEBUG ((EFI_D_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
+      } else {\r
+        DEBUG ((EFI_D_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
+      }\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));\r
+    }\r
+  );\r
+\r
+  if (!mEndOfDxe) {\r
+    //\r
+    // Before EndOfDxe, just record the current boot variable error flag to local variable,\r
+    // and leave the variable error flag in NV flash as the last boot variable error flag.\r
+    // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash\r
+    // will be initialized to this local current boot variable error flag.\r
+    //\r
+    mCurrentBootVarErrFlag &= Flag;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Record error flag (it should have be initialized).\r
+  //\r
+  Status = FindVariable (\r
+             VAR_ERROR_FLAG_NAME,\r
+             &gEdkiiVarErrorFlagGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr);\r
+    TempFlag = *VarErrFlag;\r
+    TempFlag &= Flag;\r
+    if (TempFlag == *VarErrFlag) {\r
+      return;\r
+    }\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE,\r
+               FALSE,\r
+               mVariableModuleGlobal->FvbInstance,\r
+               (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+               sizeof (TempFlag),\r
+               &TempFlag\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Update the data in NV cache.\r
+      //\r
+      *VarErrFlag = Flag;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize variable error flag.\r
+\r
+  Before EndOfDxe, the variable indicates the last boot variable error flag,\r
+  then it means the last boot variable error flag must be got before EndOfDxe.\r
+  After EndOfDxe, the variable indicates the current boot variable error flag,\r
+  then it means the current boot variable error flag must be got after EndOfDxe.\r
+\r
+**/\r
+VOID\r
+InitializeVarErrorFlag (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POINTER_TRACK    Variable;\r
+  VAR_ERROR_FLAG            Flag;\r
+  VAR_ERROR_FLAG            VarErrFlag;\r
+\r
+  if (!mEndOfDxe) {\r
+    return;\r
+  }\r
+\r
+  Flag = mCurrentBootVarErrFlag;\r
+  DEBUG ((EFI_D_INFO, "Initialize variable error flag (%02x)\n", Flag));\r
+\r
+  Status = FindVariable (\r
+             VAR_ERROR_FLAG_NAME,\r
+             &gEdkiiVarErrorFlagGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr));\r
+    if (VarErrFlag == Flag) {\r
+      return;\r
+    }\r
+  }\r
+\r
+  UpdateVariable (\r
+    VAR_ERROR_FLAG_NAME,\r
+    &gEdkiiVarErrorFlagGuid,\r
+    &Flag,\r
+    sizeof (Flag),\r
+    VARIABLE_ATTRIBUTE_NV_BS_RT,\r
+    0,\r
+    0,\r
+    &Variable,\r
+    NULL\r
+    );\r
+}\r
+\r
+/**\r
+  Is user variable?\r
+\r
+  @param[in] Variable   Pointer to variable header.\r
+\r
+  @retval TRUE          User variable.\r
+  @retval FALSE         System variable.\r
+\r
+**/\r
+BOOLEAN\r
+IsUserVariable (\r
+  IN VARIABLE_HEADER    *Variable\r
+  )\r
+{\r
+  VAR_CHECK_VARIABLE_PROPERTY   Property;\r
+\r
+  //\r
+  // Only after End Of Dxe, the variables belong to system variable are fixed.\r
+  // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
+  // then no need to check if the variable is user variable or not specially.\r
+  //\r
+  if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
+    if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Calculate common user variable total size.\r
+\r
+**/\r
+VOID\r
+CalculateCommonUserVariableTotalSize (\r
+  VOID\r
+  )\r
+{\r
+  VARIABLE_HEADER               *Variable;\r
+  VARIABLE_HEADER               *NextVariable;\r
+  UINTN                         VariableSize;\r
+  VAR_CHECK_VARIABLE_PROPERTY   Property;\r
+\r
+  //\r
+  // Only after End Of Dxe, the variables belong to system variable are fixed.\r
+  // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
+  // then no need to calculate the common user variable total size specially.\r
+  //\r
+  if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
+    Variable = GetStartPointer (mNvVariableCache);\r
+    while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
+      NextVariable = GetNextVariablePtr (Variable);\r
+      VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+      if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+        if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) {\r
+          //\r
+          // No property, it is user variable.\r
+          //\r
+          mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
+        }\r
+      }\r
+\r
+      Variable = NextVariable;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize variable quota.\r
+\r
+**/\r
+VOID\r
+InitializeVariableQuota (\r
+  VOID\r
+  )\r
+{\r
+  STATIC BOOLEAN    Initialized;\r
+\r
+  if (!mEndOfDxe || Initialized) {\r
+    return;\r
+  }\r
+  Initialized = TRUE;\r
+\r
+  InitializeVarErrorFlag ();\r
+  CalculateCommonUserVariableTotalSize ();\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
+  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
+\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
 **/\r
 BOOLEAN\r
 IsValidPubKeyIndex (\r
@@ -546,28 +789,30 @@ IsValidPubKeyIndex (
   )\r
 {\r
   VARIABLE_HEADER          *Variable;\r
+  VARIABLE_HEADER          *VariableStoreEnd;\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
+\r
+  Variable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+  VariableStoreEnd = GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+\r
+  while (IsValidVariableHeader (Variable, VariableStoreEnd)) {\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
+\r
   return FALSE;\r
 }\r
 \r
 /**\r
 \r
   Get the number of valid public key in PubKeyStore.\r
-  \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
@@ -582,13 +827,13 @@ GetValidPubKeyNumber (
   UINT32       Counter;\r
 \r
   Counter = 0;\r
-  \r
+\r
   for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
     if (IsValidPubKeyIndex (PubKeyIndex)) {\r
       Counter++;\r
     }\r
   }\r
-  \r
+\r
   return Counter;\r
 }\r
 \r
@@ -596,7 +841,7 @@ GetValidPubKeyNumber (
 \r
   Filter the useless key in public key store.\r
 \r
-  This function will find out all valid public keys in public key database, save them in new allocated \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
@@ -605,10 +850,10 @@ GetValidPubKeyNumber (
   @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
+\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
 **/\r
 EFI_STATUS\r
 PubKeyStoreFilter (\r
@@ -622,7 +867,7 @@ PubKeyStoreFilter (
   UINT32        PubKeyIndex;\r
   UINT32        CopiedKey;\r
   UINT32        NewPubKeyNumber;\r
-  \r
+\r
   NewPubKeyNumber = GetValidPubKeyNumber (PubKeyNumber);\r
   if (NewPubKeyNumber == PubKeyNumber) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -642,6 +887,7 @@ PubKeyStoreFilter (
   *NewPubKeyIndex = AllocateZeroPool ((PubKeyNumber + 1) * sizeof (UINT32));\r
   if (*NewPubKeyIndex == NULL) {\r
     FreePool (*NewPubKeyStore);\r
+    *NewPubKeyStore = NULL;\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
@@ -672,11 +918,12 @@ PubKeyStoreFilter (
   @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]      NewVariable             Pointer to new variable.\r
+  @param[in]      NewVariableSize         New variable size.\r
   @param[in]      ReclaimPubKeyStore      Reclaim for public key database or not.\r
-  @param[in]      ReclaimAnyway           If TRUE, do reclaim anyway.\r
-  \r
+\r
   @return EFI_SUCCESS                  Reclaim operation has finished successfully.\r
-  @return EFI_OUT_OF_RESOURCES         No enough memory resources.\r
+  @return EFI_OUT_OF_RESOURCES         No enough memory resources or variable space.\r
   @return EFI_DEVICE_ERROR             The public key database doesn't exist.\r
   @return Others                       Unexpect error happened during reclaim operation.\r
 \r
@@ -687,8 +934,9 @@ Reclaim (
   OUT    UINTN                        *LastVariableOffset,\r
   IN     BOOLEAN                      IsVolatile,\r
   IN OUT VARIABLE_POINTER_TRACK       *UpdatingPtrTrack,\r
-  IN     BOOLEAN                      ReclaimPubKeyStore,\r
-  IN     BOOLEAN                      ReclaimAnyway\r
+  IN     VARIABLE_HEADER              *NewVariable,\r
+  IN     UINTN                        NewVariableSize,\r
+  IN     BOOLEAN                      ReclaimPubKeyStore\r
   )\r
 {\r
   VARIABLE_HEADER       *Variable;\r
@@ -699,73 +947,82 @@ Reclaim (
   UINT8                 *ValidBuffer;\r
   UINTN                 MaximumBufferSize;\r
   UINTN                 VariableSize;\r
-  UINTN                 VariableNameSize;\r
-  UINTN                 UpdatingVariableNameSize;\r
   UINTN                 NameSize;\r
   UINT8                 *CurrPtr;\r
   VOID                  *Point0;\r
   VOID                  *Point1;\r
   BOOLEAN               FoundAdded;\r
   EFI_STATUS            Status;\r
-  CHAR16                *VariableNamePtr;\r
-  CHAR16                *UpdatingVariableNamePtr;\r
   UINTN                 CommonVariableTotalSize;\r
+  UINTN                 CommonUserVariableTotalSize;\r
   UINTN                 HwErrVariableTotalSize;\r
   UINT32                *NewPubKeyIndex;\r
   UINT8                 *NewPubKeyStore;\r
   UINT32                NewPubKeySize;\r
   VARIABLE_HEADER       *PubKeyHeader;\r
-  BOOLEAN               NeedDoReclaim;\r
   VARIABLE_HEADER       *UpdatingVariable;\r
+  VARIABLE_HEADER       *UpdatingInDeletedTransition;\r
 \r
   UpdatingVariable = NULL;\r
+  UpdatingInDeletedTransition = NULL;\r
   if (UpdatingPtrTrack != NULL) {\r
     UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
+    UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;\r
   }\r
 \r
-  NeedDoReclaim = FALSE;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
 \r
   CommonVariableTotalSize = 0;\r
+  CommonUserVariableTotalSize = 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
-  Variable          = GetStartPointer (VariableStoreHeader);\r
-  MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
 \r
-  while (IsValidVariableHeader (Variable)) {\r
-    NextVariable = GetNextVariablePtr (Variable);\r
-    if (Variable->State == VAR_ADDED ||\r
-        Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
-       ) {\r
-      VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
-      MaximumBufferSize += VariableSize;\r
-    } else {\r
-      NeedDoReclaim = TRUE;\r
-    }\r
+  if (IsVolatile) {\r
+    //\r
+    // Start Pointers for the variable.\r
+    //\r
+    Variable          = GetStartPointer (VariableStoreHeader);\r
+    MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
 \r
-    Variable = NextVariable;\r
-  }\r
+    while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
+      NextVariable = GetNextVariablePtr (Variable);\r
+      if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&\r
+          Variable != UpdatingVariable &&\r
+          Variable != UpdatingInDeletedTransition\r
+         ) {\r
+        VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+        MaximumBufferSize += VariableSize;\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
+      Variable = NextVariable;\r
+    }\r
 \r
-  //\r
-  // Reserve the 1 Bytes with Oxff to identify the\r
-  // end of the variable buffer.\r
-  //\r
-  MaximumBufferSize += 1;\r
-  ValidBuffer = AllocatePool (MaximumBufferSize);\r
-  if (ValidBuffer == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    if (NewVariable != NULL) {\r
+      //\r
+      // Add the new variable size.\r
+      //\r
+      MaximumBufferSize += NewVariableSize;\r
+    }\r
+\r
+    //\r
+    // Reserve the 1 Bytes with Oxff to identify the\r
+    // end of the variable buffer.\r
+    //\r
+    MaximumBufferSize += 1;\r
+    ValidBuffer = AllocatePool (MaximumBufferSize);\r
+    if (ValidBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    //\r
+    // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache\r
+    // as the buffer to reduce SMRAM consumption for SMM variable driver.\r
+    //\r
+    MaximumBufferSize = mNvVariableCache->Size;\r
+    ValidBuffer = (UINT8 *) mNvVariableCache;\r
   }\r
 \r
   SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
@@ -777,6 +1034,7 @@ Reclaim (
   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
 \r
   if (ReclaimPubKeyStore) {\r
+    ASSERT (IsVolatile == FALSE);\r
     //\r
     // Trim the PubKeyStore and get new PubKeyIndex.\r
     //\r
@@ -788,18 +1046,18 @@ Reclaim (
                &NewPubKeySize\r
                );\r
     if (EFI_ERROR (Status)) {\r
-      FreePool (ValidBuffer);\r
-      return Status;\r
+      goto Done;\r
     }\r
+    ASSERT ((NewPubKeyIndex != NULL) && (NewPubKeyStore != NULL));\r
 \r
     //\r
     // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).\r
     //\r
-    Variable = GetStartPointer (mNvVariableCache);\r
-    while (IsValidVariableHeader (Variable)) {\r
+    Variable = GetStartPointer (VariableStoreHeader);\r
+    while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\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
+        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
@@ -808,15 +1066,18 @@ Reclaim (
           Variable = NextVariable;\r
           continue;\r
         }\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
+        if ((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
+        } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
           CommonVariableTotalSize += VariableSize;\r
+          if (IsUserVariable (Variable)) {\r
+            CommonUserVariableTotalSize += VariableSize;\r
+          }\r
         }\r
       }\r
       Variable = NextVariable;\r
@@ -827,44 +1088,27 @@ Reclaim (
     //\r
     ASSERT (PubKeyHeader != NULL);\r
     if (PubKeyHeader == NULL) {\r
-      FreePool (ValidBuffer);\r
-      FreePool (NewPubKeyIndex);\r
-      FreePool (NewPubKeyStore);\r
-      return EFI_DEVICE_ERROR;\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Done;\r
     }\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
+    CurrPtr = (UINT8*) GetNextVariablePtr (Variable);\r
     CommonVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
+    if (IsUserVariable (Variable)) {\r
+      CommonUserVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
+    }\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
+    while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\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
-\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
+      if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {\r
         VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
         CurrPtr += VariableSize;\r
@@ -872,34 +1116,21 @@ Reclaim (
           HwErrVariableTotalSize += VariableSize;\r
         } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
           CommonVariableTotalSize += VariableSize;\r
+          if (IsUserVariable (Variable)) {\r
+            CommonUserVariableTotalSize += VariableSize;\r
+          }\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
-      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
+    Variable = GetStartPointer (VariableStoreHeader);\r
+    while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
       NextVariable = GetNextVariablePtr (Variable);\r
-      if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+      if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
 \r
         //\r
         // Buffer has cached all ADDED variable.\r
@@ -909,7 +1140,7 @@ Reclaim (
 \r
         FoundAdded = FALSE;\r
         AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
-        while (IsValidVariableHeader (AddedVariable)) {\r
+        while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {\r
           NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
           NameSize = NameSizeOfVariable (AddedVariable);\r
           if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
@@ -936,12 +1167,55 @@ Reclaim (
             HwErrVariableTotalSize += VariableSize;\r
           } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
             CommonVariableTotalSize += VariableSize;\r
+            if (IsUserVariable (Variable)) {\r
+              CommonUserVariableTotalSize += VariableSize;\r
+            }\r
           }\r
         }\r
       }\r
 \r
       Variable = NextVariable;\r
     }\r
+\r
+    //\r
+    // Install the new variable if it is not NULL.\r
+    //\r
+    if (NewVariable != NULL) {\r
+      if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
+        //\r
+        // No enough space to store the new variable.\r
+        //\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      if (!IsVolatile) {\r
+        if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          HwErrVariableTotalSize += NewVariableSize;\r
+        } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          CommonVariableTotalSize += NewVariableSize;\r
+          if (IsUserVariable (NewVariable)) {\r
+            CommonUserVariableTotalSize += NewVariableSize;\r
+          }\r
+        }\r
+        if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||\r
+            (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||\r
+            (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
+          //\r
+          // No enough space to store the new variable by NV or NV+HR attribute.\r
+          //\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);\r
+      ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+      if (UpdatingVariable != NULL) {\r
+        UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));\r
+        UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
+      }\r
+      CurrPtr += NewVariableSize;\r
+    }\r
   }\r
 \r
   if (IsVolatile) {\r
@@ -949,7 +1223,8 @@ Reclaim (
     // If volatile variable store, just copy valid buffer.\r
     //\r
     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
-    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
+    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer));\r
+    *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
     Status  = EFI_SUCCESS;\r
   } else {\r
     //\r
@@ -957,41 +1232,50 @@ Reclaim (
     //\r
     Status = FtwVariableSpace (\r
               VariableBase,\r
-              ValidBuffer,\r
-              (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
+              (VARIABLE_STORE_HEADER *) ValidBuffer\r
               );\r
-    CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
-  }\r
-  if (!EFI_ERROR (Status)) {\r
-    *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
-    if (!IsVolatile) {\r
+    if (!EFI_ERROR (Status)) {\r
+      *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
       mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
-    }\r
-  } else {\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
+      mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
+    } else {\r
+      Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
+      while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
+        NextVariable = GetNextVariablePtr (Variable);\r
+        VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+        if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+        } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+          if (IsUserVariable (Variable)) {\r
+            mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
+          }\r
+        }\r
 \r
-      NextVariable = GetNextVariablePtr (NextVariable);\r
+        Variable = NextVariable;\r
+      }\r
+      *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;\r
     }\r
-    *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
   }\r
 \r
-  if (NewPubKeyStore != NULL) {\r
-    FreePool (NewPubKeyStore);\r
-  }\r
+Done:\r
+  if (IsVolatile) {\r
+    FreePool (ValidBuffer);\r
+  } else {\r
+    //\r
+    // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.\r
+    //\r
+    CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
+\r
+    if (NewPubKeyStore != NULL) {\r
+      FreePool (NewPubKeyStore);\r
+    }\r
 \r
-  if (NewPubKeyIndex != NULL) {\r
-    FreePool (NewPubKeyIndex);\r
+    if (NewPubKeyIndex != NULL) {\r
+      FreePool (NewPubKeyIndex);\r
+    }\r
   }\r
-  \r
-  FreePool (ValidBuffer);\r
 \r
   return Status;\r
 }\r
@@ -1027,7 +1311,7 @@ FindVariableEx (
   InDeletedVariable  = NULL;\r
 \r
   for ( PtrTrack->CurrPtr = PtrTrack->StartPtr\r
-      ; (PtrTrack->CurrPtr < PtrTrack->EndPtr) && IsValidVariableHeader (PtrTrack->CurrPtr)\r
+      ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)\r
       ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)\r
       ) {\r
     if (PtrTrack->CurrPtr->State == VAR_ADDED ||\r
@@ -1435,21 +1719,154 @@ VariableGetBestLanguage (
 }\r
 \r
 /**\r
-  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
-\r
-  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+  This function is to check if the remaining variable space is enough to set\r
+  all Variables from argument list successfully. The purpose of the check\r
+  is to keep the consistency of the Variables to be in variable storage.\r
 \r
-  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
-  and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+  Note: Variables are assumed to be in same storage.\r
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,\r
+  so follow the argument sequence to check the Variables.\r
 \r
-  @param[in] VariableName       Name of variable.\r
+  @param[in] Attributes         Variable attributes for Variable entries.\r
+  @param ...                    The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.\r
+                                A NULL terminates the list. The VariableSize of\r
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.\r
+                                It will be changed to variable total size as output.\r
 \r
-  @param[in] Data               Variable data.\r
+  @retval TRUE                  Have enough variable space to set the Variables successfully.\r
+  @retval FALSE                 No enough variable space to set the Variables successfully.\r
 \r
-  @param[in] DataSize           Size of data. 0 means delete.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckRemainingSpaceForConsistency (\r
+  IN UINT32                     Attributes,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  VA_LIST                       Args;\r
+  VARIABLE_ENTRY_CONSISTENCY    *VariableEntry;\r
+  UINT64                        MaximumVariableStorageSize;\r
+  UINT64                        RemainingVariableStorageSize;\r
+  UINT64                        MaximumVariableSize;\r
+  UINTN                         TotalNeededSize;\r
+  UINTN                         OriginalVarSize;\r
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;\r
+  VARIABLE_POINTER_TRACK        VariablePtrTrack;\r
+  VARIABLE_HEADER               *NextVariable;\r
+  UINTN                         VarNameSize;\r
+  UINTN                         VarDataSize;\r
+\r
+  //\r
+  // Non-Volatile related.\r
+  //\r
+  VariableStoreHeader = mNvVariableCache;\r
+\r
+  Status = VariableServiceQueryVariableInfoInternal (\r
+             Attributes,\r
+             &MaximumVariableStorageSize,\r
+             &RemainingVariableStorageSize,\r
+             &MaximumVariableSize\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  TotalNeededSize = 0;\r
+  VA_START (Args, Attributes);\r
+  VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+  while (VariableEntry != NULL) {\r
+    //\r
+    // Calculate variable total size.\r
+    //\r
+    VarNameSize  = StrSize (VariableEntry->Name);\r
+    VarNameSize += GET_PAD_SIZE (VarNameSize);\r
+    VarDataSize  = VariableEntry->VariableSize;\r
+    VarDataSize += GET_PAD_SIZE (VarDataSize);\r
+    VariableEntry->VariableSize = HEADER_ALIGN (sizeof (VARIABLE_HEADER) + VarNameSize + VarDataSize);\r
+\r
+    TotalNeededSize += VariableEntry->VariableSize;\r
+    VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+  }\r
+  VA_END (Args);\r
+\r
+  if (RemainingVariableStorageSize >= TotalNeededSize) {\r
+    //\r
+    // Already have enough space.\r
+    //\r
+    return TRUE;\r
+  } else if (AtRuntime ()) {\r
+    //\r
+    // At runtime, no reclaim.\r
+    // The original variable space of Variables can't be reused.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  VA_START (Args, Attributes);\r
+  VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+  while (VariableEntry != NULL) {\r
+    //\r
+    // Check if Variable[Index] has been present and get its size.\r
+    //\r
+    OriginalVarSize = 0;\r
+    VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
+    VariablePtrTrack.EndPtr   = GetEndPointer   (VariableStoreHeader);\r
+    Status = FindVariableEx (\r
+               VariableEntry->Name,\r
+               VariableEntry->Guid,\r
+               FALSE,\r
+               &VariablePtrTrack\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Get size of Variable[Index].\r
+      //\r
+      NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);\r
+      OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;\r
+      //\r
+      // Add the original size of Variable[Index] to remaining variable storage size.\r
+      //\r
+      RemainingVariableStorageSize += OriginalVarSize;\r
+    }\r
+    if (VariableEntry->VariableSize > RemainingVariableStorageSize) {\r
+      //\r
+      // No enough space for Variable[Index].\r
+      //\r
+      VA_END (Args);\r
+      return FALSE;\r
+    }\r
+    //\r
+    // Sub the (new) size of Variable[Index] from remaining variable storage size.\r
+    //\r
+    RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
+    VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+  }\r
+  VA_END (Args);\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
+\r
+  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+\r
+  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
+  and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+\r
+  @param[in] Data               Variable data.\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+\r
+  @retval EFI_SUCCESS           The update operation is successful or ignored.\r
+  @retval EFI_WRITE_PROTECTED   Update PlatformLangCodes/LangCodes at runtime.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough variable space to do the update operation.\r
+  @retval Others                Other errors happened during the update operation.\r
 \r
 **/\r
-VOID\r
+EFI_STATUS\r
 AutoUpdateLangVariable (\r
   IN  CHAR16             *VariableName,\r
   IN  VOID               *Data,\r
@@ -1463,22 +1880,23 @@ AutoUpdateLangVariable (
   UINT32                 Attributes;\r
   VARIABLE_POINTER_TRACK Variable;\r
   BOOLEAN                SetLanguageCodes;\r
+  VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];\r
 \r
   //\r
   // Don't do updates for delete operation\r
   //\r
   if (DataSize == 0) {\r
-    return;\r
+    return EFI_SUCCESS;\r
   }\r
 \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
     if (AtRuntime ()) {\r
-      return;\r
+      return EFI_WRITE_PROTECTED;\r
     }\r
 \r
     SetLanguageCodes = TRUE;\r
@@ -1503,12 +1921,12 @@ 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
     if (AtRuntime ()) {\r
-      return;\r
+      return EFI_WRITE_PROTECTED;\r
     }\r
 \r
     SetLanguageCodes = TRUE;\r
@@ -1531,38 +1949,40 @@ 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
         //\r
         // Neither PlatformLang nor Lang is set, directly return\r
         //\r
-        return;\r
+        return EFI_SUCCESS;\r
       }\r
     }\r
   }\r
 \r
+  Status = EFI_SUCCESS;\r
+\r
   //\r
   // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
   //\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
@@ -1583,20 +2003,35 @@ AutoUpdateLangVariable (
         BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
 \r
         //\r
-        // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+        // Check the variable space for both Lang and PlatformLang variable.\r
         //\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, 0, 0, &Variable, NULL);\r
+        VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
+        VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;\r
+\r
+        VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);\r
+        VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
+          //\r
+          // No enough variable space to set both Lang and PlatformLang successfully.\r
+          //\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          //\r
+          // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+          //\r
+          FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
+          Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
+                                   ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);\r
+        }\r
 \r
-        ASSERT_EFI_ERROR(Status);\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));\r
       }\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
@@ -1617,18 +2052,43 @@ AutoUpdateLangVariable (
         BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
 \r
         //\r
-        // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+        // Check the variable space for both PlatformLang and Lang variable.\r
         //\r
-        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);\r
+        VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
+\r
+        VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
+        VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;\r
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
+          //\r
+          // No enough variable space to set both PlatformLang and Lang successfully.\r
+          //\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          //\r
+          // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+          //\r
+          FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang,\r
-                                 AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);\r
+          Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,\r
+                                   AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);\r
+        }\r
 \r
-        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
-        ASSERT_EFI_ERROR (Status);\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));\r
       }\r
     }\r
   }\r
+\r
+  if (SetLanguageCodes) {\r
+    //\r
+    // Continue to set PlatformLangCodes or LangCodes.\r
+    //\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return Status;\r
+  }\r
 }\r
 \r
 /**\r
@@ -1666,7 +2126,6 @@ UpdateVariable (
   VARIABLE_HEADER                     *NextVariable;\r
   UINTN                               ScratchSize;\r
   UINTN                               MaxDataSize;\r
-  UINTN                               NonVolatileVarableStoreSize;\r
   UINTN                               VarNameOffset;\r
   UINTN                               VarDataOffset;\r
   UINTN                               VarNameSize;\r
@@ -1678,8 +2137,12 @@ UpdateVariable (
   VARIABLE_POINTER_TRACK              NvVariable;\r
   VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
   UINTN                               CacheOffset;\r
-  UINTN                               BufSize;\r
+  UINT8                               *BufferForMerge;\r
+  UINTN                               MergedBufSize;\r
+  BOOLEAN                             DataReady;\r
   UINTN                               DataOffset;\r
+  BOOLEAN                             IsCommonVariable;\r
+  BOOLEAN                             IsCommonUserVariable;\r
 \r
   if (mVariableModuleGlobal->FvbInstance == NULL) {\r
     //\r
@@ -1690,7 +2153,7 @@ UpdateVariable (
       // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
       //\r
       return EFI_NOT_AVAILABLE_YET;\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
       //\r
       // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
       // The authenticated variable perhaps is not initialized, just return here.\r
@@ -1727,8 +2190,9 @@ UpdateVariable (
   // as a temporary storage.\r
   //\r
   NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
-  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
-\r
+  ScratchSize = mVariableModuleGlobal->ScratchBufferSize;\r
+  SetMem (NextVariable, ScratchSize, 0xff);\r
+  DataReady = FALSE;\r
 \r
   if (Variable->CurrPtr != NULL) {\r
     //\r
@@ -1751,7 +2215,7 @@ UpdateVariable (
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;\r
       }\r
-      \r
+\r
       //\r
       // Only variable that have RT attributes can be updated/deleted in Runtime.\r
       //\r
@@ -1820,7 +2284,7 @@ UpdateVariable (
     // then return to the caller immediately.\r
     //\r
     if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
-        (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)  &&\r
+        (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&\r
         ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
         (TimeStamp == NULL)) {\r
       //\r
@@ -1837,42 +2301,47 @@ UpdateVariable (
       //\r
       if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {\r
         //\r
-        // Cache the previous variable data into StorageArea.\r
+        // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
+        // From DataOffset of NextVariable is to save the existing variable data.\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
+        BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);\r
+        CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize);\r
 \r
         //\r
-        // Set Max Common Variable Data Size as default MaxDataSize \r
+        // Set Max Common/Auth Variable Data Size as default MaxDataSize\r
         //\r
-        MaxDataSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));\r
-\r
+        if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
+          MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;\r
+        } else {\r
+          MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;\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
+            ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
+             (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r
+             (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
           //\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
           Status = AppendSignatureList (\r
-                     mStorageArea, \r
-                     Variable->CurrPtr->DataSize, \r
+                     BufferForMerge,\r
+                     Variable->CurrPtr->DataSize,\r
                      MaxDataSize - Variable->CurrPtr->DataSize,\r
-                     Data, \r
-                     DataSize, \r
-                     &BufSize\r
+                     Data,\r
+                     DataSize,\r
+                     &MergedBufSize\r
                      );\r
           if (Status == EFI_BUFFER_TOO_SMALL) {\r
             //\r
-            // Signture List is too long, Failed to Append\r
+            // Signature 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 (MergedBufSize == Variable->CurrPtr->DataSize) {\r
             if ((TimeStamp == NULL) || CompareTimeStamp (TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
               //\r
               // New EFI_SIGNATURE_DATA is not found and timestamp is not later\r
@@ -1885,29 +2354,30 @@ UpdateVariable (
           }\r
         } 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
+          // For other Variables, append the new data to the end of existing data.\r
+          // Max Harware error record variable data size is different from common/auth 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
+            MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
           }\r
 \r
           if (Variable->CurrPtr->DataSize + DataSize > MaxDataSize) {\r
             //\r
-            // Exsiting data + Appended data exceed maximum variable size limitation \r
+            // Existing data size + new data size 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
+          CopyMem ((UINT8*) ((UINTN) BufferForMerge + Variable->CurrPtr->DataSize), Data, DataSize);\r
+          MergedBufSize = Variable->CurrPtr->DataSize + DataSize;\r
         }\r
 \r
         //\r
-        // Override Data and DataSize which are used for combined data area including previous and new data.\r
+        // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
         //\r
-        Data     = mStorageArea;\r
-        DataSize = BufSize;\r
+        Data      = BufferForMerge;\r
+        DataSize  = MergedBufSize;\r
+        DataReady = TRUE;\r
       }\r
 \r
       //\r
@@ -1964,9 +2434,7 @@ UpdateVariable (
   //\r
   // Function part - create a new variable and copy the data.\r
   // Both update a variable and create a variable will come here.\r
-\r
-  SetMem (NextVariable, ScratchSize, 0xff);\r
-\r
+  //\r
   NextVariable->StartId     = VARIABLE_DATA;\r
   //\r
   // NextVariable->State = VAR_ADDED;\r
@@ -2008,11 +2476,19 @@ UpdateVariable (
     VarNameSize\r
     );\r
   VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
-  CopyMem (\r
-    (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
-    Data,\r
-    DataSize\r
-    );\r
+\r
+  //\r
+  // If DataReady is TRUE, it means the variable data has been saved into\r
+  // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.\r
+  //\r
+  if (!DataReady) {\r
+    CopyMem (\r
+      (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
+      Data,\r
+      DataSize\r
+      );\r
+  }\r
+\r
   CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
   //\r
   // There will be pad bytes after Data, the NextVariable->NameSize and\r
@@ -2032,43 +2508,59 @@ UpdateVariable (
     // Create a nonvolatile variable.\r
     //\r
     Volatile = FALSE;\r
-    NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
+\r
+    IsCommonVariable = FALSE;\r
+    IsCommonUserVariable = FALSE;\r
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {\r
+      IsCommonVariable = TRUE;\r
+      IsCommonUserVariable = IsUserVariable (NextVariable);\r
+    }\r
     if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)\r
       && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
-      || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)\r
-      && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
+      || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))\r
+      || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))\r
+      || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))) {\r
       if (AtRuntime ()) {\r
+        if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
+          RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
+        }\r
+        if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {\r
+          RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
+        }\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
       //\r
-      // Perform garbage collection & reclaim operation.\r
+      // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
       //\r
       Status = Reclaim (\r
                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
                  Variable,\r
-                 FALSE,\r
+                 NextVariable,\r
+                 HEADER_ALIGN (VarSize),\r
                  FALSE\r
                  );\r
-      if (EFI_ERROR (Status)) {\r
-        goto Done;\r
-      }\r
-      //\r
-      // If still no enough space, return out of resources.\r
-      //\r
-      if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)\r
-        && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
-        || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)\r
-        && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
-        goto Done;\r
-      }\r
-      if (Variable->CurrPtr != NULL) {\r
-        CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
-        CacheVariable->InDeletedTransitionPtr = NULL;\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // The new variable has been integrated successfully during reclaiming.\r
+        //\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
+        UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);\r
+        FlushHobVariableToFlash (VariableName, VendorGuid);\r
+      } else {\r
+        if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
+          RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
+        }\r
+        if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {\r
+          RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
+        }\r
       }\r
+      goto Done;\r
     }\r
     //\r
     // Four steps\r
@@ -2152,6 +2644,9 @@ UpdateVariable (
       mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
     } else {\r
       mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+      if (IsCommonUserVariable) {\r
+        mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);\r
+      }\r
     }\r
     //\r
     // update the memory copy of Flash region.\r
@@ -2166,32 +2661,28 @@ UpdateVariable (
     if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
         ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
       //\r
-      // Perform garbage collection & reclaim operation.\r
+      // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
       //\r
       Status = Reclaim (\r
                  mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
                  &mVariableModuleGlobal->VolatileLastVariableOffset,\r
                  TRUE,\r
                  Variable,\r
-                 FALSE,\r
+                 NextVariable,\r
+                 HEADER_ALIGN (VarSize),\r
                  FALSE\r
                  );\r
-      if (EFI_ERROR (Status)) {\r
-        goto Done;\r
-      }\r
-      //\r
-      // If still no enough space, return out of resources.\r
-      //\r
-      if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
-            ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
-            ) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
-        goto Done;\r
-      }\r
-      if (Variable->CurrPtr != NULL) {\r
-        CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
-        CacheVariable->InDeletedTransitionPtr = NULL;\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // The new variable has been integrated successfully during reclaiming.\r
+        //\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
+        UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);\r
       }\r
+      goto Done;\r
     }\r
 \r
     NextVariable->State = VAR_ADDED;\r
@@ -2273,8 +2764,8 @@ Done:
 /**\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
+  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
@@ -2351,6 +2842,9 @@ VariableLockRequestToLock (
   )\r
 {\r
   VARIABLE_ENTRY                  *Entry;\r
+  CHAR16                          *Name;\r
+  LIST_ENTRY                      *Link;\r
+  VARIABLE_ENTRY                  *LockedEntry;\r
 \r
   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2360,7 +2854,7 @@ VariableLockRequestToLock (
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
-  Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));\r
+  Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (VariableName));\r
   if (Entry == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -2369,43 +2863,28 @@ VariableLockRequestToLock (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
-  Entry->Name = (CHAR16 *) (Entry + 1);\r
-  StrCpy   (Entry->Name, VariableName);\r
+  for ( Link = GetFirstNode (&mLockedVariableList)\r
+      ; !IsNull (&mLockedVariableList, Link)\r
+      ; Link = GetNextNode (&mLockedVariableList, Link)\r
+      ) {\r
+    LockedEntry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
+    Name = (CHAR16 *) ((UINTN) LockedEntry + sizeof (*LockedEntry));\r
+    if (CompareGuid (&LockedEntry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
+  StrnCpy   (Name, VariableName, StrLen (VariableName));\r
   CopyGuid (&Entry->Guid, VendorGuid);\r
   InsertTailList (&mLockedVariableList, &Entry->Link);\r
 \r
+Done:\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
-  @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
@@ -2551,10 +3030,7 @@ VariableServiceGetNextVariableName (
     //\r
     // Switch from Volatile to HOB, to Non-Volatile.\r
     //\r
-    while ((Variable.CurrPtr >= Variable.EndPtr) ||\r
-           (Variable.CurrPtr == NULL)            ||\r
-           !IsValidVariableHeader (Variable.CurrPtr)\r
-          ) {\r
+    while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {\r
       //\r
       // Find current storage index\r
       //\r
@@ -2697,6 +3173,7 @@ VariableServiceSetVariable (
   UINTN                               PayloadSize;\r
   LIST_ENTRY                          *Link;\r
   VARIABLE_ENTRY                      *Entry;\r
+  CHAR16                              *Name;\r
 \r
   //\r
   // Check input parameters.\r
@@ -2705,10 +3182,6 @@ VariableServiceSetVariable (
     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
@@ -2760,15 +3233,15 @@ VariableServiceSetVariable (
 \r
   if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){\r
     //\r
-    // Prevent whole variable size overflow \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
+  //  bytes for HwErrRec.\r
   //\r
   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
     if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
@@ -2780,10 +3253,16 @@ VariableServiceSetVariable (
   } else {\r
     //\r
     //  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
+    //  the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.\r
     //\r
-    if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
-      return EFI_INVALID_PARAMETER;\r
+    if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
+      if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - sizeof (VARIABLE_HEADER)) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } else {\r
+      if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - sizeof (VARIABLE_HEADER)) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
     }\r
   }\r
 \r
@@ -2798,8 +3277,7 @@ VariableServiceSetVariable (
     // Parse non-volatile variable data and get last variable offset.\r
     //\r
     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
-    while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))\r
-        && IsValidVariableHeader (NextVariable)) {\r
+    while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) {\r
       NextVariable = GetNextVariablePtr (NextVariable);\r
     }\r
     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
@@ -2814,7 +3292,8 @@ VariableServiceSetVariable (
         ; 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
+      Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
+      if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (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
@@ -2822,6 +3301,11 @@ VariableServiceSetVariable (
     }\r
   }\r
 \r
+  Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Check whether the input variable is already existed.\r
   //\r
@@ -2831,12 +3315,32 @@ VariableServiceSetVariable (
       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
+      DEBUG ((EFI_D_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));\r
+      goto Done;\r
+    }\r
   }\r
-  \r
-  //\r
-  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
-  //\r
-  AutoUpdateLangVariable (VariableName, Data, DataSize);\r
+\r
+  if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {\r
+    //\r
+    // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
+    //\r
+    Status = AutoUpdateLangVariable (VariableName, Data, DataSize);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.\r
+      //\r
+      goto Done;\r
+    }\r
+  }\r
+\r
   //\r
   // Process PK, KEK, Sigdb seperately.\r
   //\r
@@ -2844,8 +3348,12 @@ VariableServiceSetVariable (
     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);\r
   } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 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
+  } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
+             ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE)  == 0) ||\r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)\r
+             )\r
+            ) {\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
@@ -2858,6 +3366,15 @@ Done:
   InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
+  if (!AtRuntime ()) {\r
+    if (!EFI_ERROR (Status)) {\r
+      SecureBootHook (\r
+        VariableName,\r
+        VendorGuid\r
+        );\r
+    }\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -2877,14 +3394,12 @@ Done:
   @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
                                         associated with the attributes specified.\r
 \r
-  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.\r
   @return EFI_SUCCESS                   Query successfully.\r
-  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-VariableServiceQueryVariableInfo (\r
+VariableServiceQueryVariableInfoInternal (\r
   IN  UINT32                 Attributes,\r
   OUT UINT64                 *MaximumVariableStorageSize,\r
   OUT UINT64                 *RemainingVariableStorageSize,\r
@@ -2897,38 +3412,12 @@ VariableServiceQueryVariableInfo (
   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
   UINT64                 CommonVariableTotalSize;\r
   UINT64                 HwErrVariableTotalSize;\r
+  EFI_STATUS             Status;\r
+  VARIABLE_POINTER_TRACK VariablePtrTrack;\r
 \r
   CommonVariableTotalSize = 0;\r
   HwErrVariableTotalSize = 0;\r
 \r
-  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
-    //\r
-    // Make sure the Attributes combination is supported by the platform.\r
-    //\r
-    return EFI_UNSUPPORTED;\r
-  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
-    //\r
-    // Make sure if runtime bit is set, boot service bit is set also.\r
-    //\r
-    return EFI_INVALID_PARAMETER;\r
-  } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
-    //\r
-    // Make sure RT Attribute is set if we are in Runtime phase.\r
-    //\r
-    return EFI_INVALID_PARAMETER;\r
-  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-    //\r
-    // Make sure Hw Attribute is set with NV.\r
-    //\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
     //\r
     // Query is Volatile related.\r
@@ -2955,14 +3444,21 @@ VariableServiceQueryVariableInfo (
     *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
   } else {\r
     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
-      ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
-      *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
+      if (AtRuntime ()) {\r
+        *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;\r
+      } else {\r
+        *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;\r
+      }\r
     }\r
 \r
     //\r
-    // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
+    // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.\r
     //\r
-    *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
+    if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
+      *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - sizeof (VARIABLE_HEADER);\r
+    } else {\r
+      *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - sizeof (VARIABLE_HEADER);\r
+    }\r
   }\r
 \r
   //\r
@@ -2973,7 +3469,7 @@ VariableServiceQueryVariableInfo (
   //\r
   // Now walk through the related variable store.\r
   //\r
-  while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
+  while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
     NextVariable = GetNextVariablePtr (Variable);\r
     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
 \r
@@ -3000,6 +3496,27 @@ VariableServiceQueryVariableInfo (
         } else {\r
           CommonVariableTotalSize += VariableSize;\r
         }\r
+      } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+        //\r
+        // If it is a IN_DELETED_TRANSITION variable,\r
+        // and there is not also a same ADDED one at the same time,\r
+        // this IN_DELETED_TRANSITION variable is valid.\r
+        //\r
+        VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
+        VariablePtrTrack.EndPtr   = GetEndPointer   (VariableStoreHeader);\r
+        Status = FindVariableEx (\r
+                   GetVariableNamePtr (Variable),\r
+                   &Variable->VendorGuid,\r
+                   FALSE,\r
+                   &VariablePtrTrack\r
+                   );\r
+        if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {\r
+          if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+            HwErrVariableTotalSize += VariableSize;\r
+          } else {\r
+            CommonVariableTotalSize += VariableSize;\r
+          }\r
+        }\r
       }\r
     }\r
 \r
@@ -3011,8 +3528,12 @@ VariableServiceQueryVariableInfo (
 \r
   if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
     *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
-  }else {\r
-    *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+  } else {\r
+    if (*MaximumVariableStorageSize < CommonVariableTotalSize) {\r
+      *RemainingVariableStorageSize = 0;\r
+    } else {\r
+      *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+    }\r
   }\r
 \r
   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
@@ -3021,10 +3542,79 @@ VariableServiceQueryVariableInfo (
     *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
   }\r
 \r
-  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+\r
+  This code returns information about the EFI variables.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
+\r
+  @param Attributes                     Attributes bitmask to specify the type of variables\r
+                                        on which to return information.\r
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available\r
+                                        for the EFI variables associated with the attributes specified.\r
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available\r
+                                        for EFI variables associated with the attributes specified.\r
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
+                                        associated with the attributes specified.\r
+\r
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.\r
+  @return EFI_SUCCESS                   Query successfully.\r
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Attributes & VARIABLE_ATTRIBUTE_NV_BS_RT_AT_HR_AW) == 0) {\r
+    //\r
+    // Make sure the Attributes combination is supported by the platform.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    //\r
+    // Make sure if runtime bit is set, boot service bit is set also.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
+    //\r
+    // Make sure RT Attribute is set if we are in Runtime phase.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    //\r
+    // Make sure Hw Attribute is set with NV.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  Status = VariableServiceQueryVariableInfoInternal (\r
+             Attributes,\r
+             MaximumVariableStorageSize,\r
+             RemainingVariableStorageSize,\r
+             MaximumVariableSize\r
+             );\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  return Status;\r
+}\r
 \r
 /**\r
   This function reclaims variable storage if free size is below the threshold.\r
@@ -3039,35 +3629,208 @@ ReclaimForOS(
   )\r
 {\r
   EFI_STATUS                     Status;\r
-  UINTN                          CommonVariableSpace;\r
-  UINTN                          RemainingCommonVariableSpace;\r
+  UINTN                          RemainingCommonRuntimeVariableSpace;\r
   UINTN                          RemainingHwErrVariableSpace;\r
+  STATIC BOOLEAN                 Reclaimed;\r
 \r
-  Status  = EFI_SUCCESS;\r
+  //\r
+  // This function will be called only once at EndOfDxe or ReadyToBoot event.\r
+  //\r
+  if (Reclaimed) {\r
+    return;\r
+  }\r
+  Reclaimed = TRUE;\r
 \r
-  CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
+  Status  = EFI_SUCCESS;\r
 \r
-  RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
+  if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {\r
+    RemainingCommonRuntimeVariableSpace = 0;\r
+  } else {\r
+    RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
+  }\r
 \r
   RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
+\r
   //\r
-  // Check if the free area is blow a threshold.\r
+  // Check if the free area is below a threshold.\r
   //\r
-  if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
-    || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
+  if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||\r
+       (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||\r
+      ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
        (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
     Status = Reclaim (\r
             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
             &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
             FALSE,\r
             NULL,\r
-            FALSE,\r
+            NULL,\r
+            0,\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                       *Variable;\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
+  UINT32                                HwErrStorageSize;\r
+  UINT32                                MaxUserNvVariableSpaceSize;\r
+  UINT32                                BoottimeReservedNvVariableSpaceSize;\r
+\r
+  mVariableModuleGlobal->FvbInstance = NULL;\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
+  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+\r
+  HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
+  MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
+  BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\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 the value of\r
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
+  //\r
+  ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
+  //\r
+  // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
+  //\r
+  ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
+  //\r
+  // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
+  //\r
+  ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
+\r
+  mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
+  mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r
+  mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r
+\r
+  DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace));\r
+\r
+  //\r
+  // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
+  //\r
+  ASSERT (MAX_NV_VARIABLE_SIZE < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
+\r
+  mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r
+  mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r
+\r
+  //\r
+  // Parse non-volatile variable data and get last variable offset.\r
+  //\r
+  Variable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+  while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase))) {\r
+    NextVariable = GetNextVariablePtr (Variable);\r
+    VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+    if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+    }\r
+\r
+    Variable = NextVariable;\r
+  }\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Flush the HOB variable to flash.\r
 \r
@@ -3099,7 +3862,7 @@ FlushHobVariableToFlash (
     //\r
     mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
     for ( Variable = GetStartPointer (VariableStoreHeader)\r
-        ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
+        ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))\r
         ; Variable = GetNextVariablePtr (Variable)\r
         ) {\r
       if (Variable->State != VAR_ADDED) {\r
@@ -3159,7 +3922,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
@@ -3175,8 +3938,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
@@ -3193,8 +3966,9 @@ VariableWriteServiceInitialize (
                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
                  FALSE,\r
                  NULL,\r
-                 FALSE,\r
-                 TRUE\r
+                 NULL,\r
+                 0,\r
+                 FALSE\r
                  );\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
@@ -3208,7 +3982,7 @@ VariableWriteServiceInitialize (
   //\r
   // Authenticated variable initialize.\r
   //\r
-  Status = AutenticatedVariableServiceInitialize ();\r
+  Status = AutenticatedVariableServiceInitialize (mVariableModuleGlobal->MaxAuthVariableSize - sizeof (VARIABLE_HEADER));\r
 \r
   return Status;\r
 }\r
@@ -3229,12 +4003,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
@@ -3247,14 +4017,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
@@ -3265,6 +4027,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
@@ -3275,9 +4038,13 @@ VariableCommonInitialize (
   //\r
   // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
   //\r
-  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  ScratchSize = MAX_NV_VARIABLE_SIZE;\r
+  mVariableModuleGlobal->ScratchBufferSize = ScratchSize;\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
@@ -3289,7 +4056,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
@@ -3299,74 +4065,13 @@ VariableCommonInitialize (
   VolatileVariableStore->Reserved1   = 0;\r
 \r
   //\r
-  // Get non-volatile variable store.\r
+  // Init 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
-  // 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
-\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
-  //\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
@@ -3396,9 +4101,11 @@ GetFvbInfoByAddress (
   UINTN                                   Index;\r
   EFI_PHYSICAL_ADDRESS                    FvbBaseAddress;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *Fvb;\r
-  EFI_FIRMWARE_VOLUME_HEADER              *FwVolHeader;\r
   EFI_FVB_ATTRIBUTES_2                    Attributes;\r
+  UINTN                                   BlockSize;\r
+  UINTN                                   NumberOfBlocks;\r
 \r
+  HandleBuffer = NULL;\r
   //\r
   // Get all FVB handles.\r
   //\r
@@ -3434,8 +4141,15 @@ GetFvbInfoByAddress (
       continue;\r
     }\r
 \r
-    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
-    if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+    //\r
+    // Assume one FVB has one type of BlockSize.\r
+    //\r
+    Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {\r
       if (FvbHandle != NULL) {\r
         *FvbHandle  = HandleBuffer[Index];\r
       }\r
@@ -3454,4 +4168,3 @@ GetFvbInfoByAddress (
 \r
   return Status;\r
 }\r
-\r