]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Fix bug that may incorrectly set <1MB attribute
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index 31a08a3935c8b87256d47706f5eef38893d6733c..200becdd4a2500eb3145788bc2f97a19a47c3aae 100644 (file)
@@ -16,8 +16,7 @@
 \r
 **/\r
 \r
-#include <Base.h>\r
-\r
+#include <Uefi.h>\r
 #include <Register/Cpuid.h>\r
 #include <Register/Msr.h>\r
 \r
 \r
 #define OR_SEED      0x0101010101010101ull\r
 #define CLEAR_SEED   0xFFFFFFFFFFFFFFFFull\r
-\r
+#define MAX_WEIGHT   MAX_UINT8\r
+#define SCRATCH_BUFFER_SIZE           (4 * SIZE_4KB)\r
 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
+\r
+#define M(x,y) ((x) * VectorCount + (y))\r
+#define O(x,y) ((y) * VectorCount + (x))\r
+\r
 //\r
 // Context to save and restore when MTRRs are programmed\r
 //\r
@@ -40,67 +44,75 @@ typedef struct {
 } MTRR_CONTEXT;\r
 \r
 typedef struct {\r
-  UINT64                 BaseAddress;\r
+  UINT64                 Address;\r
+  UINT64                 Alignment;\r
   UINT64                 Length;\r
-  MTRR_MEMORY_CACHE_TYPE Type;\r
-} MEMORY_RANGE;\r
+  UINT8                  Type : 7;\r
+\r
+  //\r
+  // Temprary use for calculating the best MTRR settings.\r
+  //\r
+  BOOLEAN                Visited : 1;\r
+  UINT8                  Weight;\r
+  UINT16                 Previous;\r
+} MTRR_LIB_ADDRESS;\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
@@ -120,6 +132,21 @@ GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
   "R*"   // Invalid\r
 };\r
 \r
+\r
+/**\r
+  Worker function prints all MTRRs for debugging.\r
+\r
+  If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
+  settings buffer.\r
+  If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+  @param  MtrrSetting    A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
+  );\r
+\r
 /**\r
   Worker function returns the variable MTRR count for the CPU.\r
 \r
@@ -134,7 +161,7 @@ GetVariableMtrrCountWorker (
   MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
 \r
   MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
-  ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr));\r
   return MtrrCap.Bits.VCNT;\r
 }\r
 \r
@@ -214,11 +241,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
@@ -254,6 +285,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
@@ -278,7 +310,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
@@ -330,10 +364,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
@@ -407,14 +445,17 @@ MtrrGetVariableMtrrWorker (
 {\r
   UINT32  Index;\r
 \r
-  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
 \r
   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
-      VariableSettings->Mtrr[Index].Mask =\r
-        AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
+      VariableSettings->Mtrr[Index].Mask = AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
+      //\r
+      // Skip to read the Base MSR when the Mask.V is not set.\r
+      //\r
+      if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
+        VariableSettings->Mtrr[Index].Base = AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
+      }\r
     } else {\r
       VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
       VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
@@ -455,10 +496,10 @@ MtrrGetVariableMtrr (
   @param[in]      Type             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, out] LastMsrNum       On input, the last index of the fixed MTRR MSR to program.\r
+  @param[in, out] LastMsrIndex     On input, the last index of the fixed MTRR MSR to program.\r
                                    On return, the current index of the fixed MTRR MSR to program.\r
-  @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.\r
-  @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.\r
+  @param[out]     ClearMask        The bits to clear in the fixed MTRR MSR.\r
+  @param[out]     OrMask           The bits to set in the fixed MTRR MSR.\r
 \r
   @retval RETURN_SUCCESS      The cache type was updated successfully\r
   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
@@ -470,27 +511,25 @@ MtrrLibProgramFixedMtrr (
   IN     MTRR_MEMORY_CACHE_TYPE  Type,\r
   IN OUT UINT64                  *Base,\r
   IN OUT UINT64                  *Length,\r
-  IN OUT UINT32                  *LastMsrNum,\r
-  OUT    UINT64                  *ReturnClearMask,\r
-  OUT    UINT64                  *ReturnOrMask\r
+  IN OUT UINT32                  *LastMsrIndex,\r
+  OUT    UINT64                  *ClearMask,\r
+  OUT    UINT64                  *OrMask\r
   )\r
 {\r
-  UINT32  MsrNum;\r
+  UINT32  MsrIndex;\r
   UINT32  LeftByteShift;\r
   UINT32  RightByteShift;\r
-  UINT64  OrMask;\r
-  UINT64  ClearMask;\r
   UINT64  SubLength;\r
 \r
   //\r
   // Find the fixed MTRR index to be programmed\r
   //\r
-  for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
-    if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
+  for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
+    if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&\r
         (*Base <\r
             (\r
-              mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
-              (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
+              mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +\r
+              (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)\r
             )\r
           )\r
         ) {\r
@@ -498,65 +537,63 @@ MtrrLibProgramFixedMtrr (
     }\r
   }\r
 \r
-  if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
+  ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));\r
 \r
   //\r
   // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
   //\r
-  LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)\r
-               / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
-\r
-  if (LeftByteShift >= 8) {\r
+  if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
+    //\r
+    // Base address should be aligned to the begin of a certain Fixed MTRR range.\r
+    //\r
     return RETURN_UNSUPPORTED;\r
   }\r
+  LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
+  ASSERT (LeftByteShift < 8);\r
 \r
   //\r
   // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
   //\r
-  SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);\r
+  SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);\r
   if (*Length >= SubLength) {\r
     RightByteShift = 0;\r
   } else {\r
-    RightByteShift = 8 - LeftByteShift -\r
-                (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
-    if ((LeftByteShift >= 8) ||\r
-        (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)\r
-        ) {\r
+    if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
+      //\r
+      // Length should be aligned to the end of a certain Fixed MTRR range.\r
+      //\r
       return RETURN_UNSUPPORTED;\r
     }\r
+    RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
     //\r
     // Update SubLength by actual length\r
     //\r
     SubLength = *Length;\r
   }\r
 \r
-  ClearMask = CLEAR_SEED;\r
-  OrMask    = MultU64x32 (OR_SEED, (UINT32) Type);\r
+  *ClearMask = CLEAR_SEED;\r
+  *OrMask    = MultU64x32 (OR_SEED, (UINT32) Type);\r
 \r
   if (LeftByteShift != 0) {\r
     //\r
     // Clear the low bits by LeftByteShift\r
     //\r
-    ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);\r
-    OrMask    &= LShiftU64 (OrMask, LeftByteShift * 8);\r
+    *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);\r
+    *OrMask    &= LShiftU64 (*OrMask,    LeftByteShift * 8);\r
   }\r
 \r
   if (RightByteShift != 0) {\r
     //\r
     // Clear the high bits by RightByteShift\r
     //\r
-    ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);\r
-    OrMask    &= RShiftU64 (OrMask, RightByteShift * 8);\r
+    *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);\r
+    *OrMask    &= RShiftU64 (*OrMask,    RightByteShift * 8);\r
   }\r
 \r
   *Length -= SubLength;\r
   *Base   += SubLength;\r
 \r
-  *LastMsrNum      = MsrNum;\r
-  *ReturnClearMask = ClearMask;\r
-  *ReturnOrMask    = OrMask;\r
+  *LastMsrIndex    = MsrIndex;\r
 \r
   return RETURN_SUCCESS;\r
 }\r
@@ -568,20 +605,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
@@ -590,12 +626,13 @@ MtrrGetMemoryAttributeInVariableMtrrWorker (
   UINTN   Index;\r
   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
+  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));\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
+      VariableMtrr[Index].Length      =\r
+        ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
       VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
       VariableMtrr[Index].Valid       = TRUE;\r
       VariableMtrr[Index].Used        = TRUE;\r
@@ -605,6 +642,44 @@ MtrrGetMemoryAttributeInVariableMtrrWorker (
   return UsedMtrr;\r
 }\r
 \r
+/**\r
+  Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.\r
+  One MTRR_MEMORY_RANGE element is created for each MTRR setting.\r
+  The routine doesn't remove the overlap or combine the near-by region.\r
+\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      Number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+MtrrLibGetRawVariableRanges (\r
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN  UINTN                   VariableMtrrCount,\r
+  IN  UINT64                  MtrrValidBitsMask,\r
+  IN  UINT64                  MtrrValidAddressMask,\r
+  OUT MTRR_MEMORY_RANGE       *VariableMtrr\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT32  UsedMtrr;\r
+\r
+  ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));\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].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
+      VariableMtrr[Index].Length      =\r
+        ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
+      VariableMtrr[Index].Type        = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);\r
+      UsedMtrr++;\r
+    }\r
+  }\r
+  return UsedMtrr;\r
+}\r
 \r
 /**\r
   Gets the attribute of variable MTRRs.\r
@@ -650,7 +725,8 @@ MtrrGetMemoryAttributeInVariableMtrr (
 }\r
 \r
 /**\r
-  Return the least alignment of address.\r
+  Return the biggest alignment (lowest set bit) of address.\r
+  The function is equivalent to: 1 << LowBitSet64 (Address).\r
 \r
   @param Address    The address to return the alignment.\r
   @param Alignment0 The alignment to return when Address is 0.\r
@@ -658,7 +734,7 @@ MtrrGetMemoryAttributeInVariableMtrr (
   @return The least alignment of the Address.\r
 **/\r
 UINT64\r
-MtrrLibLeastAlignment (\r
+MtrrLibBiggestAlignment (\r
   UINT64    Address,\r
   UINT64    Alignment0\r
 )\r
@@ -667,65 +743,17 @@ MtrrLibLeastAlignment (
     return Alignment0;\r
   }\r
 \r
-  return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
-}\r
-\r
-/**\r
-  Return the number of required variable MTRRs to positively cover the\r
-  specified range.\r
-\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
-UINT32\r
-MtrrLibGetPositiveMtrrNumber (\r
-  IN UINT64      BaseAddress,\r
-  IN UINT64      Length,\r
-  IN UINT64      Alignment0\r
-)\r
-{\r
-  UINT64         SubLength;\r
-  UINT32         MtrrNumber;\r
-  BOOLEAN        UseLeastAlignment;\r
-\r
-  UseLeastAlignment = TRUE;\r
-\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
-      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
-    if (!UseLeastAlignment) {\r
-      SubLength = GetPowerOfTwo64 (Length);\r
-    }\r
-\r
-    BaseAddress += SubLength;\r
-    Length -= SubLength;\r
-  }\r
-\r
-  return MtrrNumber;\r
+  return Address & ((~Address) + 1);\r
 }\r
 \r
 /**\r
   Return whether the left MTRR type precedes the right MTRR type.\r
 \r
   The MTRR type precedence rules are:\r
-  1. UC precedes any other type\r
-  2. WT precedes WB\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
   @param Left  The left MTRR type.\r
   @param Right The right MTRR type.\r
@@ -742,258 +770,6 @@ MtrrLibTypeLeftPrecedeRight (
   return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
 }\r
 \r
-\r
-/**\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
-      if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
-        return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
-\r
-      } else {\r
-        if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
-          return FALSE;\r
-        }\r
-\r
-        Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
-        SubBase += Length;\r
-        SubLength -= Length;\r
-      }\r
-    }\r
-  }\r
-\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
-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  Alignment;\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
-  *SubLeft = 0;\r
-  *SubRight = 0;\r
-  LeastSubtractiveMtrrNumber = 0;\r
-\r
-  //\r
-  // Get the optimal left subtraction solution.\r
-  //\r
-  if (BaseAddress != 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
-      // 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
-      if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
-        break;\r
-      }\r
-\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
-      BaseAddress -= Alignment;\r
-      Length += Alignment;\r
-\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
-    //\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
-  // 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
-  if (Length == 0) {\r
-    return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
-  }\r
-\r
-\r
-  //\r
-  // Get the optimal right subtraction solution.\r
-  //\r
-\r
-  //\r
-  // Get the MTRR number needed without right subtraction.\r
-  //\r
-  LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
-\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
-    Length += Alignment;\r
-\r
-    //\r
-    // SubtractiveCount = Number of MTRRs used for subtraction\r
-    //\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
-/**\r
-  Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\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
-\r
-  @return The enum item in MTRR_MEMORY_CACHE_TYPE\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
-    //\r
-    return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
-  }\r
-}\r
-\r
 /**\r
   Initializes the valid bits mask and valid address mask for MTRRs.\r
 \r
@@ -1030,71 +806,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
@@ -1116,29 +855,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
+  MTRR_MEMORY_RANGE               VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.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
@@ -1146,65 +883,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 <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));\r
+  MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
 \r
-  MtrrGetMemoryAttributeInVariableMtrrWorker (\r
-           &VariableSettings,\r
-           GetFirmwareVariableMtrrCountWorker (),\r
-           MtrrValidBitsMask,\r
-           MtrrValidAddressMask,\r
-           VariableMtrr\r
-           );\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  MtrrLibGetRawVariableRanges (\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 (VariableMtrr[Index].Length != 0) {\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
@@ -1232,211 +970,43 @@ MtrrGetMemoryAttribute (
 }\r
 \r
 /**\r
-  Worker function prints all MTRRs for debugging.\r
+  Update the Ranges array to change the specified range identified by\r
+  BaseAddress and Length to Type.\r
 \r
-  If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
-  settings buffer.\r
-  If MtrrSetting is NULL, print MTRR settings from MTRRs.\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
-  @param  MtrrSetting    A buffer holding all MTRRs content.\r
-**/\r
-VOID\r
-MtrrDebugPrintAllMtrrsWorker (\r
-  IN MTRR_SETTINGS    *MtrrSetting\r
-  )\r
-{\r
-  DEBUG_CODE (\r
-    MTRR_SETTINGS  LocalMtrrs;\r
-    MTRR_SETTINGS  *Mtrrs;\r
-    UINTN          Index;\r
-    UINTN          Index1;\r
-    UINTN          VariableMtrrCount;\r
-    UINT64         Base;\r
-    UINT64         Limit;\r
-    UINT64         MtrrBase;\r
-    UINT64         MtrrLimit;\r
-    UINT64         RangeBase;\r
-    UINT64         RangeLimit;\r
-    UINT64         NoRangeBase;\r
-    UINT64         NoRangeLimit;\r
-    UINT32         RegEax;\r
-    UINTN          MemoryType;\r
-    UINTN          PreviousMemoryType;\r
-    BOOLEAN        Found;\r
-\r
-    if (!IsMtrrSupported ()) {\r
-      return;\r
-    }\r
-\r
-    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
-    DEBUG((DEBUG_CACHE, "=============\n"));\r
-\r
-    if (MtrrSetting != NULL) {\r
-      Mtrrs = MtrrSetting;\r
-    } else {\r
-      MtrrGetAllMtrrs (&LocalMtrrs);\r
-      Mtrrs = &LocalMtrrs;\r
-    }\r
-\r
-    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
-    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
-    }\r
-\r
-    VariableMtrrCount = GetVariableMtrrCount ();\r
-    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-      DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
-        Index,\r
-        Mtrrs->Variables.Mtrr[Index].Base,\r
-        Mtrrs->Variables.Mtrr[Index].Mask\r
-        ));\r
-    }\r
-    DEBUG((DEBUG_CACHE, "\n"));\r
-    DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
-    DEBUG((DEBUG_CACHE, "====================================\n"));\r
-\r
-    Base = 0;\r
-    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
-    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-      Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
-      for (Index1 = 0; Index1 < 8; Index1++) {\r
-      MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
-        if (MemoryType > CacheWriteBack) {\r
-          MemoryType = MTRR_CACHE_INVALID_TYPE;\r
-        }\r
-        if (MemoryType != PreviousMemoryType) {\r
-          if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
-            DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
-          }\r
-          PreviousMemoryType = MemoryType;\r
-          DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
-        }\r
-        Base += mMtrrLibFixedMtrrTable[Index].Length;\r
-      }\r
-    }\r
-    DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
-\r
-    VariableMtrrCount = GetVariableMtrrCount ();\r
-\r
-    Limit        = BIT36 - 1;\r
-    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
-    if (RegEax >= 0x80000008) {\r
-      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
-      Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
-    }\r
-    Base = BASE_1MB;\r
-    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
-    do {\r
-      MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
-      if (MemoryType > CacheWriteBack) {\r
-        MemoryType = MTRR_CACHE_INVALID_TYPE;\r
-      }\r
-\r
-      if (MemoryType != PreviousMemoryType) {\r
-        if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
-          DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
-        }\r
-        PreviousMemoryType = MemoryType;\r
-        DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
-      }\r
-\r
-      RangeBase    = BASE_1MB;\r
-      NoRangeBase  = BASE_1MB;\r
-      RangeLimit   = Limit;\r
-      NoRangeLimit = Limit;\r
-\r
-      for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
-        if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
-          //\r
-          // If mask is not valid, then do not display range\r
-          //\r
-          continue;\r
-        }\r
-        MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
-        MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
-\r
-        if (Base >= MtrrBase && Base < MtrrLimit) {\r
-          Found = TRUE;\r
-        }\r
-\r
-        if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
-          RangeBase = MtrrBase;\r
-        }\r
-        if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
-          RangeBase = MtrrLimit + 1;\r
-        }\r
-        if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
-          RangeLimit = MtrrBase - 1;\r
-        }\r
-        if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
-          RangeLimit = MtrrLimit;\r
-        }\r
-\r
-        if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
-          NoRangeBase = MtrrLimit + 1;\r
-        }\r
-        if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
-          NoRangeLimit = MtrrBase - 1;\r
-        }\r
-      }\r
-\r
-      if (Found) {\r
-        Base = RangeLimit + 1;\r
-      } else {\r
-        Base = NoRangeLimit + 1;\r
-      }\r
-    } while (Base < Limit);\r
-    DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
-  );\r
-}\r
-\r
-\r
-/**\r
-  This function prints all MTRRs for debugging.\r
-**/\r
-VOID\r
-EFIAPI\r
-MtrrDebugPrintAllMtrrs (\r
-  VOID\r
-  )\r
-{\r
-  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
+  @retval RETURN_SUCCESS          The type of the specified memory range is\r
+                                  changed successfully.\r
+  @retval RETURN_ALREADY_STARTED  The type of the specified memory range equals\r
+                                  to the desired type.\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 MTRR_MEMORY_RANGE             *Ranges,\r
+  IN UINT                        Capacity,\r
+  IN OUT UINT                    *Count,\r
   IN UINT64                        BaseAddress,\r
   IN UINT64                        Length,\r
   IN MTRR_MEMORY_CACHE_TYPE        Type\r
   )\r
 {\r
-  UINT32                           Index;\r
+  UINT                           Index;\r
   UINT64                           Limit;\r
   UINT64                           LengthLeft;\r
   UINT64                           LengthRight;\r
-  UINT32                           StartIndex;\r
-  UINT32                           EndIndex;\r
-  UINT32                           DeltaCount;\r
+  UINT                           StartIndex;\r
+  UINT                           EndIndex;\r
+  UINT                           DeltaCount;\r
 \r
+  LengthRight = 0;\r
+  LengthLeft  = 0;\r
   Limit = BaseAddress + Length;\r
   StartIndex = *Count;\r
   EndIndex = *Count;\r
@@ -1459,7 +1029,7 @@ MtrrLibSetMemoryType (
 \r
   ASSERT (StartIndex != *Count && EndIndex != *Count);\r
   if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
-    return RETURN_SUCCESS;\r
+    return RETURN_ALREADY_STARTED;\r
   }\r
 \r
   //\r
@@ -1522,239 +1092,646 @@ MtrrLibSetMemoryType (
 }\r
 \r
 /**\r
-  Allocate one or more variable MTRR to cover the range identified by\r
-  BaseAddress and Length.\r
+  Return the number of memory types in range [BaseAddress, BaseAddress + 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
+  @param Ranges      Array holding memory type settings for all memory regions.\r
+  @param RangeCount  The count of memory ranges the array holds.\r
+  @param BaseAddress Base address.\r
+  @param Length      Length.\r
+  @param Types       Return bit mask to indicate all memory types in the specified range.\r
 \r
-  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
-  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+  @retval  Number of memory types.\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
+UINT8\r
+MtrrLibGetNumberOfTypes (\r
+  IN CONST MTRR_MEMORY_RANGE     *Ranges,\r
+  IN UINTN                       RangeCount,\r
+  IN UINT64                      BaseAddress,\r
+  IN UINT64                      Length,\r
+  IN OUT UINT8                   *Types  OPTIONAL\r
+  )\r
+{\r
+  UINTN                          Index;\r
+  UINT8                          TypeCount;\r
+  UINT8                          LocalTypes;\r
+\r
+  TypeCount = 0;\r
+  LocalTypes = 0;\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if ((Ranges[Index].BaseAddress <= BaseAddress) &&\r
+        (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)\r
+        ) {\r
+      if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {\r
+        LocalTypes |= (UINT8)(1 << Ranges[Index].Type);\r
+        TypeCount++;\r
+      }\r
+\r
+      if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+        Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
+        BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;\r
+      } else {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (Types != NULL) {\r
+    *Types = LocalTypes;\r
+  }\r
+  return TypeCount;\r
+}\r
 \r
 /**\r
-  Allocate one or more variable MTRR to cover the range identified by\r
-  BaseAddress and Length.\r
+  Calculate the least MTRR number from vector Start to Stop and update\r
+  the Previous of all vectors from Start to Stop is updated to reflect\r
+  how the memory range is covered by MTRR.\r
+\r
+  @param VectorCount     The count of vectors in the graph.\r
+  @param Vector          Array holding all vectors.\r
+  @param Weight          2-dimention array holding weights between vectors.\r
+  @param Start           Start vector.\r
+  @param Stop            Stop vector.\r
+  @param IncludeOptional TRUE to count the optional weight.\r
+**/\r
+VOID\r
+MtrrLibCalculateLeastMtrrs (\r
+  IN UINT16                      VectorCount,\r
+  IN MTRR_LIB_ADDRESS            *Vector,\r
+  IN OUT CONST UINT8             *Weight,\r
+  IN UINT16                      Start,\r
+  IN UINT16                      Stop,\r
+  IN BOOLEAN                     IncludeOptional\r
+  )\r
+{\r
+  UINT16                         Index;\r
+  UINT8                          MinWeight;\r
+  UINT16                         MinI;\r
+  UINT8                          Mandatory;\r
+  UINT8                          Optional;\r
+\r
+  for (Index = Start; Index <= Stop; Index++) {\r
+    Vector[Index].Visited = FALSE;\r
+    Vector[Index].Previous = VectorCount;\r
+    Mandatory = Weight[M(Start,Index)];\r
+    Vector[Index].Weight = Mandatory;\r
+    if (Mandatory != MAX_WEIGHT) {\r
+      Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;\r
+      Vector[Index].Weight += Optional;\r
+      ASSERT (Vector[Index].Weight >= Optional);\r
+    }\r
+  }\r
 \r
-  The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
-  to allocate variable MTRRs when the range contains several sub-ranges\r
-  with different attributes.\r
+  MinI = Start;\r
+  MinWeight = 0;\r
+  while (!Vector[Stop].Visited) {\r
+    //\r
+    // Update the weight from the shortest vector to other unvisited vectors\r
+    //\r
+    for (Index = Start + 1; Index <= Stop; Index++) {\r
+      if (!Vector[Index].Visited) {\r
+        Mandatory = Weight[M(MinI, Index)];\r
+        if (Mandatory != MAX_WEIGHT) {\r
+          Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;\r
+          if (MinWeight + Mandatory + Optional <= Vector[Index].Weight) {\r
+            Vector[Index].Weight   = MinWeight + Mandatory + Optional;\r
+            Vector[Index].Previous = MinI; // Previous is Start based.\r
+          }\r
+        }\r
+      }\r
+    }\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
+    // Find the shortest vector from Start\r
+    //\r
+    MinI      = VectorCount;\r
+    MinWeight = MAX_WEIGHT;\r
+    for (Index = Start + 1; Index <= Stop; Index++) {\r
+      if (!Vector[Index].Visited && MinWeight > Vector[Index].Weight) {\r
+        MinI      = Index;\r
+        MinWeight = Vector[Index].Weight;\r
+      }\r
+    }\r
 \r
-  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
-  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+    //\r
+    // Mark the shortest vector from Start as visited\r
+    //\r
+    Vector[MinI].Visited = TRUE;\r
+  }\r
+}\r
+\r
+/**\r
+  Append the MTRR setting to MTRR setting array.\r
+\r
+  @param Mtrrs        Array holding all MTRR settings.\r
+  @param MtrrCapacity Capacity of the MTRR array.\r
+  @param MtrrCount    The count of MTRR settings in array.\r
+  @param BaseAddress  Base address.\r
+  @param Length       Length.\r
+  @param Type         Memory type.\r
+\r
+  @retval RETURN_SUCCESS          MTRR setting is appended to array.\r
+  @retval RETURN_OUT_OF_RESOURCES Array is full.\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
+MtrrLibAppendVariableMtrr (\r
+  IN OUT MTRR_MEMORY_RANGE       *Mtrrs,\r
+  IN     UINT32                  MtrrCapacity,\r
+  IN OUT UINT32                  *MtrrCount,\r
+  IN     UINT64                  BaseAddress,\r
+  IN     UINT64                  Length,\r
+  IN     MTRR_MEMORY_CACHE_TYPE  Type\r
+  )\r
+{\r
+  if (*MtrrCount == MtrrCapacity) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Mtrrs[*MtrrCount].BaseAddress = BaseAddress;\r
+  Mtrrs[*MtrrCount].Length      = Length;\r
+  Mtrrs[*MtrrCount].Type        = Type;\r
+  (*MtrrCount)++;\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return the memory type that has the least precedence.\r
+\r
+  @param TypeBits  Bit mask of memory type.\r
+\r
+  @retval  Memory type that has the least precedence.\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrLibLowestType (\r
+  IN      UINT8                    TypeBits\r
 )\r
 {\r
-  RETURN_STATUS                    Status;\r
-  UINT32                           Index;\r
-  UINT64                           SubLength;\r
+  INT8                             Type;\r
 \r
-  MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
-  if (Type == CacheInvalid) {\r
-    for (Index = 0; Index < RangeCount; Index++) {\r
-      if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+  ASSERT (TypeBits != 0);\r
+  for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);\r
+  return (MTRR_MEMORY_CACHE_TYPE)Type;\r
+}\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
+  Return TRUE when the Operand is exactly power of 2.\r
+\r
+  @retval TRUE  Operand is exactly power of 2.\r
+  @retval FALSE Operand is not power of 2.\r
+**/\r
+BOOLEAN\r
+MtrrLibIsPowerOfTwo (\r
+  IN     UINT64                  Operand\r
+)\r
+{\r
+  ASSERT (Operand != 0);\r
+  return (BOOLEAN) ((Operand & (Operand - 1)) == 0);\r
+}\r
+\r
+/**\r
+  Calculate the subtractive path from vector Start to Stop.\r
+\r
+  @param DefaultType  Default memory type.\r
+  @param A0           Alignment to use when base address is 0.\r
+  @param Ranges       Array holding memory type settings for all memory regions.\r
+  @param RangeCount   The count of memory ranges the array holds.\r
+  @param VectorCount  The count of vectors in the graph.\r
+  @param Vector       Array holding all vectors.\r
+  @param Weight       2-dimention array holding weights between vectors.\r
+  @param Start        Start vector.\r
+  @param Stop         Stop vector.\r
+  @param Types        Type bit mask of memory range from Start to Stop.\r
+  @param TypeCount    Number of different memory types from Start to Stop.\r
+  @param Mtrrs        Array holding all MTRR settings.\r
+  @param MtrrCapacity Capacity of the MTRR array.\r
+  @param MtrrCount    The count of MTRR settings in array.\r
+\r
+  @retval RETURN_SUCCESS          The subtractive path is calculated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.\r
+\r
+**/\r
+RETURN_STATUS\r
+MtrrLibCalculateSubtractivePath (\r
+  IN MTRR_MEMORY_CACHE_TYPE      DefaultType,\r
+  IN UINT64                      A0,\r
+  IN CONST MTRR_MEMORY_RANGE     *Ranges,\r
+  IN UINTN                       RangeCount,\r
+  IN UINT16                      VectorCount,\r
+  IN MTRR_LIB_ADDRESS            *Vector,\r
+  IN OUT UINT8                   *Weight,\r
+  IN UINT16                      Start,\r
+  IN UINT16                      Stop,\r
+  IN UINT8                       Types,\r
+  IN UINT8                       TypeCount,\r
+  IN OUT MTRR_MEMORY_RANGE       *Mtrrs,       OPTIONAL\r
+  IN UINT32                      MtrrCapacity, OPTIONAL\r
+  IN OUT UINT32                  *MtrrCount    OPTIONAL\r
+  )\r
+{\r
+  RETURN_STATUS                  Status;\r
+  UINT64                         Base;\r
+  UINT64                         Length;\r
+  UINT8                          PrecedentTypes;\r
+  UINTN                          Index;\r
+  UINT64                         HBase;\r
+  UINT64                         HLength;\r
+  UINT64                         SubLength;\r
+  UINT16                         SubStart;\r
+  UINT16                         SubStop;\r
+  UINT16                         Cur;\r
+  UINT16                         Pre;\r
+  MTRR_MEMORY_CACHE_TYPE         LowestType;\r
+  MTRR_MEMORY_CACHE_TYPE         LowestPrecedentType;\r
+\r
+  Base   = Vector[Start].Address;\r
+  Length = Vector[Stop].Address - Base;\r
+\r
+  LowestType = MtrrLibLowestType (Types);\r
+\r
+  //\r
+  // Clear the lowest type (highest bit) to get the precedent types\r
+  //\r
+  PrecedentTypes = ~(1 << LowestType) & Types;\r
+  LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);\r
+\r
+  if (Mtrrs == NULL) {\r
+    Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);\r
+    Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);\r
+  }\r
+\r
+  // Add all high level ranges\r
+  HBase = MAX_UINT64;\r
+  HLength = 0;\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if (Length == 0) {\r
+      break;\r
+    }\r
+    if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {\r
+      continue;\r
     }\r
 \r
     //\r
-    // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
+    // Base is in the Range[Index]\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
+    if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+      SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;\r
+    } else {\r
+      SubLength = Length;\r
+    }\r
+    if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {\r
+      //\r
+      // Meet a range whose types take precedence.\r
+      // Update the [HBase, HBase + HLength) to include the range,\r
+      // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.\r
+      //\r
+      if (HBase == MAX_UINT64) {\r
+        HBase = Base;\r
       }\r
+      HLength += SubLength;\r
     }\r
-    if (Index == *VariableMtrrCount) {\r
-      if (*VariableMtrrCount == VariableMtrrCapacity) {\r
-        return RETURN_OUT_OF_RESOURCES;\r
+\r
+    Base += SubLength;\r
+    Length -= SubLength;\r
+\r
+    if (HLength == 0) {\r
+      continue;\r
+    }\r
+\r
+    if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end\r
+\r
+      //\r
+      // Add the MTRRs for each high priority type range\r
+      // the range[HBase, HBase + HLength) contains only two types.\r
+      // We might use positive or subtractive, depending on which way uses less MTRR\r
+      //\r
+      for (SubStart = Start; SubStart <= Stop; SubStart++) {\r
+        if (Vector[SubStart].Address == HBase) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      for (SubStop = SubStart; SubStop <= Stop; SubStop++) {\r
+        if (Vector[SubStop].Address == HBase + HLength) {\r
+          break;\r
+        }\r
+      }\r
+      ASSERT (Vector[SubStart].Address == HBase);\r
+      ASSERT (Vector[SubStop].Address == HBase + HLength);\r
+\r
+      if ((TypeCount == 2) || (SubStart == SubStop - 1)) {\r
+        //\r
+        // add subtractive MTRRs for [HBase, HBase + HLength)\r
+        // [HBase, HBase + HLength) contains only one type.\r
+        // while - loop is to split the range to MTRR - compliant aligned range.\r
+        //\r
+        if (Mtrrs == NULL) {\r
+          Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);\r
+        } else {\r
+          while (SubStart != SubStop) {\r
+            Status = MtrrLibAppendVariableMtrr (\r
+              Mtrrs, MtrrCapacity, MtrrCount,\r
+              Vector[SubStart].Address, Vector[SubStart].Length, (MTRR_MEMORY_CACHE_TYPE) Vector[SubStart].Type\r
+            );\r
+            if (RETURN_ERROR (Status)) {\r
+              return Status;\r
+            }\r
+            SubStart++;\r
+          }\r
+        }\r
+      } else {\r
+        ASSERT (TypeCount == 3);\r
+        MtrrLibCalculateLeastMtrrs (VectorCount, Vector, Weight, SubStart, SubStop, TRUE);\r
+\r
+        if (Mtrrs == NULL) {\r
+          Weight[M (Start, Stop)] += Vector[SubStop].Weight;\r
+        } else {\r
+          // When we need to collect the optimal path from SubStart to SubStop\r
+          while (SubStop != SubStart) {\r
+            Cur = SubStop;\r
+            Pre = Vector[Cur].Previous;\r
+            SubStop = Pre;\r
+\r
+            if (Weight[M (Pre, Cur)] != 0) {\r
+              Status = MtrrLibAppendVariableMtrr (\r
+                Mtrrs, MtrrCapacity, MtrrCount,\r
+                Vector[Pre].Address, Vector[Cur].Address - Vector[Pre].Address, LowestPrecedentType\r
+              );\r
+              if (RETURN_ERROR (Status)) {\r
+                return Status;\r
+              }\r
+            }\r
+            if (Pre != Cur - 1) {\r
+              Status = MtrrLibCalculateSubtractivePath (\r
+                DefaultType, A0,\r
+                Ranges, RangeCount,\r
+                VectorCount, Vector, Weight,\r
+                Pre, Cur, PrecedentTypes, 2,\r
+                Mtrrs, MtrrCapacity, MtrrCount\r
+              );\r
+              if (RETURN_ERROR (Status)) {\r
+                return Status;\r
+              }\r
+            }\r
+          }\r
+        }\r
+\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
+      // Reset HBase, HLength\r
+      //\r
+      HBase = MAX_UINT64;\r
+      HLength = 0;\r
     }\r
-    return RETURN_SUCCESS;\r
   }\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
+  Calculate MTRR settings to cover the specified memory ranges.\r
+\r
+  @param DefaultType  Default memory type.\r
+  @param A0           Alignment to use when base address is 0.\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 Scratch      A temporary scratch buffer that is used to perform the calculation.\r
+                      This is an optional parameter that may be NULL.\r
+  @param ScratchSize  Pointer to the size in bytes of the scratch buffer.\r
+                      It may be updated to the actual required size when the calculation\r
+                      needs more scratch buffer.\r
+  @param Mtrrs        Array holding all MTRR settings.\r
+  @param MtrrCapacity Capacity of the MTRR array.\r
+  @param MtrrCount    The count of MTRR settings in array.\r
 \r
   @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
   @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+  @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\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
+MtrrLibCalculateMtrrs (\r
+  IN MTRR_MEMORY_CACHE_TYPE  DefaultType,\r
+  IN UINT64                  A0,\r
+  IN CONST MTRR_MEMORY_RANGE *Ranges,\r
+  IN UINTN                   RangeCount,\r
+  IN VOID                    *Scratch,\r
+  IN OUT UINTN               *ScratchSize,\r
+  IN OUT MTRR_MEMORY_RANGE   *Mtrrs,\r
+  IN UINT32                  MtrrCapacity,\r
+  IN OUT UINT32              *MtrrCount\r
+  )\r
 {\r
+  UINT64                    Base0;\r
+  UINT64                    Base1;\r
+  UINTN                     Index;\r
+  UINT64                    Base;\r
+  UINT64                    Length;\r
   UINT64                    Alignment;\r
-  UINT32                    MtrrNumber;\r
-  UINT32                    SubtractiveLeft;\r
-  UINT32                    SubtractiveRight;\r
-  BOOLEAN                   UseLeastAlignment;\r
+  UINT64                    SubLength;\r
+  MTRR_LIB_ADDRESS          *Vector;\r
+  UINT8                     *Weight;\r
+  UINT32                    VectorIndex;\r
+  UINT32                    VectorCount;\r
+  UINTN                     RequiredScratchSize;\r
+  UINT8                     TypeCount;\r
+  UINT16                    Start;\r
+  UINT16                    Stop;\r
+  UINT8                     Type;\r
+  RETURN_STATUS             Status;\r
 \r
-  MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
-                                     BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
+  Base0 = Ranges[0].BaseAddress;\r
+  Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;\r
+  MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);\r
 \r
-  if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
-    return RETURN_OUT_OF_RESOURCES;\r
+  //\r
+  // Count the number of vectors.\r
+  //\r
+  Vector = (MTRR_LIB_ADDRESS*)Scratch;\r
+  for (VectorIndex = 0, Index = 0; Index < RangeCount; Index++) {\r
+    Base = Ranges[Index].BaseAddress;\r
+    Length = Ranges[Index].Length;\r
+    while (Length != 0) {\r
+      Alignment = MtrrLibBiggestAlignment (Base, A0);\r
+      SubLength = Alignment;\r
+      if (SubLength > Length) {\r
+        SubLength = GetPowerOfTwo64 (Length);\r
+      }\r
+      if (VectorIndex < *ScratchSize / sizeof (*Vector)) {\r
+        Vector[VectorIndex].Address   = Base;\r
+        Vector[VectorIndex].Alignment = Alignment;\r
+        Vector[VectorIndex].Type      = Ranges[Index].Type;\r
+        Vector[VectorIndex].Length    = SubLength;\r
+      }\r
+      Base   += SubLength;\r
+      Length -= SubLength;\r
+      VectorIndex++;\r
+    }\r
   }\r
+  //\r
+  // Vector[VectorIndex] = Base1, so whole vector count is (VectorIndex + 1).\r
+  //\r
+  VectorCount = VectorIndex + 1;\r
+  DEBUG ((\r
+    DEBUG_CACHE, "VectorCount (%016lx - %016lx) = %d\n", \r
+    Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VectorCount\r
+    ));\r
+  ASSERT (VectorCount < MAX_UINT16);\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
+  RequiredScratchSize = VectorCount * sizeof (*Vector) + VectorCount * VectorCount * sizeof (*Weight);\r
+  if (*ScratchSize < RequiredScratchSize) {\r
+    *ScratchSize = RequiredScratchSize;\r
+    return RETURN_BUFFER_TOO_SMALL;\r
   }\r
+  Vector[VectorCount - 1].Address = Base1;\r
 \r
-  while (Length != 0) {\r
-    Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
-    if (Alignment > Length) {\r
-      break;\r
+  Weight = (UINT8 *) &Vector[VectorCount];\r
+  //\r
+  // Set mandatory weight between any vector to max\r
+  // Set optional weight and between any vector and self->self to 0\r
+  // E.g.:\r
+  //   00 FF FF FF\r
+  //   00 00 FF FF\r
+  //   00 00 00 FF\r
+  //   00 00 00 00\r
+  //\r
+  for (VectorIndex = 0; VectorIndex < VectorCount; VectorIndex++) {\r
+    SetMem (&Weight[M(VectorIndex, 0)], VectorIndex + 1, 0);\r
+    if (VectorIndex != VectorCount - 1) {\r
+      Weight[M (VectorIndex, VectorIndex + 1)] = (DefaultType == Vector[VectorIndex].Type) ? 0 : 1;\r
+      SetMem (&Weight[M (VectorIndex, VectorIndex + 2)], VectorCount - VectorIndex - 2, MAX_WEIGHT);\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
+  for (TypeCount = 2; TypeCount <= 3; TypeCount++) {\r
+    for (Start = 0; Start < VectorCount; Start++) {\r
+      for (Stop = Start + 2; Stop < VectorCount; Stop++) {\r
+        ASSERT (Vector[Stop].Address > Vector[Start].Address);\r
+        Length = Vector[Stop].Address - Vector[Start].Address;\r
+        if (Length > Vector[Start].Alignment) {\r
+          //\r
+          // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.\r
+          //\r
+          break;\r
+        }\r
+        if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {\r
+          if (MtrrLibGetNumberOfTypes (\r
+                Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type\r
+                ) == TypeCount) {\r
+            //\r
+            // Update the Weight[Start, Stop] using subtractive path.\r
+            //\r
+            MtrrLibCalculateSubtractivePath (\r
+              DefaultType, A0,\r
+              Ranges, RangeCount,\r
+              (UINT16)VectorCount, Vector, Weight,\r
+              Start, Stop, Type, TypeCount,\r
+              NULL, 0, NULL\r
+              );\r
+          } else if (TypeCount == 2) {\r
+            //\r
+            // Pick up a new Start when we expect 2-type range, but 3-type range is met.\r
+            // Because no matter how Stop is increased, we always meet 3-type range.\r
+            //\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\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
+  Status = RETURN_SUCCESS;\r
+  MtrrLibCalculateLeastMtrrs ((UINT16) VectorCount, Vector, Weight, 0, (UINT16) VectorCount - 1, FALSE);\r
+  Stop = (UINT16) VectorCount - 1;\r
+  while (Stop != 0) {\r
+    Start = Vector[Stop].Previous;\r
+    TypeCount = MAX_UINT8;\r
+    Type = 0;\r
+    if (Weight[M(Start, Stop)] != 0) {\r
+      TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type);\r
+      Status = MtrrLibAppendVariableMtrr (\r
+        Mtrrs, MtrrCapacity, MtrrCount,\r
+        Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, \r
+        MtrrLibLowestType (Type)\r
+        );\r
+      if (RETURN_ERROR (Status)) {\r
+        break;\r
       }\r
     }\r
 \r
-    if (!UseLeastAlignment) {\r
-      Alignment = GetPowerOfTwo64 (Length);\r
+    if (Start != Stop - 1) {\r
+      //\r
+      // substractive path\r
+      //\r
+      if (TypeCount == MAX_UINT8) {\r
+        TypeCount = MtrrLibGetNumberOfTypes (\r
+                      Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type\r
+                      );\r
+      }\r
+      Status = MtrrLibCalculateSubtractivePath (\r
+                 DefaultType, A0,\r
+                 Ranges, RangeCount,\r
+                 (UINT16) VectorCount, Vector, Weight, Start, Stop,\r
+                 Type, TypeCount,\r
+                 Mtrrs, MtrrCapacity, MtrrCount\r
+                 );\r
+      if (RETURN_ERROR (Status)) {\r
+        break;\r
+      }\r
     }\r
+    Stop = Start;\r
+  }\r
+  return Status;\r
+}\r
 \r
-    MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
-                            BaseAddress, Alignment, Type, Alignment0);\r
-    BaseAddress += Alignment;\r
-    Length -= Alignment;\r
+\r
+/**\r
+  Apply the variable MTRR settings to memory range array.\r
+\r
+  @param Fixed             The fixed MTRR settings.\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
+MtrrLibApplyFixedMtrrs (\r
+  IN     MTRR_FIXED_SETTINGS  *Fixed,\r
+  IN OUT MTRR_MEMORY_RANGE    *Ranges,\r
+  IN     UINTN                RangeCapacity,\r
+  IN OUT UINTN                *RangeCount\r
+  )\r
+{\r
+  RETURN_STATUS               Status;\r
+  UINTN                       MsrIndex;\r
+  UINTN                       Index;\r
+  MTRR_MEMORY_CACHE_TYPE      MemoryType;\r
+  UINT64                      Base;\r
+\r
+  Base = 0;\r
+  for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
+    ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);\r
+    for (Index = 0; Index < sizeof (UINT64); Index++) {\r
+      MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];\r
+      Status = MtrrLibSetMemoryType (\r
+                 Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType\r
+                 );\r
+      if (Status == RETURN_OUT_OF_RESOURCES) {\r
+        return Status;\r
+      }\r
+      Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
+    }\r
   }\r
+  ASSERT (Base == BASE_1MB);\r
   return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
-  Return an array of memory ranges holding memory type settings for all memory\r
-  address.\r
+  Apply the variable MTRR settings to memory range array.\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 Ranges            Return the memory range array with new MTRR settings applied.\r
   @param RangeCapacity     The capacity of memory range array.\r
   @param RangeCount        Return the count of memory range.\r
 \r
@@ -1762,15 +1739,13 @@ MtrrLibSetMemoryAttributeInVariableMtrr (
   @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
+MtrrLibApplyVariableMtrrs (\r
+  IN     CONST MTRR_MEMORY_RANGE *VariableMtrr,\r
+  IN     UINT32                  VariableMtrrCount,\r
+  IN OUT MTRR_MEMORY_RANGE       *Ranges,\r
+  IN     UINTN                   RangeCapacity,\r
+  IN OUT UINTN                   *RangeCount\r
+  )\r
 {\r
   RETURN_STATUS                  Status;\r
   UINTN                          Index;\r
@@ -1781,24 +1756,16 @@ MtrrLibGetMemoryTypes (
   // 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
+    if ((VariableMtrr[Index].Length != 0) && (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
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
       );\r
-      if (RETURN_ERROR (Status)) {\r
+      if (Status == RETURN_OUT_OF_RESOURCES) {\r
         return Status;\r
       }\r
     }\r
@@ -1808,12 +1775,13 @@ MtrrLibGetMemoryTypes (
   // 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
+    if ((VariableMtrr[Index].Length != 0) && \r
+        (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
+                 Ranges, RangeCapacity, RangeCount,\r
+                 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
+                 );\r
+      if (Status == RETURN_OUT_OF_RESOURCES) {\r
         return Status;\r
       }\r
     }\r
@@ -1823,12 +1791,12 @@ MtrrLibGetMemoryTypes (
   // 3. Set UC\r
   //\r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
+    if (VariableMtrr[Index].Length != 0 && 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
+                 Ranges, RangeCapacity, RangeCount,\r
+                 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
+                 );\r
+      if (Status == RETURN_OUT_OF_RESOURCES) {\r
         return Status;\r
       }\r
     }\r
@@ -1837,388 +1805,643 @@ MtrrLibGetMemoryTypes (
 }\r
 \r
 /**\r
-  Worker function attempts to set the attributes for a memory range.\r
+  Return the memory type bit mask that's compatible to first type in the Ranges.\r
 \r
-  If MtrrSetting is not NULL, set the attributes into the input MTRR\r
-  settings buffer.\r
-  If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
+  @param Ranges     Memory range array holding the memory type\r
+                    settings for all memory address.\r
+  @param RangeCount Count of memory ranges.\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 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
+  @return Compatible memory type bit mask.\r
+**/\r
+UINT8\r
+MtrrLibGetCompatibleTypes (\r
+  IN CONST MTRR_MEMORY_RANGE *Ranges,\r
+  IN UINTN                   RangeCount\r
+  )\r
+{\r
+  ASSERT (RangeCount != 0);\r
 \r
-  @retval RETURN_SUCCESS            The attributes were set for the memory\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 MTRR type is not support for the\r
-                                    memory resource range specified\r
-                                    by BaseAddress and Length.\r
-  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
-                                    modify the attributes of the memory\r
-                                    resource range.\r
+  switch (Ranges[0].Type) {\r
+  case CacheWriteBack:\r
+  case CacheWriteThrough:\r
+    return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);\r
+    break;\r
+\r
+  case CacheWriteCombining:\r
+  case CacheWriteProtected:\r
+    return (1 << Ranges[0].Type) | (1 << CacheUncacheable);\r
+    break;\r
+\r
+  case CacheUncacheable:\r
+    if (RangeCount == 1) {\r
+      return (1 << CacheUncacheable);\r
+    }\r
+    return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);\r
+    break;\r
+\r
+  case CacheInvalid:\r
+  default:\r
+    ASSERT (FALSE);\r
+    break;\r
+  }\r
+  return 0;\r
+}\r
 \r
+/**\r
+  Overwrite the destination MTRR settings with the source MTRR settings.\r
+  This routine is to make sure the modification to destination MTRR settings\r
+  is as small as possible.\r
+\r
+  @param DstMtrrs     Destination MTRR settings.\r
+  @param DstMtrrCount Count of destination MTRR settings.\r
+  @param SrcMtrrs     Source MTRR settings.\r
+  @param SrcMtrrCount Count of source MTRR settings.\r
+  @param Modified     Flag array to indicate which destination MTRR setting is modified.\r
 **/\r
-RETURN_STATUS\r
-MtrrSetMemoryAttributeWorker (\r
-  IN OUT MTRR_SETTINGS           *MtrrSetting,\r
-  IN PHYSICAL_ADDRESS            BaseAddress,\r
-  IN UINT64                      Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE      Type\r
+VOID\r
+MtrrLibMergeVariableMtrr (\r
+  MTRR_MEMORY_RANGE *DstMtrrs,\r
+  UINT32            DstMtrrCount,\r
+  MTRR_MEMORY_RANGE *SrcMtrrs,\r
+  UINT32            SrcMtrrCount,\r
+  BOOLEAN           *Modified\r
   )\r
 {\r
-  RETURN_STATUS             Status;\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
-  UINT64                    Alignment0;\r
-  MTRR_CONTEXT              MtrrContext;\r
-  BOOLEAN                   MtrrContextValid;\r
+  UINT32          DstIndex;\r
+  UINT32          SrcIndex;\r
 \r
-  MTRR_MEMORY_CACHE_TYPE    DefaultType;\r
+  ASSERT (SrcMtrrCount <= DstMtrrCount);\r
 \r
-  UINT32                    MsrIndex;\r
-  UINT64                    ClearMask;\r
-  UINT64                    OrMask;\r
-  UINT64                    NewValue;\r
-  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
-  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
-  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
+  for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {\r
+    Modified[DstIndex] = FALSE;\r
 \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
+    if (DstMtrrs[DstIndex].Length == 0) {\r
+      continue;\r
+    }\r
+    for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
+      if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&\r
+        DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&\r
+        DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {\r
+        break;\r
+      }\r
+    }\r
 \r
-  if (Length == 0) {\r
-    return RETURN_INVALID_PARAMETER;\r
+    if (SrcIndex == SrcMtrrCount) {\r
+      //\r
+      // Remove the one from DstMtrrs which is not in SrcMtrrs\r
+      //\r
+      DstMtrrs[DstIndex].Length = 0;\r
+      Modified[DstIndex] = TRUE;\r
+    } else {\r
+      //\r
+      // Remove the one from SrcMtrrs which is also in DstMtrrs\r
+      //\r
+      SrcMtrrs[SrcIndex].Length = 0;\r
+    }\r
   }\r
 \r
-  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
-  if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
+  //\r
+  // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.\r
+  // Merge MTRRs from SrcMtrrs to DstMtrrs\r
+  //\r
+  DstIndex = 0;\r
+  for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
+    if (SrcMtrrs[SrcIndex].Length != 0) {\r
 \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
+      // Find the empty slot in DstMtrrs\r
+      //\r
+      while (DstIndex < DstMtrrCount) {\r
+        if (DstMtrrs[DstIndex].Length == 0) {\r
+          break;\r
+        }\r
+        DstIndex++;\r
+      }\r
+      ASSERT (DstIndex < DstMtrrCount);\r
+      CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));\r
+      Modified[DstIndex] = TRUE;\r
+    }\r
   }\r
+}\r
+\r
+/**\r
+  Calculate the variable MTRR settings for all memory ranges.\r
+\r
+  @param DefaultType          Default memory type.\r
+  @param A0                   Alignment to use when base address is 0.\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 Scratch              Scratch buffer to be used in MTRR calculation.\r
+  @param ScratchSize          Pointer to the size of scratch buffer.\r
+  @param VariableMtrr         Array holding all MTRR settings.\r
+  @param VariableMtrrCapacity Capacity of the MTRR array.\r
+  @param VariableMtrrCount    The count of MTRR settings in array.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+  @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
+                                  The required scratch buffer size is returned through ScratchSize.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryRanges (\r
+  IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+  IN UINT64                 A0,\r
+  IN MTRR_MEMORY_RANGE      *Ranges,\r
+  IN UINTN                  RangeCount,\r
+  IN VOID                   *Scratch,\r
+  IN OUT UINTN              *ScratchSize,\r
+  OUT MTRR_MEMORY_RANGE     *VariableMtrr,\r
+  IN UINT32                 VariableMtrrCapacity,\r
+  OUT UINT32                *VariableMtrrCount\r
+  )\r
+{\r
+  RETURN_STATUS             Status;\r
+  UINT32                    Index;\r
+  UINT64                    Base0;\r
+  UINT64                    Base1;\r
+  UINT64                    Alignment;\r
+  UINT8                     CompatibleTypes;\r
+  UINT64                    Length;\r
+  UINT32                    End;\r
+  UINTN                     ActualScratchSize;\r
+  UINTN                     BiggestScratchSize;\r
 \r
+  *VariableMtrrCount = 0;\r
+  \r
   //\r
-  // Check if Fixed MTRR\r
+  // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().\r
+  // Each call needs different scratch buffer size.\r
+  // When the provided scratch buffer size is not sufficient in any call,\r
+  // set the GetActualScratchSize to TRUE, and following calls will only\r
+  // calculate the actual scratch size for the caller.\r
   //\r
-  if (BaseAddress < BASE_1MB) {\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
-        return Status;\r
+  BiggestScratchSize = 0;\r
+\r
+  for (Index = 0; Index < RangeCount;) {\r
+    Base0 = Ranges[Index].BaseAddress;\r
+\r
+    //\r
+    // Full step is optimal\r
+    //\r
+    while (Index < RangeCount) {\r
+      ASSERT (Ranges[Index].BaseAddress == Base0);\r
+      Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
+      while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+        if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {\r
+          Status = MtrrLibAppendVariableMtrr (\r
+            VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+            Base0, Alignment, Ranges[Index].Type\r
+            );\r
+          if (RETURN_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+        }\r
+        Base0 += Alignment;\r
+        Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
       }\r
-      if (MtrrSetting != NULL) {\r
-        MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
-        ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
+\r
+      //\r
+      // Remove the above range from Ranges[Index]\r
+      //\r
+      Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;\r
+      Ranges[Index].BaseAddress = Base0;\r
+      if (Ranges[Index].Length != 0) {\r
+        break;\r
       } else {\r
-        if (!FixedSettingsValid[MsrIndex]) {\r
-          WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);\r
-          FixedSettingsValid[MsrIndex] = TRUE;\r
-        }\r
-        NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
-        if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {\r
-          WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;\r
-          FixedSettingsModified[MsrIndex] = TRUE;\r
-        }\r
+        Index++;\r
       }\r
     }\r
 \r
-    if (Length == 0) {\r
+    if (Index == RangeCount) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Find continous ranges [Base0, Base1) which could be combined by MTRR.\r
+    // Per SDM, the compatible types between[B0, B1) are:\r
+    //   UC, *\r
+    //   WB, WT\r
+    //   UC, WB, WT\r
+    //\r
+    CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);\r
+\r
+    End = Index; // End points to last one that matches the CompatibleTypes.\r
+    while (End + 1 < RangeCount) {\r
+      if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {\r
+        break;\r
+      }\r
+      End++;\r
+    }\r
+    Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
+    Length    = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);\r
+    Base1     = Base0 + MIN (Alignment, Length);\r
+\r
+    //\r
+    // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.\r
+    //\r
+    End = Index;\r
+    while (End + 1 < RangeCount) {\r
+      if (Base1 <= Ranges[End + 1].BaseAddress) {\r
+        break;\r
+      }\r
+      End++;\r
+    }\r
+\r
+    Length = Ranges[End].Length;\r
+    Ranges[End].Length = Base1 - Ranges[End].BaseAddress;\r
+    ActualScratchSize  = *ScratchSize;\r
+    Status = MtrrLibCalculateMtrrs (\r
+               DefaultType, A0,\r
+               &Ranges[Index], End + 1 - Index,\r
+               Scratch, &ActualScratchSize,\r
+               VariableMtrr, VariableMtrrCapacity, VariableMtrrCount\r
+               );\r
+    if (Status == RETURN_BUFFER_TOO_SMALL) {\r
+      BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);\r
       //\r
-      // A Length of 0 can only make sense for fixed MTTR ranges.\r
-      // Since we just handled the fixed MTRRs, we can skip the\r
-      // variable MTRR section.\r
+      // Ignore this error, because we need to calculate the biggest\r
+      // scratch buffer size.\r
       //\r
-      goto Done;\r
+      Status = RETURN_SUCCESS;\r
+    }\r
+    if (RETURN_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (Length != Ranges[End].Length) {\r
+      Ranges[End].BaseAddress = Base1;\r
+      Ranges[End].Length = Length - Ranges[End].Length;\r
+      Index = End;\r
+    } else {\r
+      Index = End + 1;\r
     }\r
   }\r
 \r
-  //\r
-  // Read the default MTRR type\r
-  //\r
-  DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
+  if (*ScratchSize < BiggestScratchSize) {\r
+    *ScratchSize = BiggestScratchSize;\r
+    return RETURN_BUFFER_TOO_SMALL;\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the below-1MB memory attribute to fixed MTRR buffer.\r
+  Modified flag array indicates which fixed MTRR is modified.\r
+\r
+  @param [in, out] FixedSettings Fixed MTRR buffer.\r
+  @param [out]     Modified      Flag array indicating which MTRR is modified.\r
+  @param [in]      BaseAddress   Base address.\r
+  @param [in]      Length        Length.\r
+  @param [in]      Type          Memory type.\r
+\r
+  @retval RETURN_SUCCESS      The memory attribute is set successfully.\r
+  @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
+                              for the fixed MTRRs.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetBelow1MBMemoryAttribute (\r
+  IN OUT MTRR_FIXED_SETTINGS     *FixedSettings,\r
+  OUT BOOLEAN                    *Modified,\r
+  IN PHYSICAL_ADDRESS            BaseAddress,\r
+  IN UINT64                      Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE      Type\r
+  )\r
+{\r
+  RETURN_STATUS             Status;\r
+  UINT32                    MsrIndex;\r
+  UINT64                    ClearMask;\r
+  UINT64                    OrMask;\r
+  UINT64                    ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
+  UINT64                    OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
+  BOOLEAN                   LocalModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
+\r
+  ASSERT (BaseAddress < BASE_1MB);\r
+\r
+  SetMem (LocalModified, sizeof (LocalModified), FALSE);\r
 \r
   //\r
-  // Read all variable MTRRs and convert to Ranges.\r
+  // (Value & ~0 | 0) still equals to (Value)\r
   //\r
-  OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
-  if (MtrrSetting == NULL) {\r
-    ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));\r
-    MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);\r
-    VariableSettings = &OriginalVariableSettings;\r
-  } else {\r
-    VariableSettings = &MtrrSetting->Variables;\r
+  SetMem64 (ClearMasks, sizeof (ClearMasks), 0);\r
+  SetMem64 (OrMasks, sizeof (OrMasks), 0);\r
+\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
+      return Status;\r
+    }\r
+    ClearMasks[MsrIndex]    = ClearMask;\r
+    OrMasks[MsrIndex]       = OrMask;\r
+    Modified[MsrIndex]      = TRUE;\r
+    LocalModified[MsrIndex] = TRUE;\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
+  for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
+    if (LocalModified[MsrIndex]) {\r
+      FixedSettings->Mtrr[MsrIndex] = (FixedSettings->Mtrr[MsrIndex] & ~ClearMasks[MsrIndex]) | OrMasks[MsrIndex];\r
+    }\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.\r
+\r
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
+  @param[in]       Scratch      A temporary scratch buffer that is used to perform the calculation.\r
+  @param[in, out]  ScratchSize  Pointer to the size in bytes of the scratch buffer.\r
+                                It may be updated to the actual required size when the calculation\r
+                                needs more scratch buffer.\r
+  @param[in]       Ranges       Pointer to an array of MTRR_MEMORY_RANGE.\r
+                                When range overlap happens, the last one takes higher priority.\r
+                                When the function returns, either all the attributes are set successfully,\r
+                                or none of them is set.\r
+  @param[in]                    Count of MTRR_MEMORY_RANGE.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for all the memory ranges.\r
+  @retval RETURN_INVALID_PARAMETER  Length in any range 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 in any range.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource\r
+                                    range specified by BaseAddress and Length in any range.\r
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of\r
+                                    the memory resource ranges.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by\r
+                                    BaseAddress and Length cannot be modified.\r
+  @retval RETURN_BUFFER_TOO_SMALL   The scratch buffer is too small for MTRR calculation.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttributesInMtrrSettings (\r
+  IN OUT MTRR_SETTINGS           *MtrrSetting,\r
+  IN     VOID                    *Scratch,\r
+  IN OUT UINTN                   *ScratchSize,\r
+  IN     CONST MTRR_MEMORY_RANGE *Ranges,\r
+  IN     UINTN                   RangeCount\r
+  )\r
+{\r
+  RETURN_STATUS             Status;\r
+  UINT32                    Index;\r
+  UINT64                    BaseAddress;\r
+  UINT64                    Length;\r
+  BOOLEAN                   Above1MbExist;\r
+\r
+  UINT64                    MtrrValidBitsMask;\r
+  UINT64                    MtrrValidAddressMask;\r
+  MTRR_MEMORY_CACHE_TYPE    DefaultType;\r
+  MTRR_VARIABLE_SETTINGS    VariableSettings;\r
+  MTRR_MEMORY_RANGE         WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];\r
+  UINTN                     WorkingRangeCount;\r
+  BOOLEAN                   Modified;\r
+  MTRR_VARIABLE_SETTING     VariableSetting;\r
+  UINT32                    OriginalVariableMtrrCount;\r
+  UINT32                    FirmwareVariableMtrrCount;\r
+  UINT32                    WorkingVariableMtrrCount;\r
+  MTRR_MEMORY_RANGE         OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
+  MTRR_MEMORY_RANGE         WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
+  BOOLEAN                   VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
+\r
+  BOOLEAN                   FixedSettingsModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
+\r
+  MTRR_CONTEXT              MtrrContext;\r
+  BOOLEAN                   MtrrContextValid;\r
 \r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
-  ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
 \r
   //\r
-  // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
+  // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.\r
   //\r
-  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
-  ASSERT (Status == RETURN_SUCCESS);\r
+  SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);\r
   //\r
-  // Apply Type to [BaseAddress, BaseAddress + Length)\r
+  // TRUE indicating the accordingly Fixed setting needs modification in WorkingFixedSettings.\r
   //\r
-  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
-  if (RETURN_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  SetMem (FixedSettingsModified, ARRAY_SIZE (FixedSettingsModified), FALSE);\r
+\r
+  //\r
+  // TRUE indicating the caller requests to set variable MTRRs.\r
+  //\r
+  Above1MbExist             = FALSE;\r
+  OriginalVariableMtrrCount = 0;\r
 \r
-  Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
-  WorkingVariableMtrrCount = 0;\r
-  ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
+  //\r
+  // 1. Validate the parameters.\r
+  //\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
+    if (Ranges[Index].Length == 0) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+    if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||\r
+        ((Ranges[Index].Length & ~MtrrValidAddressMask) != 0)\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+    if ((Ranges[Index].Type != CacheUncacheable) &&\r
+        (Ranges[Index].Type != CacheWriteCombining) &&\r
+        (Ranges[Index].Type != CacheWriteThrough) &&\r
+        (Ranges[Index].Type != CacheWriteProtected) &&\r
+        (Ranges[Index].Type != CacheWriteBack)) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+    if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {\r
+      Above1MbExist = TRUE;\r
     }\r
   }\r
 \r
   //\r
-  // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
+  // 2. Apply the above-1MB memory attribute settings.\r
   //\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
+  if (Above1MbExist) {\r
+    //\r
+    // 2.1. Read all variable MTRRs and convert to Ranges.\r
+    //\r
+    OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
+    MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);\r
+    MtrrLibGetRawVariableRanges (\r
+      &VariableSettings, OriginalVariableMtrrCount,\r
+      MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr\r
+      );\r
 \r
-  if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
-    return RETURN_OUT_OF_RESOURCES;\r
-  }\r
+    DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
+    WorkingRangeCount = 1;\r
+    WorkingRanges[0].BaseAddress = 0;\r
+    WorkingRanges[0].Length      = MtrrValidBitsMask + 1;\r
+    WorkingRanges[0].Type        = DefaultType;\r
 \r
-  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
-    VariableSettingModified[Index] = FALSE;\r
+    Status = MtrrLibApplyVariableMtrrs (\r
+               OriginalVariableMtrr, OriginalVariableMtrrCount,\r
+               WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);\r
+    ASSERT_RETURN_ERROR (Status);\r
 \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
+    ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));\r
+    FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
+    ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
 \r
-    if (WorkingIndex == WorkingVariableMtrrCount) {\r
-      //\r
-      // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr\r
-      //\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
+    // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.\r
     //\r
-  }\r
+    Status = MtrrLibSetMemoryType (\r
+               WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
+               0, SIZE_1MB, CacheUncacheable\r
+               );\r
+    ASSERT (Status != RETURN_OUT_OF_RESOURCES);\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
+    // 2.3. Apply the new memory attribute settings to Ranges.\r
+    //\r
+    Modified = FALSE;\r
+    for (Index = 0; Index < RangeCount; Index++) {\r
+      BaseAddress = Ranges[Index].BaseAddress;\r
+      Length = Ranges[Index].Length;\r
+      if (BaseAddress < BASE_1MB) {\r
+        if (Length <= BASE_1MB - BaseAddress) {\r
+          continue;\r
         }\r
+        Length -= BASE_1MB - BaseAddress;\r
+        BaseAddress = BASE_1MB;\r
       }\r
-      if (WorkingIndex == WorkingVariableMtrrCount) {\r
-        FreeVariableMtrrCount++;\r
+      Status = MtrrLibSetMemoryType (\r
+                 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
+                 BaseAddress, Length, Ranges[Index].Type\r
+                 );\r
+      if (Status == RETURN_ALREADY_STARTED) {\r
+        Status = RETURN_SUCCESS;\r
+      } else if (Status == RETURN_OUT_OF_RESOURCES) {\r
+        return Status;\r
       } else {\r
-        CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
-        VariableSettingModified[Index] = TRUE;\r
-        WorkingIndex++;\r
+        ASSERT_RETURN_ERROR (Status);\r
+        Modified = TRUE;\r
       }\r
     }\r
-  }\r
-  ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
 \r
-  //\r
-  // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning\r
-  //\r
-  WorkingIndex = FirmwareVariableMtrrCount;\r
-  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
-    if (!OriginalVariableMtrr[Index].Valid) {\r
+    if (Modified) {\r
+      //\r
+      // 2.4. Calculate the Variable MTRR settings based on the Ranges.\r
+      //      Buffer Too Small may be returned if the scratch buffer size is insufficient.\r
+      //\r
+      Status = MtrrLibSetMemoryRanges (\r
+                 DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,\r
+                 Scratch, ScratchSize,\r
+                 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount\r
+                 );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
       //\r
-      // Found an empty MTRR in WorkingIndex position\r
+      // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
       //\r
-      for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
-        if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
+      for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {\r
+        if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {\r
+          ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);\r
+          WorkingVariableMtrrCount--;\r
+          CopyMem (\r
+            &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],\r
+            (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])\r
+            );\r
           break;\r
         }\r
       }\r
 \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
+      if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
       }\r
+\r
+      //\r
+      // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr\r
+      //      Make sure least modification is made to OriginalVariableMtrr.\r
+      //\r
+      MtrrLibMergeVariableMtrr (\r
+        OriginalVariableMtrr, OriginalVariableMtrrCount,\r
+        WorkingVariableMtrr, WorkingVariableMtrrCount,\r
+        VariableSettingModified\r
+      );\r
     }\r
   }\r
 \r
   //\r
-  // Convert OriginalVariableMtrr to VariableSettings\r
-  // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
+  // 3. Apply the below-1MB memory attribute settings.\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
+  ZeroMem (WorkingFixedSettings.Mtrr, sizeof (WorkingFixedSettings.Mtrr));\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if (Ranges[Index].BaseAddress >= BASE_1MB) {\r
+      continue;\r
     }\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
+    Status = MtrrLibSetBelow1MBMemoryAttribute (\r
+               &WorkingFixedSettings, FixedSettingsModified,\r
+               Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type\r
+               );\r
+    if (RETURN_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   MtrrContextValid = FALSE;\r
   //\r
-  // Write fixed MTRRs that have been modified\r
+  // 4. Write fixed MTRRs that have been modified\r
   //\r
-  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+  for (Index = 0; Index < ARRAY_SIZE (FixedSettingsModified); Index++) {\r
     if (FixedSettingsModified[Index]) {\r
-      if (!MtrrContextValid) {\r
-        MtrrLibPreMtrrChange (&MtrrContext);\r
-        MtrrContextValid = TRUE;\r
-      }\r
-      AsmWriteMsr64 (\r
-        mMtrrLibFixedMtrrTable[Index].Msr,\r
-        WorkingFixedSettings.Mtrr[Index]\r
+      if (MtrrSetting != NULL) {\r
+        MtrrSetting->Fixed.Mtrr[Index] = WorkingFixedSettings.Mtrr[Index];\r
+      } else {\r
+        if (!MtrrContextValid) {\r
+          MtrrLibPreMtrrChange (&MtrrContext);\r
+          MtrrContextValid = TRUE;\r
+        }\r
+        AsmWriteMsr64 (\r
+          mMtrrLibFixedMtrrTable[Index].Msr,\r
+          WorkingFixedSettings.Mtrr[Index]\r
         );\r
+      }\r
     }\r
   }\r
 \r
   //\r
-  // Write variable MTRRs\r
+  // 5. Write variable MTRRs that have been modified\r
   //\r
   for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
     if (VariableSettingModified[Index]) {\r
-      if (!MtrrContextValid) {\r
-        MtrrLibPreMtrrChange (&MtrrContext);\r
-        MtrrContextValid = TRUE;\r
+      if (OriginalVariableMtrr[Index].Length != 0) {\r
+        VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)\r
+                             | (UINT8)OriginalVariableMtrr[Index].Type;\r
+        VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
+      } else {\r
+        VariableSetting.Base = 0;\r
+        VariableSetting.Mask = 0;\r
+      }\r
+      if (MtrrSetting != NULL) {\r
+        CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));\r
+      } else {\r
+        if (!MtrrContextValid) {\r
+          MtrrLibPreMtrrChange (&MtrrContext);\r
+          MtrrContextValid = TRUE;\r
+        }\r
+        AsmWriteMsr64 (\r
+          MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+          VariableSetting.Base\r
+        );\r
+        AsmWriteMsr64 (\r
+          MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
+          VariableSetting.Mask\r
+        );\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
-  return Status;\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 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 range.\r
-\r
-  @retval RETURN_SUCCESS            The attributes were set for the memory\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
-                                    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
-\r
-**/\r
-RETURN_STATUS\r
-EFIAPI\r
-MtrrSetMemoryAttribute (\r
-  IN PHYSICAL_ADDRESS        BaseAddress,\r
-  IN UINT64                  Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
-  )\r
-{\r
-  RETURN_STATUS              Status;\r
 \r
-  if (!IsMtrrSupported ()) {\r
-    return RETURN_UNSUPPORTED;\r
+  if (MtrrSetting != NULL) {\r
+    ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;\r
+    ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
+  } else {\r
+    if (MtrrContextValid) {\r
+      MtrrLibPostMtrrChange (&MtrrContext);\r
+    }\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
+  return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -2241,7 +2464,7 @@ MtrrSetMemoryAttribute (
                                     BaseAddress and Length cannot be modified.\r
   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of\r
                                     the memory resource range.\r
-\r
+  @retval RETURN_BUFFER_TOO_SMALL   The scratch buffer is too small for MTRR calculation.\r
 **/\r
 RETURN_STATUS\r
 EFIAPI\r
@@ -2253,17 +2476,66 @@ MtrrSetMemoryAttributeInMtrrSettings (
   )\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
+  UINT8                      Scratch[SCRATCH_BUFFER_SIZE];\r
+  UINTN                      ScratchSize;\r
+  MTRR_MEMORY_RANGE          Range;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  Range.BaseAddress = BaseAddress;\r
+  Range.Length      = Length;\r
+  Range.Type        = Attribute;\r
+  ScratchSize = sizeof (Scratch);\r
+  Status = MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);\r
+  DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute(MtrrSettings = %p) %s: [%016lx, %016lx) - %x\n",\r
+          MtrrSetting,\r
+          mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
 \r
   if (!RETURN_ERROR (Status)) {\r
     MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
   }\r
-\r
   return Status;\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 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 range.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory\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
+                                    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
+  @retval RETURN_BUFFER_TOO_SMALL   The scratch buffer is too small for MTRR calculation.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  )\r
+{\r
+  return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);\r
+}\r
+\r
 /**\r
   Worker function setting variable MTRRs\r
 \r
@@ -2279,17 +2551,17 @@ MtrrSetVariableMtrrWorker (
   UINT32  VariableMtrrCount;\r
 \r
   VariableMtrrCount = GetVariableMtrrCountWorker ();\r
-  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
 \r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-    AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
-      VariableSettings->Mtrr[Index].Base\r
-      );\r
-    AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
-      VariableSettings->Mtrr[Index].Mask\r
-      );\r
+    //\r
+    // Mask MSR is always updated since caller might need to invalidate the MSR pair.\r
+    // Base MSR is skipped when Mask.V is not set.\r
+    //\r
+    AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSettings->Mtrr[Index].Mask);\r
+    if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
+      AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSettings->Mtrr[Index].Base);\r
+    }\r
   }\r
 }\r
 \r
@@ -2408,7 +2680,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
@@ -2449,7 +2721,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
@@ -2493,3 +2765,111 @@ IsMtrrSupported (
   return TRUE;\r
 }\r
 \r
+\r
+/**\r
+  Worker function prints all MTRRs for debugging.\r
+\r
+  If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
+  settings buffer.\r
+  If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+  @param  MtrrSetting    A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
+  )\r
+{\r
+  DEBUG_CODE (\r
+    MTRR_SETTINGS     LocalMtrrs;\r
+    MTRR_SETTINGS     *Mtrrs;\r
+    UINTN             Index;\r
+    UINTN             RangeCount;\r
+    UINT64            MtrrValidBitsMask;\r
+    UINT64            MtrrValidAddressMask;\r
+    UINT32            VariableMtrrCount;\r
+    MTRR_MEMORY_RANGE Ranges[\r
+      ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1\r
+      ];\r
+    MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
+\r
+    if (!IsMtrrSupported ()) {\r
+      return;\r
+    }\r
+\r
+    VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+\r
+    if (MtrrSetting != NULL) {\r
+      Mtrrs = MtrrSetting;\r
+    } else {\r
+      MtrrGetAllMtrrs (&LocalMtrrs);\r
+      Mtrrs = &LocalMtrrs;\r
+    }\r
+\r
+    //\r
+    // Dump RAW MTRR contents\r
+    //\r
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+    DEBUG((DEBUG_CACHE, "=============\n"));\r
+    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
+    for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {\r
+      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
+    }\r
+\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 0) {\r
+        //\r
+        // If mask is not valid, then do not display range\r
+        //\r
+        continue;\r
+      }\r
+      DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+        Index,\r
+        Mtrrs->Variables.Mtrr[Index].Base,\r
+        Mtrrs->Variables.Mtrr[Index].Mask\r
+        ));\r
+    }\r
+    DEBUG((DEBUG_CACHE, "\n"));\r
+\r
+    //\r
+    // Dump MTRR setting in ranges\r
+    //\r
+    DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
+    DEBUG((DEBUG_CACHE, "====================================\n"));\r
+    MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+    Ranges[0].BaseAddress = 0;\r
+    Ranges[0].Length      = MtrrValidBitsMask + 1;\r
+    Ranges[0].Type        = MtrrGetDefaultMemoryTypeWorker (Mtrrs);\r
+    RangeCount = 1;\r
+\r
+    MtrrLibGetRawVariableRanges (\r
+      &Mtrrs->Variables, VariableMtrrCount,\r
+      MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges\r
+      );\r
+    MtrrLibApplyVariableMtrrs (\r
+      RawVariableRanges, VariableMtrrCount,\r
+      Ranges, ARRAY_SIZE (Ranges), &RangeCount\r
+      );\r
+\r
+    MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);\r
+\r
+    for (Index = 0; Index < RangeCount; Index++) {\r
+      DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",\r
+        mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],\r
+        Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1\r
+        ));\r
+    }\r
+  );\r
+}\r
+\r
+/**\r
+  This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+EFIAPI\r
+MtrrDebugPrintAllMtrrs (\r
+  VOID\r
+  )\r
+{\r
+  MtrrDebugPrintAllMtrrsWorker (NULL);\r
+}\r