]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg Variable: Introduce PcdReclaimVariableSpaceAtEndOfDxe
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index c66eb875068031d95513764ac7fbcaef3742b11b..b3c36992e36a181af3c831d60dcea6f4907c8dee 100644 (file)
@@ -3,7 +3,18 @@
   The common variable operation routines shared by DXE_RUNTIME variable \r
   module and DXE_SMM variable module.\r
   \r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Caution: This module requires additional review when modified.\r
+  This driver will have external input - variable data. They may be input in SMM mode.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.\r
+  They need check input parameter.\r
+\r
+  VariableServiceGetVariable() and VariableServiceSetVariable() are external API\r
+  to receive datasize and data buffer. The size should be checked carefully.\r
+\r
+Copyright (c) 2006 - 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
@@ -45,50 +56,9 @@ BOOLEAN                mEndOfDxe              = FALSE;
 BOOLEAN                mEnableLocking         = TRUE;\r
 \r
 //\r
-// To prevent name collisions with possible future globally defined variables,\r
-// other internal firmware data variables that are not defined here must be\r
-// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or\r
-// any other GUID defined by the UEFI Specification. Implementations must\r
-// only permit the creation of variables with a UEFI Specification-defined\r
-// VendorGuid when these variables are documented in the UEFI Specification.\r
+// It will record the current boot error flag before EndOfDxe.\r
 //\r
-GLOBAL_VARIABLE_ENTRY mGlobalVariableList[] = {\r
-  {EFI_LANG_CODES_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_LANG_VARIABLE_NAME,                   VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_TIME_OUT_VARIABLE_NAME,               VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,    VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_PLATFORM_LANG_VARIABLE_NAME,          VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_CON_IN_VARIABLE_NAME,                 VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_CON_OUT_VARIABLE_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_ERR_OUT_VARIABLE_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_CON_IN_DEV_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_CON_OUT_DEV_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_ERR_OUT_DEV_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_BOOT_ORDER_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_BOOT_NEXT_VARIABLE_NAME,              VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_BOOT_CURRENT_VARIABLE_NAME,           VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,    VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_DRIVER_ORDER_VARIABLE_NAME,           VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,     VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_SETUP_MODE_NAME,                      VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_KEY_EXCHANGE_KEY_NAME,                VARIABLE_ATTRIBUTE_NV_BS_RT_AT},\r
-  {EFI_PLATFORM_KEY_NAME,                    VARIABLE_ATTRIBUTE_NV_BS_RT_AT},\r
-  {EFI_SIGNATURE_SUPPORT_NAME,               VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_SECURE_BOOT_MODE_NAME,                VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_KEK_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_PK_DEFAULT_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_DB_DEFAULT_VARIABLE_NAME,             VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_DBX_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_DBT_DEFAULT_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, VARIABLE_ATTRIBUTE_BS_RT},\r
-  {EFI_OS_INDICATIONS_VARIABLE_NAME,         VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {EFI_VENDOR_KEYS_VARIABLE_NAME,            VARIABLE_ATTRIBUTE_BS_RT},\r
-};\r
-GLOBAL_VARIABLE_ENTRY mGlobalVariableList2[] = {\r
-  {L"Boot####",                              VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {L"Driver####",                            VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-  {L"Key####",                               VARIABLE_ATTRIBUTE_NV_BS_RT},\r
-};\r
+VAR_ERROR_FLAG         mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;\r
 \r
 /**\r
   Routine used to track statistical information about variable usage. \r
@@ -139,9 +109,9 @@ UpdateVariableInfo (
       ASSERT (gVariableInfo != NULL);\r
 \r
       CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
-      gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
+      gVariableInfo->Name = AllocateZeroPool (StrSize (VariableName));\r
       ASSERT (gVariableInfo->Name != NULL);\r
-      StrCpy (gVariableInfo->Name, VariableName);\r
+      StrnCpy (gVariableInfo->Name, VariableName, StrLen (VariableName));\r
       gVariableInfo->Volatile = Volatile;\r
     }\r
 \r
@@ -175,9 +145,9 @@ UpdateVariableInfo (
         ASSERT (Entry->Next != NULL);\r
 \r
         CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
-        Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
+        Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));\r
         ASSERT (Entry->Next->Name != NULL);\r
-        StrCpy (Entry->Next->Name, VariableName);\r
+        StrnCpy (Entry->Next->Name, VariableName, StrLen (VariableName));\r
         Entry->Next->Volatile = Volatile;\r
       }\r
 \r
@@ -190,18 +160,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
@@ -499,10 +475,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
@@ -556,6 +528,225 @@ 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
+    &Variable\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
@@ -599,6 +790,7 @@ Reclaim (
   BOOLEAN               FoundAdded;\r
   EFI_STATUS            Status;\r
   UINTN                 CommonVariableTotalSize;\r
+  UINTN                 CommonUserVariableTotalSize;\r
   UINTN                 HwErrVariableTotalSize;\r
   VARIABLE_HEADER       *UpdatingVariable;\r
   VARIABLE_HEADER       *UpdatingInDeletedTransition;\r
@@ -613,6 +805,7 @@ Reclaim (
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
 \r
   CommonVariableTotalSize = 0;\r
+  CommonUserVariableTotalSize = 0;\r
   HwErrVariableTotalSize  = 0;\r
 \r
   if (IsVolatile) {\r
@@ -622,7 +815,7 @@ Reclaim (
     Variable          = GetStartPointer (VariableStoreHeader);\r
     MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
 \r
-    while (IsValidVariableHeader (Variable)) {\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
@@ -672,7 +865,7 @@ Reclaim (
   // 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 != UpdatingVariable && Variable->State == VAR_ADDED) {\r
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
@@ -682,6 +875,9 @@ 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
@@ -691,7 +887,7 @@ Reclaim (
   // Reinstall all in delete transition variables.\r
   // \r
   Variable = GetStartPointer (VariableStoreHeader);\r
-  while (IsValidVariableHeader (Variable)) {\r
+  while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
     NextVariable = GetNextVariablePtr (Variable);\r
     if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
 \r
@@ -703,7 +899,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
@@ -730,6 +926,9 @@ 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
@@ -753,9 +952,13 @@ Reclaim (
         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 > VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - 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
@@ -793,19 +996,24 @@ Reclaim (
       *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
       mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+      mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
     } else {\r
-      NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
-      while (IsValidVariableHeader (NextVariable)) {\r
-        VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\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 += HEADER_ALIGN (VariableSize);\r
+          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
         } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-          mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\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) NextVariable - (UINTN) VariableBase;\r
+      *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;\r
     }\r
   }\r
 \r
@@ -853,7 +1061,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
@@ -1258,6 +1466,134 @@ VariableGetBestLanguage (
   return NULL;\r
 }\r
 \r
+/**\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
+  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] 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
+  @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
+**/\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
@@ -1272,8 +1608,13 @@ VariableGetBestLanguage (
 \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
@@ -1287,12 +1628,13 @@ 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
@@ -1302,7 +1644,7 @@ AutoUpdateLangVariable (
     // 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
@@ -1332,7 +1674,7 @@ AutoUpdateLangVariable (
     // 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
@@ -1376,11 +1718,13 @@ AutoUpdateLangVariable (
         //\r
         // Neither PlatformLang nor Lang is set, directly return\r
         //\r
-        return;\r
+        return EFI_SUCCESS;\r
       }\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
@@ -1407,16 +1751,31 @@ 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 (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
-\r
-        Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
-                                 ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\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, &Variable);\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
@@ -1441,18 +1800,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 (EFI_PLATFORM_LANG_VARIABLE_NAME, &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 (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, \r
-                                 AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
+          Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, \r
+                                   AsciiStrSize (BestPlatformLang), Attributes, &Variable);\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
@@ -1483,7 +1867,6 @@ UpdateVariable (
   EFI_STATUS                          Status;\r
   VARIABLE_HEADER                     *NextVariable;\r
   UINTN                               ScratchSize;\r
-  UINTN                               NonVolatileVarableStoreSize;\r
   UINTN                               VarNameOffset;\r
   UINTN                               VarDataOffset;\r
   UINTN                               VarNameSize;\r
@@ -1495,6 +1878,8 @@ UpdateVariable (
   VARIABLE_POINTER_TRACK              NvVariable;\r
   VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
   UINTN                               CacheOffset;\r
+  BOOLEAN                             IsCommonVariable;\r
+  BOOLEAN                             IsCommonUserVariable;\r
 \r
   if ((mVariableModuleGlobal->FvbInstance == NULL) && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {\r
     //\r
@@ -1712,12 +2097,25 @@ UpdateVariable (
     // Create a nonvolatile variable.\r
     //\r
     Volatile = FALSE;\r
-    NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
-    if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \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
@@ -1736,6 +2134,13 @@ UpdateVariable (
         }\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
@@ -1821,6 +2226,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
@@ -1985,63 +2393,6 @@ IsHwErrRecVariable (
   return TRUE;\r
 }\r
 \r
-/**\r
-  This code checks if variable guid is global variable guid first.\r
-  If yes, further check if variable name is in mGlobalVariableList or mGlobalVariableList2 and attributes matched.\r
-\r
-  @param[in] VariableName       Pointer to variable name.\r
-  @param[in] VendorGuid         Variable Vendor Guid.\r
-  @param[in] Attributes         Attributes of the variable.\r
-\r
-  @retval EFI_SUCCESS           Variable is not global variable, or Variable is global variable, variable name is in the lists and attributes matched.\r
-  @retval EFI_INVALID_PARAMETER Variable is global variable, but variable name is not in the lists or attributes unmatched.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CheckEfiGlobalVariable (\r
-  IN CHAR16             *VariableName,\r
-  IN EFI_GUID           *VendorGuid,\r
-  IN UINT32             Attributes\r
-  )\r
-{\r
-  UINTN     Index;\r
-  UINTN     NameLength;\r
-\r
-  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)){\r
-    //\r
-    // Try list 1, exactly match.\r
-    //\r
-    for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {\r
-      if ((StrCmp (mGlobalVariableList[Index].Name, VariableName) == 0) &&\r
-          (Attributes == 0 || Attributes == mGlobalVariableList[Index].Attributes)) {\r
-        return EFI_SUCCESS;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Try list 2.\r
-    //\r
-    NameLength = StrLen (VariableName) - 4;\r
-    for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {\r
-      if ((StrLen (VariableName) == StrLen (mGlobalVariableList2[Index].Name)) &&\r
-          (StrnCmp (mGlobalVariableList2[Index].Name, VariableName, NameLength) == 0) &&\r
-          IsHexaDecimalDigitCharacter (VariableName[NameLength]) &&\r
-          IsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&\r
-          IsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&\r
-          IsHexaDecimalDigitCharacter (VariableName[NameLength + 3]) &&\r
-          (Attributes == 0 || Attributes == mGlobalVariableList2[Index].Attributes)) {\r
-        return EFI_SUCCESS;\r
-      }\r
-    }\r
-\r
-    DEBUG ((EFI_D_INFO, "[Variable]: set global variable with invalid variable name or attributes - %g:%s:%x\n", VendorGuid, VariableName, Attributes));\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
 /**\r
   Mark a variable that will become read-only after leaving the DXE phase of execution.\r
 \r
@@ -2066,6 +2417,7 @@ VariableLockRequestToLock (
   )\r
 {\r
   VARIABLE_ENTRY                  *Entry;\r
+  CHAR16                          *Name;\r
 \r
   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2075,7 +2427,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
@@ -2084,8 +2436,8 @@ VariableLockRequestToLock (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
-  Entry->Name = (CHAR16 *) (Entry + 1);\r
-  StrCpy   (Entry->Name, VariableName);\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
@@ -2098,6 +2450,10 @@ VariableLockRequestToLock (
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize is external input.\r
+  This function will do basic validation, before parse the data.\r
+\r
   @param VariableName               Name of Variable to be found.\r
   @param VendorGuid                 Variable vendor GUID.\r
   @param Attributes                 Attribute value of the variable found.\r
@@ -2175,6 +2531,9 @@ Done:
 \r
   This code Finds the Next available variable.\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 VariableNameSize           Size of the variable name.\r
   @param VariableName               Pointer to variable name.\r
   @param VendorGuid                 Variable Vendor Guid.\r
@@ -2232,10 +2591,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
@@ -2340,6 +2696,10 @@ Done:
 \r
   This code sets variable in storage blocks (Volatile or Non-Volatile).\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+\r
   @param VariableName                     Name of Variable to be found.\r
   @param VendorGuid                       Variable vendor GUID.\r
   @param Attributes                       Attribute value of the variable found\r
@@ -2370,6 +2730,7 @@ VariableServiceSetVariable (
   EFI_PHYSICAL_ADDRESS                Point;\r
   LIST_ENTRY                          *Link;\r
   VARIABLE_ENTRY                      *Entry;\r
+  CHAR16                              *Name;\r
 \r
   //\r
   // Check input parameters.\r
@@ -2422,12 +2783,7 @@ VariableServiceSetVariable (
     //\r
     if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
       return EFI_INVALID_PARAMETER;\r
-    }  \r
-  }\r
-\r
-  Status = CheckEfiGlobalVariable (VariableName, VendorGuid, Attributes);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    }\r
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
@@ -2441,8 +2797,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
@@ -2457,7 +2812,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
@@ -2465,6 +2821,11 @@ VariableServiceSetVariable (
     }\r
   }\r
 \r
+  Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Check whether the input variable is already existed.\r
   //\r
@@ -2482,14 +2843,23 @@ VariableServiceSetVariable (
       // 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
+  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
   Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
 \r
@@ -2504,6 +2874,9 @@ Done:
 \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
@@ -2513,14 +2886,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
@@ -2533,43 +2904,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
-  } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-    //\r
-    // Not support authentiated variable write yet.\r
-    //\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
     //\r
     // Query is Volatile related.\r
@@ -2596,8 +2936,11 @@ 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
@@ -2614,7 +2957,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
@@ -2641,6 +2984,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
@@ -2652,8 +3016,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
@@ -2662,14 +3030,91 @@ 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 & (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
+  } else if ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) {\r
+    //\r
+    // Not support authenticated or append variable write yet.\r
+    //\r
+    return EFI_UNSUPPORTED;\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
-  \r
+\r
+  Caution: This function may be invoked at SMM mode.\r
+  Care must be taken to make sure not security issue.\r
+\r
 **/\r
 VOID\r
 ReclaimForOS(\r
@@ -2677,22 +3122,32 @@ 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
-  // 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 < PcdGet32 (PcdMaxVariableSize))\r
+    || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
        (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
     Status = Reclaim (\r
             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
@@ -2720,6 +3175,7 @@ InitNonVolatileVariableStore (
   )\r
 {\r
   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
+  VARIABLE_HEADER                       *Variable;\r
   VARIABLE_HEADER                       *NextVariable;\r
   EFI_PHYSICAL_ADDRESS                  VariableStoreBase;\r
   UINT64                                VariableStoreLength;\r
@@ -2731,17 +3187,12 @@ InitNonVolatileVariableStore (
   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
-  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
-  // is stored with common variable in the same NV region. So the platform integrator should\r
-  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
-  // PcdFlashNvStorageVariableSize.\r
-  //\r
-  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
-\r
   //\r
   // Allocate runtime memory used for a memory copy of the FLASH region.\r
   // Keep the memory and the FLASH in sync as updates occur.\r
@@ -2811,6 +3262,37 @@ InitNonVolatileVariableStore (
   }\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 variable or hardware error variable size should be < variable store size.\r
   //\r
@@ -2819,18 +3301,19 @@ InitNonVolatileVariableStore (
   //\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
+  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 += HEADER_ALIGN (VariableSize);\r
+      mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
     }\r
 \r
-    NextVariable = GetNextVariablePtr (NextVariable);\r
+    Variable = NextVariable;\r
   }\r
-  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase;\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -2866,7 +3349,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
@@ -3098,9 +3581,12 @@ 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
\r
+  UINTN                                   BlockSize;\r
+  UINTN                                   NumberOfBlocks;\r
+\r
+  HandleBuffer = NULL;\r
+\r
   //\r
   // Get all FVB handles.\r
   //\r
@@ -3125,9 +3611,9 @@ GetFvbInfoByAddress (
     //\r
     Status = Fvb->GetAttributes (Fvb, &Attributes);\r
     if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
-      continue;     \r
+      continue;\r
     }\r
-    \r
+\r
     //\r
     // Compare the address and select the right one.\r
     //\r
@@ -3136,8 +3622,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