]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Avoid running unnecessary code
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index 2679725a179340df49b9e9c2b7f62e8725ad33aa..9d1927262a4edee650bd18621fac69cba7f73738 100644 (file)
@@ -30,6 +30,7 @@
 #define OR_SEED      0x0101010101010101ull\r
 #define CLEAR_SEED   0xFFFFFFFFFFFFFFFFull\r
 \r
+#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
 //\r
 // Context to save and restore when MTRRs are programmed\r
 //\r
@@ -38,62 +39,68 @@ typedef struct {
   BOOLEAN  InterruptState;\r
 } MTRR_CONTEXT;\r
 \r
+typedef struct {\r
+  UINT64                 BaseAddress;\r
+  UINT64                 Length;\r
+  MTRR_MEMORY_CACHE_TYPE Type;\r
+} MEMORY_RANGE;\r
+\r
 //\r
 // This table defines the offset, base and length of the fixed MTRRs\r
 //\r
 CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
+    MSR_IA32_MTRR_FIX64K_00000,\r
     0,\r
     SIZE_64KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
+    MSR_IA32_MTRR_FIX16K_80000,\r
     0x80000,\r
     SIZE_16KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
+    MSR_IA32_MTRR_FIX16K_A0000,\r
     0xA0000,\r
     SIZE_16KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
+    MSR_IA32_MTRR_FIX4K_C0000,\r
     0xC0000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
+    MSR_IA32_MTRR_FIX4K_C8000,\r
     0xC8000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
+    MSR_IA32_MTRR_FIX4K_D0000,\r
     0xD0000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
+    MSR_IA32_MTRR_FIX4K_D8000,\r
     0xD8000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
+    MSR_IA32_MTRR_FIX4K_E0000,\r
     0xE0000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
+    MSR_IA32_MTRR_FIX4K_E8000,\r
     0xE8000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
+    MSR_IA32_MTRR_FIX4K_F0000,\r
     0xF0000,\r
     SIZE_4KB\r
   },\r
   {\r
-    MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
+    MSR_IA32_MTRR_FIX4K_F8000,\r
     0xF8000,\r
     SIZE_4KB\r
   }\r
@@ -207,11 +214,15 @@ MtrrGetDefaultMemoryTypeWorker (
   IN MTRR_SETTINGS      *MtrrSetting\r
   )\r
 {\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
+\r
   if (MtrrSetting == NULL) {\r
-    return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
+    DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
   } else {\r
-    return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
+    DefType.Uint64 = MtrrSetting->MtrrDefType;\r
   }\r
+\r
+  return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
 }\r
 \r
 \r
@@ -247,6 +258,7 @@ MtrrLibPreMtrrChange (
   OUT MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;\r
   //\r
   // Disable interrupts and save current interrupt state\r
   //\r
@@ -271,7 +283,9 @@ MtrrLibPreMtrrChange (
   //\r
   // Disable MTRRs\r
   //\r
-  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
+  DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
+  DefType.Bits.E = 0;\r
+  AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
 }\r
 \r
 /**\r
@@ -323,10 +337,14 @@ MtrrLibPostMtrrChange (
   IN MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;\r
   //\r
   // Enable Cache MTRR\r
   //\r
-  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
+  DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
+  DefType.Bits.E = 1;\r
+  DefType.Bits.FE = 1;\r
+  AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
 \r
   MtrrLibPostMtrrChangeEnableCache (MtrrContext);\r
 }\r
@@ -405,9 +423,9 @@ MtrrGetVariableMtrrWorker (
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     if (MtrrSetting == NULL) {\r
       VariableSettings->Mtrr[Index].Base =\r
-        AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
+        AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
       VariableSettings->Mtrr[Index].Mask =\r
-        AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
+        AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
     } else {\r
       VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
       VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
@@ -561,20 +579,19 @@ MtrrLibProgramFixedMtrr (
   This function shadows the content of variable MTRRs into an\r
   internal array: VariableMtrr.\r
 \r
-  @param[in]   VariableSettings           The variable MTRR values to shadow\r
-  @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware\r
-  @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR\r
-  @param[in]   MtrrValidAddressMask       The valid address mask for MTRR\r
-  @param[out]  VariableMtrr               The array to shadow variable MTRRs content\r
+  @param[in]   VariableSettings      The variable MTRR values to shadow\r
+  @param[in]   VariableMtrrCount     The number of variable MTRRs\r
+  @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[in]   MtrrValidAddressMask  The valid address mask for MTRR\r
+  @param[out]  VariableMtrr          The array to shadow variable MTRRs content\r
 \r
-  @return                       The return value of this parameter indicates the\r
-                                number of MTRRs which has been used.\r
+  @return      Number of MTRRs which has been used.\r
 \r
 **/\r
 UINT32\r
 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
   IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
-  IN  UINTN                   FirmwareVariableMtrrCount,\r
+  IN  UINTN                   VariableMtrrCount,\r
   IN  UINT64                  MtrrValidBitsMask,\r
   IN  UINT64                  MtrrValidAddressMask,\r
   OUT VARIABLE_MTRR           *VariableMtrr\r
@@ -584,8 +601,8 @@ MtrrGetMemoryAttributeInVariableMtrrWorker (
   UINT32  UsedMtrr;\r
 \r
   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
-  for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
-    if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
+  for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
+    if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
       VariableMtrr[Index].Msr         = (UINT32)Index;\r
       VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
       VariableMtrr[Index].Length      = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
@@ -642,401 +659,315 @@ MtrrGetMemoryAttributeInVariableMtrr (
            );\r
 }\r
 \r
-\r
 /**\r
-  Checks overlap between given memory range and MTRRs.\r
+  Return the least alignment of address.\r
 \r
-  @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available\r
-                                         to firmware.\r
-  @param[in]  Start                      The start address of memory range.\r
-  @param[in]  End                        The end address of memory range.\r
-  @param[in]  VariableMtrr               The array to shadow variable MTRRs content\r
-\r
-  @retval TRUE             Overlap exists.\r
-  @retval FALSE            No overlap.\r
+  @param Address    The address to return the alignment.\r
+  @param Alignment0 The alignment to return when Address is 0.\r
 \r
+  @return The least alignment of the Address.\r
 **/\r
-BOOLEAN\r
-CheckMemoryAttributeOverlap (\r
-  IN UINTN             FirmwareVariableMtrrCount,\r
-  IN PHYSICAL_ADDRESS  Start,\r
-  IN PHYSICAL_ADDRESS  End,\r
-  IN VARIABLE_MTRR     *VariableMtrr\r
-  )\r
+UINT64\r
+MtrrLibLeastAlignment (\r
+  UINT64    Address,\r
+  UINT64    Alignment0\r
+)\r
 {\r
-  UINT32  Index;\r
-\r
-  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
-    if (\r
-         VariableMtrr[Index].Valid &&\r
-         !(\r
-           (Start > (VariableMtrr[Index].BaseAddress +\r
-                     VariableMtrr[Index].Length - 1)\r
-           ) ||\r
-           (End < VariableMtrr[Index].BaseAddress)\r
-         )\r
-       ) {\r
-      return TRUE;\r
-    }\r
+  if (Address == 0) {\r
+    return Alignment0;\r
   }\r
 \r
-  return FALSE;\r
+  return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
 }\r
 \r
-\r
 /**\r
-  Marks a variable MTRR as non-valid.\r
+  Return the number of required variable MTRRs to positively cover the\r
+  specified range.\r
 \r
-  @param[in]   Index         The index of the array VariableMtrr to be invalidated\r
-  @param[in]   VariableMtrr  The array to shadow variable MTRRs content\r
-  @param[out]  UsedMtrr      The number of MTRRs which has already been used\r
+  @param BaseAddress Base address of the range.\r
+  @param Length      Length of the range.\r
+  @param Alignment0  Alignment of 0.\r
 \r
+  @return The number of the required variable MTRRs.\r
 **/\r
-VOID\r
-InvalidateShadowMtrr (\r
-  IN   UINTN              Index,\r
-  IN   VARIABLE_MTRR      *VariableMtrr,\r
-  OUT  UINT32             *UsedMtrr\r
-  )\r
+UINT32\r
+MtrrLibGetPositiveMtrrNumber (\r
+  IN UINT64      BaseAddress,\r
+  IN UINT64      Length,\r
+  IN UINT64      Alignment0\r
+)\r
 {\r
-  VariableMtrr[Index].Valid = FALSE;\r
-  *UsedMtrr = *UsedMtrr - 1;\r
-}\r
-\r
-\r
-/**\r
-  Combines memory attributes.\r
+  UINT64         SubLength;\r
+  UINT32         MtrrNumber;\r
+  BOOLEAN        UseLeastAlignment;\r
 \r
-  If overlap exists between given memory range and MTRRs, try to combine them.\r
+  UseLeastAlignment = TRUE;\r
+  SubLength = 0;\r
 \r
-  @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs\r
-                                              available to firmware.\r
-  @param[in]       Attributes                 The memory type to set.\r
-  @param[in, out]  Base                       The base address of memory range.\r
-  @param[in, out]  Length                     The length of memory range.\r
-  @param[in]       VariableMtrr               The array to shadow variable MTRRs content\r
-  @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used\r
-  @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used\r
-\r
-  @retval EFI_SUCCESS            Memory region successfully combined.\r
-  @retval EFI_ACCESS_DENIED      Memory region cannot be combined.\r
-\r
-**/\r
-RETURN_STATUS\r
-CombineMemoryAttribute (\r
-  IN     UINT32             FirmwareVariableMtrrCount,\r
-  IN     UINT64             Attributes,\r
-  IN OUT UINT64             *Base,\r
-  IN OUT UINT64             *Length,\r
-  IN     VARIABLE_MTRR      *VariableMtrr,\r
-  IN OUT UINT32             *UsedMtrr,\r
-  OUT    BOOLEAN            *OverwriteExistingMtrr\r
-  )\r
-{\r
-  UINT32  Index;\r
-  UINT64  CombineStart;\r
-  UINT64  CombineEnd;\r
-  UINT64  MtrrEnd;\r
-  UINT64  EndAddress;\r
-  BOOLEAN CoveredByExistingMtrr;\r
-\r
-  *OverwriteExistingMtrr = FALSE;\r
-  CoveredByExistingMtrr = FALSE;\r
-  EndAddress = *Base +*Length - 1;\r
-\r
-  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
-\r
-    MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
-    if (\r
-         !VariableMtrr[Index].Valid ||\r
-         (\r
-           *Base > (MtrrEnd) ||\r
-           (EndAddress < VariableMtrr[Index].BaseAddress)\r
-         )\r
-       ) {\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // Combine same attribute MTRR range\r
-    //\r
-    if (Attributes == VariableMtrr[Index].Type) {\r
-      //\r
-      // if the MTRR range contain the request range, set a flag, then continue to\r
-      // invalidate any MTRR of the same request range with higher priority cache type.\r
-      //\r
-      if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
-        CoveredByExistingMtrr = TRUE;\r
-        continue;\r
-      }\r
-      //\r
-      // invalid this MTRR, and program the combine range\r
-      //\r
-      CombineStart  =\r
-        (*Base) < VariableMtrr[Index].BaseAddress ?\r
-          (*Base) :\r
-          VariableMtrr[Index].BaseAddress;\r
-      CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
+  //\r
+  // Calculate the alignment of the base address.\r
+  //\r
+  for (MtrrNumber = 0; Length != 0; MtrrNumber++) {\r
+    if (UseLeastAlignment) {\r
+      SubLength = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
 \r
-      //\r
-      // Record the MTRR usage status in VariableMtrr array.\r
-      //\r
-      InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
-      *Base       = CombineStart;\r
-      *Length     = CombineEnd - CombineStart + 1;\r
-      EndAddress  = CombineEnd;\r
-      *OverwriteExistingMtrr = TRUE;\r
-      continue;\r
-    } else {\r
-      //\r
-      // The cache type is different, but the range is covered by one MTRR\r
-      //\r
-      if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
-        InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
-        continue;\r
+      if (SubLength > Length) {\r
+        //\r
+        // Set a flag when remaining length is too small\r
+        //  so that MtrrLibLeastAlignment() is not called in following loops.\r
+        //\r
+        UseLeastAlignment = FALSE;\r
       }\r
-\r
     }\r
 \r
-    if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
-         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
-        (Attributes == MTRR_CACHE_WRITE_BACK &&\r
-         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
-        (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
-        (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
-     ) {\r
-      *OverwriteExistingMtrr = TRUE;\r
-      continue;\r
+    if (!UseLeastAlignment) {\r
+      SubLength = GetPowerOfTwo64 (Length);\r
     }\r
-    //\r
-    // Other type memory overlap is invalid\r
-    //\r
-    return RETURN_ACCESS_DENIED;\r
-  }\r
 \r
-  if (CoveredByExistingMtrr) {\r
-    *Length = 0;\r
+    BaseAddress += SubLength;\r
+    Length -= SubLength;\r
   }\r
 \r
-  return RETURN_SUCCESS;\r
+  return MtrrNumber;\r
 }\r
 \r
-\r
 /**\r
-  Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
+  Return whether the left MTRR type precedes the right MTRR type.\r
 \r
-  @param[in]  MemoryLength        The number to pass in.\r
+  The MTRR type precedence rules are:\r
+    1. UC precedes any other type\r
+    2. WT precedes WB\r
+  For further details, please refer the IA32 Software Developer's Manual,\r
+  Volume 3, Section "MTRR Precedences".\r
 \r
-  @return The maximum value which is align to power of 2 and less the MemoryLength\r
+  @param Left  The left MTRR type.\r
+  @param Right The right MTRR type.\r
 \r
+  @retval TRUE  Left precedes Right.\r
+  @retval FALSE Left doesn't precede Right.\r
 **/\r
-UINT64\r
-Power2MaxMemory (\r
-  IN UINT64                     MemoryLength\r
-  )\r
+BOOLEAN\r
+MtrrLibTypeLeftPrecedeRight (\r
+  IN MTRR_MEMORY_CACHE_TYPE  Left,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Right\r
+)\r
 {\r
-  UINT64  Result;\r
-\r
-  if (RShiftU64 (MemoryLength, 32) != 0) {\r
-    Result = LShiftU64 (\r
-               (UINT64) GetPowerOfTwo32 (\r
-                          (UINT32) RShiftU64 (MemoryLength, 32)\r
-                          ),\r
-               32\r
-               );\r
-  } else {\r
-    Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
-  }\r
-\r
-  return Result;\r
+  return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
 }\r
 \r
 \r
 /**\r
-  Determines the MTRR numbers used to program a memory range.\r
+  Return whether the type of the specified range can precede the specified type.\r
+\r
+  @param Ranges     Memory range array holding memory type settings for all\r
+                    the memory address.\r
+  @param RangeCount Count of memory ranges.\r
+  @param Type       Type to check precedence.\r
+  @param SubBase    Base address of the specified range.\r
+  @param SubLength  Length of the specified range.\r
+\r
+  @retval TRUE  The type of the specified range can precede the Type.\r
+  @retval FALSE The type of the specified range cannot precede the Type.\r
+                So the subtraction is not applicable.\r
+**/\r
+BOOLEAN\r
+MtrrLibSubstractable (\r
+  IN CONST MEMORY_RANGE     *Ranges,\r
+  IN UINT32                  RangeCount,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Type,\r
+  IN UINT64                  SubBase,\r
+  IN UINT64                  SubLength\r
+)\r
+{\r
+  UINT32                     Index;\r
+  UINT64                     Length;\r
+  // WT > WB\r
+  // UC > *\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
 \r
-  This function first checks the alignment of the base address.\r
-  If the alignment of the base address <= Length, cover the memory range\r
- (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
-  Length -= alignment. Repeat the step until alignment > Length.\r
+      if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
+        return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
 \r
-  Then this function determines which direction of programming the variable\r
-  MTRRs for the remaining length will use fewer MTRRs.\r
+      } else {\r
+        if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
+          return FALSE;\r
+        }\r
 \r
-  @param[in]  BaseAddress Length of Memory to program MTRR\r
-  @param[in]  Length      Length of Memory to program MTRR\r
-  @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs\r
+        Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
+        SubBase += Length;\r
+        SubLength -= Length;\r
+      }\r
+    }\r
+  }\r
 \r
-  @retval TRUE        Positive direction is better.\r
-          FALSE       Negative direction is better.\r
+  ASSERT (FALSE);\r
+  return FALSE;\r
+}\r
 \r
+/**\r
+  Return the number of required variable MTRRs to cover the specified range.\r
+\r
+  The routine considers subtraction in the both side of the range to find out\r
+  the most optimal solution (which uses the least MTRRs).\r
+\r
+  @param Ranges            Array holding memory type settings of all memory\r
+                           address.\r
+  @param RangeCount        Count of memory ranges.\r
+  @param VariableMtrr      Array holding allocated variable MTRRs.\r
+  @param VariableMtrrCount Count of allocated variable MTRRs.\r
+  @param BaseAddress       Base address of the specified range.\r
+  @param Length            Length of the specified range.\r
+  @param Type              MTRR type of the specified range.\r
+  @param Alignment0        Alignment of 0.\r
+  @param SubLeft           Return the count of left subtraction.\r
+  @param SubRight          Return the count of right subtraction.\r
+\r
+  @return Number of required variable MTRRs.\r
 **/\r
-BOOLEAN\r
-GetMtrrNumberAndDirection (\r
-  IN UINT64      BaseAddress,\r
-  IN UINT64      Length,\r
-  IN UINTN       *MtrrNumber\r
+UINT32\r
+MtrrLibGetMtrrNumber (\r
+  IN CONST MEMORY_RANGE    *Ranges,\r
+  IN UINT32                 RangeCount,\r
+  IN CONST VARIABLE_MTRR    *VariableMtrr,\r
+  IN UINT32                 VariableMtrrCount,\r
+  IN UINT64                 BaseAddress,\r
+  IN UINT64                 Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE Type,\r
+  IN UINT64                 Alignment0,\r
+  OUT UINT32                *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR\r
+  OUT UINT32                *SubRight // subtractive from BaseAddress + Length, to save MTRR\r
   )\r
 {\r
-  UINT64  TempQword;\r
   UINT64  Alignment;\r
-  UINT32  Positive;\r
-  UINT32  Subtractive;\r
+  UINT32  LeastLeftMtrrNumber;\r
+  UINT32  MiddleMtrrNumber;\r
+  UINT32  LeastRightMtrrNumber;\r
+  UINT32  CurrentMtrrNumber;\r
+  UINT32  SubtractiveCount;\r
+  UINT32  SubtractiveMtrrNumber;\r
+  UINT32  LeastSubtractiveMtrrNumber;\r
+  UINT64  SubtractiveBaseAddress;\r
+  UINT64  SubtractiveLength;\r
+  UINT64  BaseAlignment;\r
+  UINT32  Index;\r
 \r
-  *MtrrNumber = 0;\r
+  *SubLeft = 0;\r
+  *SubRight = 0;\r
+  LeastSubtractiveMtrrNumber = 0;\r
+  BaseAlignment = 0;\r
 \r
+  //\r
+  // Get the optimal left subtraction solution.\r
+  //\r
   if (BaseAddress != 0) {\r
-    do {\r
+    SubtractiveBaseAddress = 0;\r
+    SubtractiveLength      = 0;\r
+    //\r
+    // Get the MTRR number needed without left subtraction.\r
+    //\r
+    LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
+\r
+    //\r
+    // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
+    //\r
+    for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
+      Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+\r
       //\r
-      // Calculate the alignment of the base address.\r
+      // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.\r
+      // IA32 Manual defines the following override rules:\r
+      //   WT > WB\r
+      //   UC > * (any)\r
       //\r
-      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
-\r
-      if (Alignment > Length) {\r
+      if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
         break;\r
       }\r
 \r
-      (*MtrrNumber)++;\r
-      BaseAddress += Alignment;\r
-      Length -= Alignment;\r
-    } while (TRUE);\r
-\r
-    if (Length == 0) {\r
-      return TRUE;\r
-    }\r
-  }\r
-\r
-  TempQword   = Length;\r
-  Positive    = 0;\r
-  Subtractive = 0;\r
+      for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+        if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&\r
+            (VariableMtrr[Index].Length == Alignment)) {\r
+          break;\r
+        }\r
+      }\r
+      if (Index == VariableMtrrCount) {\r
+        //\r
+        // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR\r
+        //\r
+        SubtractiveMtrrNumber++;\r
+      }\r
 \r
-  do {\r
-    TempQword -= Power2MaxMemory (TempQword);\r
-    Positive++;\r
-  } while (TempQword != 0);\r
+      BaseAddress -= Alignment;\r
+      Length += Alignment;\r
 \r
-  TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
-  Subtractive++;\r
-  do {\r
-    TempQword -= Power2MaxMemory (TempQword);\r
-    Subtractive++;\r
-  } while (TempQword != 0);\r
+      CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
+      if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {\r
+        LeastLeftMtrrNumber = CurrentMtrrNumber;\r
+        LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;\r
+        *SubLeft = SubtractiveCount;\r
+        SubtractiveBaseAddress = BaseAddress;\r
+        SubtractiveLength = Length;\r
+      }\r
+    }\r
 \r
-  if (Positive <= Subtractive) {\r
-    *MtrrNumber += Positive;\r
-    return TRUE;\r
-  } else {\r
-    *MtrrNumber += Subtractive;\r
-    return FALSE;\r
+    //\r
+    // If left subtraction is better, subtract BaseAddress to left, and enlarge Length\r
+    //\r
+    if (*SubLeft != 0) {\r
+      BaseAddress = SubtractiveBaseAddress;\r
+      Length = SubtractiveLength;\r
+    }\r
   }\r
-}\r
-\r
-/**\r
-  Invalid variable MTRRs according to the value in the shadow array.\r
-\r
-  This function programs MTRRs according to the values specified\r
-  in the shadow array.\r
-\r
-  @param[in, out]  VariableSettings   Variable MTRR settings\r
-  @param[in]       VariableMtrrCount  Number of variable MTRRs\r
-  @param[in, out]  VariableMtrr       Shadow of variable MTRR contents\r
 \r
-**/\r
-VOID\r
-InvalidateMtrr (\r
-  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
-  IN     UINTN                   VariableMtrrCount,\r
-  IN OUT VARIABLE_MTRR           *VariableMtrr\r
-  )\r
-{\r
-  UINTN         Index;\r
-\r
-  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-    if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
-       VariableSettings->Mtrr[Index].Base = 0;\r
-       VariableSettings->Mtrr[Index].Mask = 0;\r
-       VariableMtrr[Index].Used = FALSE;\r
+  //\r
+  // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)\r
+  //\r
+  MiddleMtrrNumber = 0;\r
+  while (Length != 0) {\r
+    BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+    if (BaseAlignment > Length) {\r
+      break;\r
     }\r
+    BaseAddress += BaseAlignment;\r
+    Length -= BaseAlignment;\r
+    MiddleMtrrNumber++;\r
   }\r
-}\r
-\r
 \r
-/**\r
-  Programs variable MTRRs\r
-\r
-  This function programs variable MTRRs\r
 \r
-  @param[in, out]  VariableSettings      Variable MTRR settings.\r
-  @param[in]       MtrrNumber            Index of MTRR to program.\r
-  @param[in]       BaseAddress           Base address of memory region.\r
-  @param[in]       Length                Length of memory region.\r
-  @param[in]       MemoryCacheType       Memory type to set.\r
-  @param[in]       MtrrValidAddressMask  The valid address mask for MTRR\r
+  if (Length == 0) {\r
+    return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
+  }\r
 \r
-**/\r
-VOID\r
-ProgramVariableMtrr (\r
-  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
-  IN     UINTN                   MtrrNumber,\r
-  IN     PHYSICAL_ADDRESS        BaseAddress,\r
-  IN     UINT64                  Length,\r
-  IN     UINT64                  MemoryCacheType,\r
-  IN     UINT64                  MtrrValidAddressMask\r
-  )\r
-{\r
-  UINT64        TempQword;\r
 \r
   //\r
-  // MTRR Physical Base\r
+  // Get the optimal right subtraction solution.\r
   //\r
-  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
-  VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
 \r
   //\r
-  // MTRR Physical Mask\r
+  // Get the MTRR number needed without right subtraction.\r
   //\r
-  TempQword = ~(Length - 1);\r
-  VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
-}\r
-\r
-\r
-/**\r
-  Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
+  LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
 \r
-  If MtrrSetting is not NULL, gets the default memory attribute from input\r
-  MTRR settings buffer.\r
-  If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
-\r
-  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
-  @param[in]  MtrrType           MTRR memory type\r
+  for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
+    if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {\r
+      break;\r
+    }\r
 \r
-  @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
+    Length += Alignment;\r
 \r
-**/\r
-MTRR_MEMORY_CACHE_TYPE\r
-GetMemoryCacheTypeFromMtrrType (\r
-  IN MTRR_SETTINGS         *MtrrSetting,\r
-  IN UINT64                MtrrType\r
-  )\r
-{\r
-  switch (MtrrType) {\r
-  case MTRR_CACHE_UNCACHEABLE:\r
-    return CacheUncacheable;\r
-  case MTRR_CACHE_WRITE_COMBINING:\r
-    return CacheWriteCombining;\r
-  case MTRR_CACHE_WRITE_THROUGH:\r
-    return CacheWriteThrough;\r
-  case MTRR_CACHE_WRITE_PROTECTED:\r
-    return CacheWriteProtected;\r
-  case MTRR_CACHE_WRITE_BACK:\r
-    return CacheWriteBack;\r
-  default:\r
     //\r
-    // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
-    // no MTRR covers the range\r
+    // SubtractiveCount = Number of MTRRs used for subtraction\r
     //\r
-    return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
+    CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
+    if (CurrentMtrrNumber <= LeastRightMtrrNumber) {\r
+      LeastRightMtrrNumber = CurrentMtrrNumber;\r
+      *SubRight = SubtractiveCount;\r
+      SubtractiveLength = Length;\r
+    }\r
   }\r
+\r
+  return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
 }\r
 \r
 /**\r
@@ -1054,22 +985,20 @@ MtrrLibInitializeMtrrMask (
   OUT UINT64 *MtrrValidAddressMask\r
   )\r
 {\r
-  UINT32  RegEax;\r
-  UINT8   PhysicalAddressBits;\r
+  UINT32                          MaxExtendedFunction;\r
+  CPUID_VIR_PHY_ADDRESS_SIZE_EAX  VirPhyAddressSize;\r
 \r
-  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
 \r
-  if (RegEax >= 0x80000008) {\r
-    AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
 \r
-    PhysicalAddressBits = (UINT8) RegEax;\r
-\r
-    *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;\r
-    *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
+  if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
+    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
   } else {\r
-    *MtrrValidBitsMask    = MTRR_LIB_MSR_VALID_MASK;\r
-    *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
+    VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
   }\r
+\r
+  *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
+  *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
 }\r
 \r
 \r
@@ -1077,71 +1006,34 @@ MtrrLibInitializeMtrrMask (
   Determines the real attribute of a memory range.\r
 \r
   This function is to arbitrate the real attribute of the memory when\r
-  there are 2 MTRRs covers the same memory range.  For further details,\r
+  there are 2 MTRRs covers the same memory range. For further details,\r
   please refer the IA32 Software Developer's Manual, Volume 3,\r
-  Section 10.11.4.1.\r
+  Section "MTRR Precedences".\r
 \r
   @param[in]  MtrrType1    The first kind of Memory type\r
   @param[in]  MtrrType2    The second kind of memory type\r
 \r
 **/\r
-UINT64\r
+MTRR_MEMORY_CACHE_TYPE\r
 MtrrLibPrecedence (\r
-  IN UINT64    MtrrType1,\r
-  IN UINT64    MtrrType2\r
+  IN MTRR_MEMORY_CACHE_TYPE    MtrrType1,\r
+  IN MTRR_MEMORY_CACHE_TYPE    MtrrType2\r
   )\r
 {\r
-  UINT64 MtrrType;\r
-\r
-  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
-  switch (MtrrType1) {\r
-  case MTRR_CACHE_UNCACHEABLE:\r
-    MtrrType = MTRR_CACHE_UNCACHEABLE;\r
-    break;\r
-  case MTRR_CACHE_WRITE_COMBINING:\r
-    if (\r
-         MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
-         MtrrType2==MTRR_CACHE_UNCACHEABLE\r
-       ) {\r
-      MtrrType = MtrrType2;\r
-    }\r
-    break;\r
-  case MTRR_CACHE_WRITE_THROUGH:\r
-    if (\r
-         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
-         MtrrType2==MTRR_CACHE_WRITE_BACK\r
-       ) {\r
-      MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
-    } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
-      MtrrType = MTRR_CACHE_UNCACHEABLE;\r
-    }\r
-    break;\r
-  case MTRR_CACHE_WRITE_PROTECTED:\r
-    if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
-        MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
-      MtrrType = MtrrType2;\r
-    }\r
-    break;\r
-  case MTRR_CACHE_WRITE_BACK:\r
-    if (\r
-         MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
-         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
-         MtrrType2== MTRR_CACHE_WRITE_BACK\r
-       ) {\r
-      MtrrType = MtrrType2;\r
-    }\r
-    break;\r
-  case MTRR_CACHE_INVALID_TYPE:\r
-    MtrrType = MtrrType2;\r
-    break;\r
-  default:\r
-    break;\r
+  if (MtrrType1 == MtrrType2) {\r
+    return MtrrType1;\r
   }\r
 \r
-  if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
-    MtrrType = MtrrType1;\r
+  ASSERT (\r
+    MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
+    MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
+  );\r
+\r
+  if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
+    return MtrrType1;\r
+  } else {\r
+    return MtrrType2;\r
   }\r
-  return MtrrType;\r
 }\r
 \r
 /**\r
@@ -1163,29 +1055,27 @@ MtrrGetMemoryAttributeByAddressWorker (
   IN PHYSICAL_ADDRESS   Address\r
   )\r
 {\r
-  UINT64                  TempQword;\r
-  UINTN                   Index;\r
-  UINTN                   SubIndex;\r
-  UINT64                  MtrrType;\r
-  UINT64                  TempMtrrType;\r
-  MTRR_MEMORY_CACHE_TYPE  CacheType;\r
-  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
-  UINT64                  MtrrValidBitsMask;\r
-  UINT64                  MtrrValidAddressMask;\r
-  UINTN                   VariableMtrrCount;\r
-  MTRR_VARIABLE_SETTINGS  VariableSettings;\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
+  UINT64                          FixedMtrr;\r
+  UINTN                           Index;\r
+  UINTN                           SubIndex;\r
+  MTRR_MEMORY_CACHE_TYPE          MtrrType;\r
+  VARIABLE_MTRR                   VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT64                          MtrrValidBitsMask;\r
+  UINT64                          MtrrValidAddressMask;\r
+  UINT32                          VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS          VariableSettings;\r
 \r
   //\r
   // Check if MTRR is enabled, if not, return UC as attribute\r
   //\r
   if (MtrrSetting == NULL) {\r
-    TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
+    DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
   } else {\r
-    TempQword = MtrrSetting->MtrrDefType;\r
+    DefType.Uint64 = MtrrSetting->MtrrDefType;\r
   }\r
-  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
 \r
-  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+  if (DefType.Bits.E == 0) {\r
     return CacheUncacheable;\r
   }\r
 \r
@@ -1193,65 +1083,66 @@ MtrrGetMemoryAttributeByAddressWorker (
   // If address is less than 1M, then try to go through the fixed MTRR\r
   //\r
   if (Address < BASE_1MB) {\r
-    if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
+    if (DefType.Bits.FE != 0) {\r
       //\r
       // Go through the fixed MTRR\r
       //\r
       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-         if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
-             Address  < (\r
-                          mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
-                          (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
-                        )\r
-            ) {\r
-           SubIndex =\r
-             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
-               mMtrrLibFixedMtrrTable[Index].Length;\r
-           if (MtrrSetting == NULL) {\r
-             TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
-           } else {\r
-             TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
-           }\r
-           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
-           return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
-         }\r
+        if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+            Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
+            (mMtrrLibFixedMtrrTable[Index].Length * 8)) {\r
+          SubIndex =\r
+            ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+            mMtrrLibFixedMtrrTable[Index].Length;\r
+          if (MtrrSetting == NULL) {\r
+            FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
+          } else {\r
+            FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];\r
+          }\r
+          return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);\r
+        }\r
       }\r
     }\r
   }\r
-  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
 \r
-  MtrrGetVariableMtrrWorker (\r
-    MtrrSetting,\r
-    GetVariableMtrrCountWorker (),\r
-    &VariableSettings\r
-    );\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
 \r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
   MtrrGetMemoryAttributeInVariableMtrrWorker (\r
-           &VariableSettings,\r
-           GetFirmwareVariableMtrrCountWorker (),\r
-           MtrrValidBitsMask,\r
-           MtrrValidAddressMask,\r
-           VariableMtrr\r
-           );\r
+    &VariableSettings,\r
+    VariableMtrrCount,\r
+    MtrrValidBitsMask,\r
+    MtrrValidAddressMask,\r
+    VariableMtrr\r
+  );\r
 \r
   //\r
   // Go through the variable MTRR\r
   //\r
-  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
-  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
-\r
+  MtrrType = CacheInvalid;\r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     if (VariableMtrr[Index].Valid) {\r
       if (Address >= VariableMtrr[Index].BaseAddress &&\r
-          Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
-        TempMtrrType = VariableMtrr[Index].Type;\r
-        MtrrType = MtrrLibPrecedence (MtrrType, TempMtrrType);\r
+          Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
+        if (MtrrType == CacheInvalid) {\r
+          MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;\r
+        } else {\r
+          MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);\r
+        }\r
       }\r
     }\r
   }\r
-  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
 \r
-  return CacheType;\r
+  //\r
+  // If there is no MTRR which covers the Address, use the default MTRR type.\r
+  //\r
+  if (MtrrType == CacheInvalid) {\r
+    MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
+  }\r
+\r
+  return MtrrType;\r
 }\r
 \r
 \r
@@ -1450,33 +1341,466 @@ MtrrDebugPrintAllMtrrs (
   MtrrDebugPrintAllMtrrsWorker (NULL);\r
 }\r
 \r
+/**\r
+  Update the Ranges array to change the specified range identified by\r
+  BaseAddress and Length to Type.\r
+\r
+  @param Ranges      Array holding memory type settings for all memory regions.\r
+  @param Capacity    The maximum count of memory ranges the array can hold.\r
+  @param Count       Return the new memory range count in the array.\r
+  @param BaseAddress The base address of the memory range to change type.\r
+  @param Length      The length of the memory range to change type.\r
+  @param Type        The new type of the specified memory range.\r
+\r
+  @retval RETURN_SUCCESS          The type of the specified memory range is\r
+                                  changed successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
+                                  range exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryType (\r
+  IN MEMORY_RANGE                 *Ranges,\r
+  IN UINT32                        Capacity,\r
+  IN OUT UINT32                    *Count,\r
+  IN UINT64                        BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type\r
+  )\r
+{\r
+  UINT32                           Index;\r
+  UINT64                           Limit;\r
+  UINT64                           LengthLeft;\r
+  UINT64                           LengthRight;\r
+  UINT32                           StartIndex;\r
+  UINT32                           EndIndex;\r
+  UINT32                           DeltaCount;\r
+\r
+  LengthRight = 0;\r
+  LengthLeft  = 0;\r
+  Limit = BaseAddress + Length;\r
+  StartIndex = *Count;\r
+  EndIndex = *Count;\r
+  for (Index = 0; Index < *Count; Index++) {\r
+    if ((StartIndex == *Count) &&\r
+        (Ranges[Index].BaseAddress <= BaseAddress) &&\r
+        (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+      StartIndex = Index;\r
+      LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
+    }\r
+\r
+    if ((EndIndex == *Count) &&\r
+        (Ranges[Index].BaseAddress < Limit) &&\r
+        (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+      EndIndex = Index;\r
+      LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT (StartIndex != *Count && EndIndex != *Count);\r
+  if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
+    return RETURN_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // The type change may cause merging with previous range or next range.\r
+  // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
+  // logic doesn't need to consider merging.\r
+  //\r
+  if (StartIndex != 0) {\r
+    if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
+      StartIndex--;\r
+      Length += Ranges[StartIndex].Length;\r
+      BaseAddress -= Ranges[StartIndex].Length;\r
+    }\r
+  }\r
+  if (EndIndex != (*Count) - 1) {\r
+    if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
+      EndIndex++;\r
+      Length += Ranges[EndIndex].Length;\r
+    }\r
+  }\r
+\r
+  //\r
+  // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount  Count (Count = 4)\r
+  //   |++++++++++++++++++|    0          3         1=3-0-2    3\r
+  //   |+++++++|               0          1        -1=1-0-2    5\r
+  //   |+|                     0          0        -2=0-0-2    6\r
+  // |+++|                     0          0        -1=0-0-2+1  5\r
+  //\r
+  //\r
+  DeltaCount = EndIndex - StartIndex - 2;\r
+  if (LengthLeft == 0) {\r
+    DeltaCount++;\r
+  }\r
+  if (LengthRight == 0) {\r
+    DeltaCount++;\r
+  }\r
+  if (*Count - DeltaCount > Capacity) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Reserve (-DeltaCount) space\r
+  //\r
+  CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
+  *Count -= DeltaCount;\r
+\r
+  if (LengthLeft != 0) {\r
+    Ranges[StartIndex].Length = LengthLeft;\r
+    StartIndex++;\r
+  }\r
+  if (LengthRight != 0) {\r
+    Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
+    Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
+    Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
+  }\r
+  Ranges[StartIndex].BaseAddress = BaseAddress;\r
+  Ranges[StartIndex].Length = Length;\r
+  Ranges[StartIndex].Type = Type;\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the memory range.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+  IN CONST MEMORY_RANGE           *Ranges,\r
+  IN UINT32                        RangeCount,\r
+  IN OUT VARIABLE_MTRR             *VariableMtrr,\r
+  IN UINT32                        VariableMtrrCapacity,\r
+  IN OUT UINT32                    *VariableMtrrCount,\r
+  IN UINT64                        BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type,\r
+  IN UINT64                        Alignment0\r
+  );\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
+  to allocate variable MTRRs when the range contains several sub-ranges\r
+  with different attributes.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the range.\r
+                              If it's CacheInvalid, the memory range may\r
+                              contains several sub-ranges with different\r
+                              attributes.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibAddVariableMtrr (\r
+  IN CONST MEMORY_RANGE           *Ranges,\r
+  IN UINT32                        RangeCount,\r
+  IN OUT VARIABLE_MTRR             *VariableMtrr,\r
+  IN UINT32                        VariableMtrrCapacity,\r
+  IN OUT UINT32                    *VariableMtrrCount,\r
+  IN PHYSICAL_ADDRESS              BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type,\r
+  IN UINT64                        Alignment0\r
+)\r
+{\r
+  RETURN_STATUS                    Status;\r
+  UINT32                           Index;\r
+  UINT64                           SubLength;\r
+\r
+  MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
+  if (Type == CacheInvalid) {\r
+    ASSERT (Ranges != NULL);\r
+    for (Index = 0; Index < RangeCount; Index++) {\r
+      if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+\r
+        //\r
+        // Because the Length may not be aligned to BaseAddress, below code calls\r
+        // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
+        // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
+        // aligned ranges.\r
+        //\r
+        if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
+          return MtrrLibSetMemoryAttributeInVariableMtrr (\r
+            Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+            BaseAddress, Length, Ranges[Index].Type, Alignment0\r
+          );\r
+        } else {\r
+          SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
+          Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
+            Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+            BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
+          );\r
+          if (RETURN_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+          BaseAddress += SubLength;\r
+          Length -= SubLength;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
+    //\r
+    ASSERT (FALSE);\r
+    return RETURN_DEVICE_ERROR;\r
+  } else {\r
+    for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
+      if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
+        ASSERT (VariableMtrr[Index].Type == Type);\r
+        break;\r
+      }\r
+    }\r
+    if (Index == *VariableMtrrCount) {\r
+      if (*VariableMtrrCount == VariableMtrrCapacity) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
+      }\r
+      VariableMtrr[Index].BaseAddress = BaseAddress;\r
+      VariableMtrr[Index].Length = Length;\r
+      VariableMtrr[Index].Type = Type;\r
+      VariableMtrr[Index].Valid = TRUE;\r
+      VariableMtrr[Index].Used = TRUE;\r
+      (*VariableMtrrCount)++;\r
+    }\r
+    return RETURN_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the memory range.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+  IN CONST MEMORY_RANGE     *Ranges,\r
+  IN UINT32                 RangeCount,\r
+  IN OUT VARIABLE_MTRR      *VariableMtrr,\r
+  IN UINT32                 VariableMtrrCapacity,\r
+  IN OUT UINT32             *VariableMtrrCount,\r
+  IN UINT64                 BaseAddress,\r
+  IN UINT64                 Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE Type,\r
+  IN UINT64                 Alignment0\r
+)\r
+{\r
+  UINT64                    Alignment;\r
+  UINT32                    MtrrNumber;\r
+  UINT32                    SubtractiveLeft;\r
+  UINT32                    SubtractiveRight;\r
+  BOOLEAN                   UseLeastAlignment;\r
+\r
+  Alignment = 0;\r
+\r
+  MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
+                                     BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
+\r
+  if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  while (SubtractiveLeft-- != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+    ASSERT (Alignment <= Length);\r
+\r
+    MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
+    BaseAddress -= Alignment;\r
+    Length += Alignment;\r
+  }\r
+\r
+  while (Length != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+    if (Alignment > Length) {\r
+      break;\r
+    }\r
+    MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress, Alignment, Type, Alignment0);\r
+    BaseAddress += Alignment;\r
+    Length -= Alignment;\r
+  }\r
+\r
+  while (SubtractiveRight-- != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
+    MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
+    Length += Alignment;\r
+  }\r
+\r
+  UseLeastAlignment = TRUE;\r
+  while (Length != 0) {\r
+    if (UseLeastAlignment) {\r
+      Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+      if (Alignment > Length) {\r
+        UseLeastAlignment = FALSE;\r
+      }\r
+    }\r
+\r
+    if (!UseLeastAlignment) {\r
+      Alignment = GetPowerOfTwo64 (Length);\r
+    }\r
+\r
+    MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress, Alignment, Type, Alignment0);\r
+    BaseAddress += Alignment;\r
+    Length -= Alignment;\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return an array of memory ranges holding memory type settings for all memory\r
+  address.\r
+\r
+  @param DefaultType       The default memory type.\r
+  @param TotalLength       The total length of the memory.\r
+  @param VariableMtrr      The variable MTRR array.\r
+  @param VariableMtrrCount The count of variable MTRRs.\r
+  @param Ranges            Return the memory range array holding memory type\r
+                           settings for all memory address.\r
+  @param RangeCapacity     The capacity of memory range array.\r
+  @param RangeCount        Return the count of memory range.\r
+\r
+  @retval RETURN_SUCCESS          The memory range array is returned successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibGetMemoryTypes (\r
+  IN MTRR_MEMORY_CACHE_TYPE      DefaultType,\r
+  IN UINT64                      TotalLength,\r
+  IN CONST VARIABLE_MTRR         *VariableMtrr,\r
+  IN UINT32                      VariableMtrrCount,\r
+  OUT MEMORY_RANGE               *Ranges,\r
+  IN UINT32                      RangeCapacity,\r
+  OUT UINT32                     *RangeCount\r
+)\r
+{\r
+  RETURN_STATUS                  Status;\r
+  UINTN                          Index;\r
+\r
+  //\r
+  // WT > WB\r
+  // UC > *\r
+  // UC > * (except WB, UC) > WB\r
+  //\r
+\r
+  //\r
+  // 0. Set whole range as DefaultType\r
+  //\r
+  *RangeCount = 1;\r
+  Ranges[0].BaseAddress = 0;\r
+  Ranges[0].Length = TotalLength;\r
+  Ranges[0].Type = DefaultType;\r
+\r
+  //\r
+  // 1. Set WB\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 2. Set other types than WB or UC\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 3. Set UC\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
 \r
 /**\r
   Worker function attempts to set the attributes for a memory range.\r
 \r
-  If MtrrSettings is not NULL, set the attributes into the input MTRR\r
+  If MtrrSetting is not NULL, set the attributes into the input MTRR\r
   settings buffer.\r
-  If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
+  If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
 \r
   @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.\r
   @param[in]       BaseAddress       The physical address that is the start\r
-                                     address of a memory region.\r
-  @param[in]       Length            The size in bytes of the memory region.\r
-  @param[in]       Attribute         The bit mask of attributes to set for the\r
-                                     memory region.\r
+                                     address of a memory range.\r
+  @param[in]       Length            The size in bytes of the memory range.\r
+  @param[in]       Type              The MTRR type to set for the memory range.\r
 \r
   @retval RETURN_SUCCESS            The attributes were set for the memory\r
-                                    region.\r
+                                    range.\r
   @retval RETURN_INVALID_PARAMETER  Length is zero.\r
   @retval RETURN_UNSUPPORTED        The processor does not support one or\r
                                     more bytes of the memory resource range\r
                                     specified by BaseAddress and Length.\r
-  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
-                                    for the memory resource range specified\r
+  @retval RETURN_UNSUPPORTED        The MTRR type is not support for the\r
+                                    memory resource range specified\r
                                     by BaseAddress and Length.\r
-  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource\r
-                                    range specified by BaseAddress and Length\r
-                                    cannot be modified.\r
   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
                                     modify the attributes of the memory\r
                                     resource range.\r
@@ -1487,97 +1811,82 @@ MtrrSetMemoryAttributeWorker (
   IN OUT MTRR_SETTINGS           *MtrrSetting,\r
   IN PHYSICAL_ADDRESS            BaseAddress,\r
   IN UINT64                      Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE      Attribute\r
+  IN MTRR_MEMORY_CACHE_TYPE      Type\r
   )\r
 {\r
-  UINT64                    TempQword;\r
   RETURN_STATUS             Status;\r
-  UINT64                    MemoryType;\r
-  UINT64                    Alignment;\r
-  BOOLEAN                   OverLap;\r
-  BOOLEAN                   Positive;\r
-  UINT32                    MsrNum;\r
-  UINTN                     MtrrNumber;\r
-  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
-  UINT32                    UsedMtrr;\r
+  UINT32                    Index;\r
+  UINT32                    WorkingIndex;\r
+  //\r
+  // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).\r
+  //\r
+  MEMORY_RANGE              Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];\r
+  UINT32                    RangeCount;\r
   UINT64                    MtrrValidBitsMask;\r
   UINT64                    MtrrValidAddressMask;\r
-  BOOLEAN                   OverwriteExistingMtrr;\r
-  UINT32                    FirmwareVariableMtrrCount;\r
+  UINT64                    Alignment0;\r
   MTRR_CONTEXT              MtrrContext;\r
   BOOLEAN                   MtrrContextValid;\r
-  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
-  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
-  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
-  UINT32                    VariableMtrrCount;\r
-  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
-  BOOLEAN                   ProgramVariableSettings;\r
-  MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;\r
-  UINT32                    Index;\r
+\r
+  MTRR_MEMORY_CACHE_TYPE    DefaultType;\r
+\r
+  UINT32                    MsrIndex;\r
   UINT64                    ClearMask;\r
   UINT64                    OrMask;\r
   UINT64                    NewValue;\r
-  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
 \r
-  MtrrContextValid  = FALSE;\r
-  VariableMtrrCount = 0;\r
-  ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
-  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-    FixedSettingsValid[Index]    = FALSE;\r
-    FixedSettingsModified[Index] = FALSE;\r
-  }\r
-  ProgramVariableSettings = FALSE;\r
+  UINT32                    FirmwareVariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
+  UINT32                    OriginalVariableMtrrCount;\r
+  VARIABLE_MTRR             OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT32                    WorkingVariableMtrrCount;\r
+  VARIABLE_MTRR             WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  BOOLEAN                   VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINTN                     FreeVariableMtrrCount;\r
 \r
-  if (!IsMtrrSupported ()) {\r
-    Status = RETURN_UNSUPPORTED;\r
-    goto Done;\r
+  if (Length == 0) {\r
+    return RETURN_INVALID_PARAMETER;\r
   }\r
 \r
   MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
-\r
-  TempQword = 0;\r
-  MemoryType = (UINT64)Attribute;\r
-  OverwriteExistingMtrr = FALSE;\r
-\r
-  //\r
-  // Check for an invalid parameter\r
-  //\r
-  if (Length == 0) {\r
-    Status = RETURN_INVALID_PARAMETER;\r
-    goto Done;\r
+  if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
+    return RETURN_UNSUPPORTED;\r
   }\r
+  OriginalVariableMtrrCount = 0;\r
+  VariableSettings          = NULL;\r
 \r
-  if (\r
-       (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
-       (Length & ~MtrrValidAddressMask) != 0\r
-     ) {\r
-    Status = RETURN_UNSUPPORTED;\r
-    goto Done;\r
+  ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    FixedSettingsValid[Index]    = FALSE;\r
+    FixedSettingsModified[Index] = FALSE;\r
   }\r
 \r
   //\r
   // Check if Fixed MTRR\r
   //\r
-  Status = RETURN_SUCCESS;\r
   if (BaseAddress < BASE_1MB) {\r
-    MsrNum = (UINT32)-1;\r
-    while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
-      Status = MtrrLibProgramFixedMtrr (Attribute, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
+    MsrIndex = (UINT32)-1;\r
+    while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
+      Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
       if (RETURN_ERROR (Status)) {\r
-        goto Done;\r
+        return Status;\r
       }\r
       if (MtrrSetting != NULL) {\r
-        MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
-        MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
+        MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
+        ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
       } else {\r
-        if (!FixedSettingsValid[MsrNum]) {\r
-          WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
-          FixedSettingsValid[MsrNum] = TRUE;\r
+        if (!FixedSettingsValid[MsrIndex]) {\r
+          WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);\r
+          FixedSettingsValid[MsrIndex] = TRUE;\r
         }\r
-        NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
-        if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
-          WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
-          FixedSettingsModified[MsrNum] = TRUE;\r
+        NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
+        if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {\r
+          WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;\r
+          FixedSettingsModified[MsrIndex] = TRUE;\r
         }\r
       }\r
     }\r
@@ -1593,198 +1902,180 @@ MtrrSetMemoryAttributeWorker (
   }\r
 \r
   //\r
-  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
-  // we can set the base to 0 to save variable MTRRs.\r
+  // Read the default MTRR type\r
   //\r
-  if (BaseAddress == BASE_1MB) {\r
-    BaseAddress = 0;\r
-    Length += SIZE_1MB;\r
-  }\r
+  DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
 \r
   //\r
-  // Read all variable MTRRs\r
+  // Read all variable MTRRs and convert to Ranges.\r
   //\r
-  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
-  if (MtrrSetting != NULL) {\r
-    VariableSettings = &MtrrSetting->Variables;\r
+  OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  if (MtrrSetting == NULL) {\r
+    ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));\r
+    MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);\r
+    VariableSettings = &OriginalVariableSettings;\r
   } else {\r
-    MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
-    CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
-    ProgramVariableSettings = TRUE;\r
-    VariableSettings = &WorkingVariableSettings;\r
-  }\r
-\r
-  //\r
-  // Check for overlap\r
-  //\r
-  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
-               VariableSettings,\r
-               FirmwareVariableMtrrCount,\r
-               MtrrValidBitsMask,\r
-               MtrrValidAddressMask,\r
-               VariableMtrr\r
-               );\r
-  OverLap = CheckMemoryAttributeOverlap (\r
-              FirmwareVariableMtrrCount,\r
-              BaseAddress,\r
-              BaseAddress + Length - 1,\r
-              VariableMtrr\r
-              );\r
-  if (OverLap) {\r
-    Status = CombineMemoryAttribute (\r
-               FirmwareVariableMtrrCount,\r
-               MemoryType,\r
-               &BaseAddress,\r
-               &Length,\r
-               VariableMtrr,\r
-               &UsedMtrr,\r
-               &OverwriteExistingMtrr\r
-               );\r
-    if (RETURN_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
-\r
-    if (Length == 0) {\r
-      //\r
-      // Combined successfully, invalidate the now-unused MTRRs\r
-      //\r
-      InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
-      Status = RETURN_SUCCESS;\r
-      goto Done;\r
-    }\r
+    VariableSettings = &MtrrSetting->Variables;\r
   }\r
+  MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);\r
+\r
+  Status = MtrrLibGetMemoryTypes (\r
+    DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,\r
+    Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount\r
+  );\r
+  ASSERT (Status == RETURN_SUCCESS);\r
+\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
+  ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
 \r
   //\r
-  // The memory type is the same with the type specified by\r
-  // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
+  // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
   //\r
-  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {\r
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
-    goto Done;\r
+  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
+  ASSERT (Status == RETURN_SUCCESS);\r
+  //\r
+  // Apply Type to [BaseAddress, BaseAddress + Length)\r
+  //\r
+  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
+  if (RETURN_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
-  Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
-\r
-  if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
-    Status = RETURN_OUT_OF_RESOURCES;\r
-    goto Done;\r
+  Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
+  WorkingVariableMtrrCount = 0;\r
+  ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if (Ranges[Index].Type != DefaultType) {\r
+      //\r
+      // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)\r
+      // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that\r
+      //\r
+      Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
+        Ranges, RangeCount,\r
+        WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,\r
+        Ranges[Index].BaseAddress, Ranges[Index].Length,\r
+        Ranges[Index].Type, Alignment0\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
   }\r
 \r
   //\r
-  // Invalidate the now-unused MTRRs\r
+  // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
   //\r
-  InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+  if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {\r
+    ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);\r
+    WorkingVariableMtrrCount--;\r
+    CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));\r
+  }\r
 \r
-  //\r
-  // Find first unused MTRR\r
-  //\r
-  for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
-    if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-      break;\r
-    }\r
+  if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
   }\r
 \r
-  if (BaseAddress != 0) {\r
-    do {\r
-      //\r
-      // Calculate the alignment of the base address.\r
-      //\r
-      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    VariableSettingModified[Index] = FALSE;\r
 \r
-      if (Alignment > Length) {\r
+    if (!OriginalVariableMtrr[Index].Valid) {\r
+      continue;\r
+    }\r
+    for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
+      if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&\r
+          OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&\r
+          OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {\r
         break;\r
       }\r
+    }\r
 \r
+    if (WorkingIndex == WorkingVariableMtrrCount) {\r
       //\r
-      // Find unused MTRR\r
+      // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr\r
       //\r
-      for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
-        if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+      OriginalVariableMtrr[Index].Valid = FALSE;\r
+      VariableSettingModified[Index] = TRUE;\r
+    } else {\r
+      //\r
+      // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr\r
+      //\r
+      WorkingVariableMtrr[WorkingIndex].Valid = FALSE;\r
+    }\r
+    //\r
+    // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.\r
+    //\r
+  }\r
+\r
+  //\r
+  // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr\r
+  //\r
+  for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (!OriginalVariableMtrr[Index].Valid) {\r
+      for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
+        if (WorkingVariableMtrr[WorkingIndex].Valid) {\r
           break;\r
         }\r
       }\r
-\r
-      ProgramVariableMtrr (\r
-        VariableSettings,\r
-        MsrNum,\r
-        BaseAddress,\r
-        Alignment,\r
-        MemoryType,\r
-        MtrrValidAddressMask\r
-        );\r
-      BaseAddress += Alignment;\r
-      Length -= Alignment;\r
-    } while (TRUE);\r
-\r
-    if (Length == 0) {\r
-      goto Done;\r
+      if (WorkingIndex == WorkingVariableMtrrCount) {\r
+        FreeVariableMtrrCount++;\r
+      } else {\r
+        CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
+        VariableSettingModified[Index] = TRUE;\r
+        WorkingIndex++;\r
+      }\r
     }\r
   }\r
+  ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
 \r
-  TempQword = Length;\r
-\r
-  if (!Positive) {\r
-    Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
+  //\r
+  // Move MTRRs after the FirmwareVariableMtrrCount position to beginning\r
+  //\r
+  if (FirmwareVariableMtrrCount < OriginalVariableMtrrCount) {\r
+    WorkingIndex = FirmwareVariableMtrrCount;\r
+    for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+      if (!OriginalVariableMtrr[Index].Valid) {\r
+        //\r
+        // Found an empty MTRR in WorkingIndex position\r
+        //\r
+        for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
+          if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
+            break;\r
+          }\r
+        }\r
 \r
-    //\r
-    // Find unused MTRR\r
-    //\r
-    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
-      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-        break;\r
+        if (WorkingIndex != OriginalVariableMtrrCount) {\r
+          CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
+          VariableSettingModified[Index] = TRUE;\r
+          VariableSettingModified[WorkingIndex] = TRUE;\r
+          OriginalVariableMtrr[WorkingIndex].Valid = FALSE;\r
+        }\r
       }\r
     }\r
-\r
-    ProgramVariableMtrr (\r
-      VariableSettings,\r
-      MsrNum,\r
-      BaseAddress,\r
-      Length,\r
-      MemoryType,\r
-      MtrrValidAddressMask\r
-      );\r
-    BaseAddress += Length;\r
-    TempQword   = Length - TempQword;\r
-    MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
   }\r
 \r
-  do {\r
-    //\r
-    // Find unused MTRR\r
-    //\r
-    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
-      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-        break;\r
+  //\r
+  // Convert OriginalVariableMtrr to VariableSettings\r
+  // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
+  //\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (VariableSettingModified[Index]) {\r
+      if (OriginalVariableMtrr[Index].Valid) {\r
+        VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;\r
+        VariableSettings->Mtrr[Index].Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
+      } else {\r
+        VariableSettings->Mtrr[Index].Base = 0;\r
+        VariableSettings->Mtrr[Index].Mask = 0;\r
       }\r
     }\r
-\r
-    Length = Power2MaxMemory (TempQword);\r
-    if (!Positive) {\r
-      BaseAddress -= Length;\r
-    }\r
-\r
-    ProgramVariableMtrr (\r
-      VariableSettings,\r
-      MsrNum,\r
-      BaseAddress,\r
-      Length,\r
-      MemoryType,\r
-      MtrrValidAddressMask\r
-      );\r
-\r
-    if (Positive) {\r
-      BaseAddress += Length;\r
-    }\r
-    TempQword -= Length;\r
-\r
-  } while (TempQword > 0);\r
+  }\r
 \r
 Done:\r
+  if (MtrrSetting != NULL) {\r
+    ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;\r
+    return RETURN_SUCCESS;\r
+  }\r
 \r
+  MtrrContextValid = FALSE;\r
   //\r
   // Write fixed MTRRs that have been modified\r
   //\r
@@ -1803,52 +2094,43 @@ Done:
 \r
   //\r
   // Write variable MTRRs\r
+  // When only fixed MTRRs were changed, below loop doesn't run\r
+  // because OriginalVariableMtrrCount equals to 0.\r
   //\r
-  if (ProgramVariableSettings) {\r
-    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-      if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
-          WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {\r
-        if (!MtrrContextValid) {\r
-          MtrrLibPreMtrrChange (&MtrrContext);\r
-          MtrrContextValid = TRUE;\r
-        }\r
-        AsmWriteMsr64 (\r
-          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
-          WorkingVariableSettings.Mtrr[Index].Base\r
-          );\r
-        AsmWriteMsr64 (\r
-          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
-          WorkingVariableSettings.Mtrr[Index].Mask\r
-          );\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (VariableSettingModified[Index]) {\r
+      if (!MtrrContextValid) {\r
+        MtrrLibPreMtrrChange (&MtrrContext);\r
+        MtrrContextValid = TRUE;\r
       }\r
+      AsmWriteMsr64 (\r
+        MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+        VariableSettings->Mtrr[Index].Base\r
+      );\r
+      AsmWriteMsr64 (\r
+        MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
+        VariableSettings->Mtrr[Index].Mask\r
+      );\r
     }\r
   }\r
   if (MtrrContextValid) {\r
     MtrrLibPostMtrrChange (&MtrrContext);\r
   }\r
 \r
-  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
-  if (!RETURN_ERROR (Status)) {\r
-    if (MtrrSetting != NULL) {\r
-      MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
-    }\r
-    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
-  }\r
-\r
-  return Status;\r
+  return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
   This function attempts to set the attributes for a memory range.\r
 \r
   @param[in]  BaseAddress        The physical address that is the start\r
-                                 address of a memory region.\r
-  @param[in]  Length             The size in bytes of the memory region.\r
+                                 address of a memory range.\r
+  @param[in]  Length             The size in bytes of the memory range.\r
   @param[in]  Attributes         The bit mask of attributes to set for the\r
-                                 memory region.\r
+                                 memory range.\r
 \r
   @retval RETURN_SUCCESS            The attributes were set for the memory\r
-                                    region.\r
+                                    range.\r
   @retval RETURN_INVALID_PARAMETER  Length is zero.\r
   @retval RETURN_UNSUPPORTED        The processor does not support one or\r
                                     more bytes of the memory resource range\r
@@ -1872,13 +2154,20 @@ MtrrSetMemoryAttribute (
   IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
   )\r
 {\r
-  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
-  return MtrrSetMemoryAttributeWorker (\r
-           NULL,\r
-           BaseAddress,\r
-           Length,\r
-           Attribute\r
-           );\r
+  RETURN_STATUS              Status;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);\r
+  DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",\r
+          mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
+\r
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrsWorker (NULL);\r
+  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -1886,12 +2175,12 @@ MtrrSetMemoryAttribute (
 \r
   @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
   @param[in]       BaseAddress  The physical address that is the start address\r
-                                of a memory region.\r
-  @param[in]       Length       The size in bytes of the memory region.\r
+                                of a memory range.\r
+  @param[in]       Length       The size in bytes of the memory range.\r
   @param[in]       Attribute    The bit mask of attributes to set for the\r
-                                memory region.\r
+                                memory range.\r
 \r
-  @retval RETURN_SUCCESS            The attributes were set for the memory region.\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory range.\r
   @retval RETURN_INVALID_PARAMETER  Length is zero.\r
   @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the\r
                                     memory resource range specified by BaseAddress and Length.\r
@@ -1912,13 +2201,16 @@ MtrrSetMemoryAttributeInMtrrSettings (
   IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
   )\r
 {\r
-  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
-  return MtrrSetMemoryAttributeWorker (\r
-           MtrrSetting,\r
-           BaseAddress,\r
-           Length,\r
-           Attribute\r
-           );\r
+  RETURN_STATUS              Status;\r
+  Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",\r
+         MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
+\r
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -1940,11 +2232,11 @@ MtrrSetVariableMtrrWorker (
 \r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
+      MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
       VariableSettings->Mtrr[Index].Base\r
       );\r
     AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
+      MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
       VariableSettings->Mtrr[Index].Mask\r
       );\r
   }\r
@@ -2065,7 +2357,7 @@ MtrrGetAllMtrrs (
   //\r
   // Get MTRR_DEF_TYPE value\r
   //\r
-  MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
+  MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
 \r
   return MtrrSetting;\r
 }\r
@@ -2106,7 +2398,7 @@ MtrrSetAllMtrrs (
   //\r
   // Set MTRR_DEF_TYPE value\r
   //\r
-  AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
+  AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
 \r
   MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
 \r
@@ -2149,3 +2441,4 @@ IsMtrrSupported (
   }\r
   return TRUE;\r
 }\r
+\r