]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Avoid running unnecessary code
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index dab0535fe98248032719bfeb8d9338c3b8b990ee..9d1927262a4edee650bd18621fac69cba7f73738 100644 (file)
@@ -1,8 +1,12 @@
 /** @file\r
   MTRR setting library\r
 \r
-  Copyright (c) 2008 - 2010, Intel Corporation\r
-  All rights reserved. This program and the accompanying materials\r
+  @par Note: \r
+    Most of services in this library instance are suggested to be invoked by BSP only,\r
+    except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.\r
+\r
+  Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
   http://opensource.org/licenses/bsd-license.php\r
 \r
 #include <Base.h>\r
 \r
+#include <Register/Cpuid.h>\r
+#include <Register/Msr.h>\r
+\r
 #include <Library/MtrrLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/CpuLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \r
+#define OR_SEED      0x0101010101010101ull\r
+#define CLEAR_SEED   0xFFFFFFFFFFFFFFFFull\r
+\r
+#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
+//\r
+// Context to save and restore when MTRRs are programmed\r
+//\r
+typedef struct {\r
+  UINTN    Cr4;\r
+  BOOLEAN  InterruptState;\r
+} MTRR_CONTEXT;\r
+\r
+typedef struct {\r
+  UINT64                 BaseAddress;\r
+  UINT64                 Length;\r
+  MTRR_MEMORY_CACHE_TYPE Type;\r
+} MEMORY_RANGE;\r
+\r
 //\r
 // This table defines the offset, base and length of the fixed MTRRs\r
 //\r
-STATIC\r
-FIXED_MTRR    MtrrLibFixedMtrrTable[] = {\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
+  }\r
+};\r
+\r
+//\r
+// Lookup table used to print MTRRs\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
+  "UC",  // CacheUncacheable\r
+  "WC",  // CacheWriteCombining\r
+  "R*",  // Invalid\r
+  "R*",  // Invalid\r
+  "WT",  // CacheWriteThrough\r
+  "WP",  // CacheWriteProtected\r
+  "WB",  // CacheWriteBack\r
+  "R*"   // Invalid\r
 };\r
 \r
+/**\r
+  Worker function returns the variable MTRR count for the CPU.\r
+\r
+  @return Variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetVariableMtrrCountWorker (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
+\r
+  MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
+  ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  return MtrrCap.Bits.VCNT;\r
+}\r
+\r
 /**\r
   Returns the variable MTRR count for the CPU.\r
 \r
@@ -89,6 +145,7 @@ FIXED_MTRR    MtrrLibFixedMtrrTable[] = {
 \r
 **/\r
 UINT32\r
+EFIAPI\r
 GetVariableMtrrCount (\r
   VOID\r
   )\r
@@ -96,8 +153,30 @@ GetVariableMtrrCount (
   if (!IsMtrrSupported ()) {\r
     return 0;\r
   }\r
+  return GetVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+  Worker function returns the firmware usable variable MTRR count for the CPU.\r
+\r
+  @return Firmware usable variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetFirmwareVariableMtrrCountWorker (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  VariableMtrrCount;\r
+  UINT32  ReservedMtrrNumber;\r
+\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
+  if (VariableMtrrCount < ReservedMtrrNumber) {\r
+    return 0;\r
+  }\r
 \r
-  return (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
+  return VariableMtrrCount - ReservedMtrrNumber;\r
 }\r
 \r
 /**\r
@@ -107,50 +186,83 @@ GetVariableMtrrCount (
 \r
 **/\r
 UINT32\r
+EFIAPI\r
 GetFirmwareVariableMtrrCount (\r
   VOID\r
   )\r
 {\r
-  UINT32  VariableMtrrCount;\r
-\r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
-  if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) {\r
+  if (!IsMtrrSupported ()) {\r
     return 0;\r
   }\r
+  return GetFirmwareVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+  Worker function returns the default MTRR cache type for the system.\r
+\r
+  If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
+\r
+  @param[in]  MtrrSetting    A buffer holding all MTRRs content.\r
+\r
+  @return  The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetDefaultMemoryTypeWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting\r
+  )\r
+{\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
+\r
+  if (MtrrSetting == NULL) {\r
+    DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
+  } else {\r
+    DefType.Uint64 = MtrrSetting->MtrrDefType;\r
+  }\r
 \r
-  return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;\r
+  return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
 }\r
 \r
+\r
 /**\r
   Returns the default MTRR cache type for the system.\r
 \r
-  @return  MTRR default type\r
+  @return  The default MTRR cache type.\r
 \r
 **/\r
-UINT64\r
-GetMtrrDefaultMemoryType (\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetDefaultMemoryType (\r
   VOID\r
-)\r
+  )\r
 {\r
-  return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
+  return MtrrGetDefaultMemoryTypeWorker (NULL);\r
 }\r
 \r
-\r
 /**\r
   Preparation before programming MTRR.\r
 \r
   This function will do some preparation for programming MTRRs:\r
   disable cache, invalid cache and disable MTRR caching functionality\r
 \r
-  @return  CR4 value before changing.\r
+  @param[out] MtrrContext  Pointer to context to save\r
 \r
 **/\r
-UINTN\r
-PreMtrrChange (\r
-  VOID\r
+VOID\r
+MtrrLibPreMtrrChange (\r
+  OUT MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
-  UINTN  Value;\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;\r
+  //\r
+  // Disable interrupts and save current interrupt state\r
+  //\r
+  MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
 \r
   //\r
   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
@@ -160,8 +272,8 @@ PreMtrrChange (
   //\r
   // Save original CR4 value and clear PGE flag (Bit 7)\r
   //\r
-  Value = AsmReadCr4 ();\r
-  AsmWriteCr4 (Value & (~BIT7));\r
+  MtrrContext->Cr4 = AsmReadCr4 ();\r
+  AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
 \r
   //\r
   // Flush all TLBs\r
@@ -169,38 +281,29 @@ PreMtrrChange (
   CpuFlushTlb ();\r
 \r
   //\r
-  // Disable Mtrrs\r
-  //\r
-  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
-\r
-  //\r
-  // Return original CR4 value\r
+  // Disable MTRRs\r
   //\r
-  return Value;\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
 /**\r
   Cleaning up after programming MTRRs.\r
 \r
   This function will do some clean up after programming MTRRs:\r
-  enable MTRR caching functionality, and enable cache\r
+  Flush all TLBs,  re-enable caching, restore CR4.\r
 \r
-  @param  Cr4  CR4 value to restore\r
+  @param[in] MtrrContext  Pointer to context to restore\r
 \r
 **/\r
 VOID\r
-PostMtrrChange (\r
-  UINTN Cr4\r
+MtrrLibPostMtrrChangeEnableCache (\r
+  IN MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
   //\r
-  // Enable Cache MTRR\r
-  //\r
-  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
-\r
-  //\r
-  // Flush all TLBs \r
+  // Flush all TLBs\r
   //\r
   CpuFlushTlb ();\r
 \r
@@ -212,16 +315,161 @@ PostMtrrChange (
   //\r
   // Restore original CR4 value\r
   //\r
-  AsmWriteCr4 (Cr4);\r
+  AsmWriteCr4 (MtrrContext->Cr4);\r
+\r
+  //\r
+  // Restore original interrupt state\r
+  //\r
+  SetInterruptState (MtrrContext->InterruptState);\r
+}\r
+\r
+/**\r
+  Cleaning up after programming MTRRs.\r
+\r
+  This function will do some clean up after programming MTRRs:\r
+  enable MTRR caching functionality, and enable cache\r
+\r
+  @param[in] MtrrContext  Pointer to context to restore\r
+\r
+**/\r
+VOID\r
+MtrrLibPostMtrrChange (\r
+  IN MTRR_CONTEXT  *MtrrContext\r
+  )\r
+{\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;\r
+  //\r
+  // Enable Cache MTRR\r
+  //\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
+\r
+/**\r
+  Worker function gets the content in fixed MTRRs\r
+\r
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+  @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+MtrrGetFixedMtrrWorker (\r
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      FixedSettings->Mtrr[Index] =\r
+        AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
+  }\r
+\r
+  return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+  This function gets the content in fixed MTRRs\r
+\r
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+  @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrGetFixedMtrr (\r
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return FixedSettings;\r
+  }\r
+\r
+  return MtrrGetFixedMtrrWorker (FixedSettings);\r
+}\r
+\r
+\r
+/**\r
+  Worker function will get the raw value in variable MTRRs\r
+\r
+  If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
+\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
+  @param[in]  VariableMtrrCount  Number of variable MTRRs.\r
+  @param[out] VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+MtrrGetVariableMtrrWorker (\r
+  IN  MTRR_SETTINGS           *MtrrSetting,\r
+  IN  UINT32                  VariableMtrrCount,\r
+  OUT MTRR_VARIABLE_SETTINGS  *VariableSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (MtrrSetting == NULL) {\r
+      VariableSettings->Mtrr[Index].Base =\r
+        AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
+      VariableSettings->Mtrr[Index].Mask =\r
+        AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
+    } else {\r
+      VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
+      VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
+    }\r
+  }\r
+\r
+  return  VariableSettings;\r
 }\r
 \r
+/**\r
+  This function will get the raw value in variable MTRRs\r
+\r
+  @param[out]  VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrGetVariableMtrr (\r
+  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return VariableSettings;\r
+  }\r
+\r
+  return MtrrGetVariableMtrrWorker (\r
+           NULL,\r
+           GetVariableMtrrCountWorker (),\r
+           VariableSettings\r
+           );\r
+}\r
 \r
 /**\r
   Programs fixed MTRRs registers.\r
 \r
-  @param  MemoryCacheType  The memory type to set.\r
-  @param  Base             The base address of memory range.\r
-  @param  Length           The length of memory range.\r
+  @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
+                                   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
 \r
   @retval RETURN_SUCCESS      The cache type was updated successfully\r
   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
@@ -229,28 +477,31 @@ PostMtrrChange (
 \r
 **/\r
 RETURN_STATUS\r
-ProgramFixedMtrr (\r
-  IN     UINT64     MemoryCacheType,\r
-  IN OUT UINT64     *Base,\r
-  IN OUT UINT64     *Length\r
+MtrrLibProgramFixedMtrr (\r
+  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
   )\r
 {\r
   UINT32  MsrNum;\r
-  UINT32  ByteShift;\r
-  UINT64  TempQword;\r
+  UINT32  LeftByteShift;\r
+  UINT32  RightByteShift;\r
   UINT64  OrMask;\r
   UINT64  ClearMask;\r
+  UINT64  SubLength;\r
 \r
-  TempQword = 0;\r
-  OrMask    = 0;\r
-  ClearMask = 0;\r
-\r
-  for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
-    if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\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
         (*Base <\r
             (\r
-              MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
-              (8 * MtrrLibFixedMtrrTable[MsrNum].Length)\r
+              mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+              (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
             )\r
           )\r
         ) {\r
@@ -263,104 +514,102 @@ ProgramFixedMtrr (
   }\r
 \r
   //\r
-  // We found the fixed MTRR to be programmed\r
+  // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
   //\r
-  for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
-    if (*Base ==\r
-         (\r
-           MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
-           (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)\r
-         )\r
-       ) {\r
-      break;\r
-    }\r
-  }\r
+  LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)\r
+               / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
 \r
-  if (ByteShift == 8) {\r
+  if (LeftByteShift >= 8) {\r
     return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  for (\r
-        ;\r
-        ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));\r
-        ByteShift++\r
-      ) {\r
-    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
-    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
-    *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;\r
-    *Base += MtrrLibFixedMtrrTable[MsrNum].Length;\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
+  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
+      return RETURN_UNSUPPORTED;\r
+    }\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
+\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
   }\r
 \r
-  if (ByteShift < 8 && (*Length != 0)) {\r
-    return RETURN_UNSUPPORTED;\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
   }\r
 \r
-  TempQword =\r
-    (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
-  AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
+  *Length -= SubLength;\r
+  *Base   += SubLength;\r
+\r
+  *LastMsrNum      = MsrNum;\r
+  *ReturnClearMask = ClearMask;\r
+  *ReturnOrMask    = OrMask;\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
 \r
 /**\r
-  Get the attribute of variable MTRRs.\r
+  Worker function gets the attribute of variable MTRRs.\r
 \r
   This function shadows the content of variable MTRRs into an\r
   internal array: VariableMtrr.\r
 \r
-  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
-  @param  MtrrValidAddressMask  The valid address mask for MTRR\r
-  @param  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 paramter indicates the\r
-                                number of MTRRs which has been used.\r
+  @return      Number of MTRRs which has been used.\r
 \r
 **/\r
 UINT32\r
-EFIAPI\r
-MtrrGetMemoryAttributeInVariableMtrr (\r
-  IN  UINT64                    MtrrValidBitsMask,\r
-  IN  UINT64                    MtrrValidAddressMask,\r
-  OUT VARIABLE_MTRR             *VariableMtrr\r
+MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN  UINTN                   VariableMtrrCount,\r
+  IN  UINT64                  MtrrValidBitsMask,\r
+  IN  UINT64                  MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR           *VariableMtrr\r
   )\r
 {\r
   UINTN   Index;\r
-  UINT32  MsrNum;\r
   UINT32  UsedMtrr;\r
-  UINT32  FirmwareVariableMtrrCount;\r
-  UINT32  VariableMtrrEnd;\r
-\r
-  if (!IsMtrrSupported ()) {\r
-    return 0;\r
-  }\r
-\r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
-  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
 \r
   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
-  UsedMtrr = 0;\r
-\r
-  for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
-       (\r
-         (MsrNum < VariableMtrrEnd) &&\r
-         (Index < FirmwareVariableMtrrCount)\r
-       );\r
-       MsrNum += 2\r
-      ) {\r
-    if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
-      VariableMtrr[Index].Msr          = MsrNum;\r
-      VariableMtrr[Index].BaseAddress  = (AsmReadMsr64 (MsrNum) &\r
-                                          MtrrValidAddressMask);\r
-      VariableMtrr[Index].Length       = ((~(AsmReadMsr64 (MsrNum + 1) &\r
-                                             MtrrValidAddressMask)\r
-                                          ) &\r
-                                          MtrrValidBitsMask\r
-                                         ) + 1;\r
-      VariableMtrr[Index].Type         = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
-      VariableMtrr[Index].Valid        = TRUE;\r
-      VariableMtrr[Index].Used         = TRUE;\r
-      UsedMtrr = UsedMtrr  + 1;\r
-      Index++;\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].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
+      VariableMtrr[Index].Valid       = TRUE;\r
+      VariableMtrr[Index].Used        = TRUE;\r
+      UsedMtrr++;\r
     }\r
   }\r
   return UsedMtrr;\r
@@ -368,873 +617,1606 @@ MtrrGetMemoryAttributeInVariableMtrr (
 \r
 \r
 /**\r
-  Checks overlap between given memory range and MTRRs.\r
+  Gets the attribute of variable MTRRs.\r
 \r
-  @param  Start            The start address of memory range.\r
-  @param  End              The end address of memory range.\r
-  @param  VariableMtrr     The array to shadow variable MTRRs content\r
+  This function shadows the content of variable MTRRs into an\r
+  internal array: VariableMtrr.\r
 \r
-  @retval TRUE             Overlap exists.\r
-  @retval FALSE            No overlap.\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
 \r
 **/\r
-BOOLEAN\r
-CheckMemoryAttributeOverlap (\r
-  IN PHYSICAL_ADDRESS     Start,\r
-  IN PHYSICAL_ADDRESS     End,\r
-  IN VARIABLE_MTRR      *VariableMtrr\r
+UINT32\r
+EFIAPI\r
+MtrrGetMemoryAttributeInVariableMtrr (\r
+  IN  UINT64                    MtrrValidBitsMask,\r
+  IN  UINT64                    MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR             *VariableMtrr\r
   )\r
 {\r
-  UINT32  Index;\r
+  MTRR_VARIABLE_SETTINGS  VariableSettings;\r
 \r
-  for (Index = 0; Index < 6; Index++) {\r
-    if (\r
-         VariableMtrr[Index].Valid &&\r
-         !(\r
-           (Start > (VariableMtrr[Index].BaseAddress +\r
-                     VariableMtrr[Index].Length - 1)\r
-           ) ||\r
-           (End < VariableMtrr[Index].BaseAddress)\r
-         )\r
-       ) {\r
-      return TRUE;\r
-    }\r
+  if (!IsMtrrSupported ()) {\r
+    return 0;\r
   }\r
 \r
-  return FALSE;\r
-}\r
+  MtrrGetVariableMtrrWorker (\r
+    NULL,\r
+    GetVariableMtrrCountWorker (),\r
+    &VariableSettings\r
+    );\r
 \r
+  return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+           &VariableSettings,\r
+           GetFirmwareVariableMtrrCountWorker (),\r
+           MtrrValidBitsMask,\r
+           MtrrValidAddressMask,\r
+           VariableMtrr\r
+           );\r
+}\r
 \r
 /**\r
-  Marks a variable MTRR as non-valid.\r
+  Return the least alignment of address.\r
 \r
-  @param  Index         The index of the array VariableMtrr to be invalidated\r
-  @param  VariableMtrr  The array to shadow variable MTRRs content\r
-  @param  UsedMtrr      The number of MTRRs which has already been used\r
+  @param Address    The address to return the alignment.\r
+  @param Alignment0 The alignment to return when Address is 0.\r
 \r
+  @return The least alignment of the Address.\r
 **/\r
-VOID\r
-InvalidateShadowMtrr (\r
-  IN   UINTN              Index,\r
-  IN   VARIABLE_MTRR      *VariableMtrr,\r
-  OUT  UINT32             *UsedMtrr\r
-  )\r
+UINT64\r
+MtrrLibLeastAlignment (\r
+  UINT64    Address,\r
+  UINT64    Alignment0\r
+)\r
 {\r
-  VariableMtrr[Index].Valid = FALSE;\r
-  *UsedMtrr = *UsedMtrr - 1;\r
-}\r
+  if (Address == 0) {\r
+    return Alignment0;\r
+  }\r
 \r
+  return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
+}\r
 \r
 /**\r
-  Combine memory attributes.\r
-\r
-  If overlap exists between given memory range and MTRRs, try to combine them.\r
-\r
-  @param  Attributes             The memory type to set.\r
-  @param  Base                   The base address of memory range.\r
-  @param  Length                 The length of memory range.\r
-  @param  VariableMtrr           The array to shadow variable MTRRs content\r
-  @param  UsedMtrr               The number of MTRRs which has already been used\r
-  @param  OverwriteExistingMtrr  Returns whether an existing MTRR was used\r
+  Return the number of required variable MTRRs to positively cover the\r
+  specified range.\r
 \r
-  @retval EFI_SUCCESS            Memory region successfully combined.\r
-  @retval EFI_ACCESS_DENIED      Memory region cannot be combined.\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
-RETURN_STATUS\r
-CombineMemoryAttribute (\r
-  IN     UINT64             Attributes,\r
-  IN OUT UINT64             *Base,\r
-  IN OUT UINT64             *Length,\r
-  IN     VARIABLE_MTRR      *VariableMtrr,\r
-  IN OUT UINT32             *UsedMtrr,\r
-  OUT    BOOLEAN            *OverwriteExistingMtrr\r
-  )\r
+UINT32\r
+MtrrLibGetPositiveMtrrNumber (\r
+  IN UINT64      BaseAddress,\r
+  IN UINT64      Length,\r
+  IN UINT64      Alignment0\r
+)\r
 {\r
-  UINT32  Index;\r
-  UINT64  CombineStart;\r
-  UINT64  CombineEnd;\r
-  UINT64  MtrrEnd;\r
-  UINT64  EndAddress;\r
-  UINT32  FirmwareVariableMtrrCount;\r
-\r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
-\r
-  *OverwriteExistingMtrr = FALSE;\r
-  EndAddress = *Base +*Length - 1;\r
-\r
-  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
-\r
-    MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
-    if (\r
-         !VariableMtrr[Index].Valid ||\r
-         (\r
-           *Base > (MtrrEnd) ||\r
-           (EndAddress < VariableMtrr[Index].BaseAddress)\r
-         )\r
-       ) {\r
-      continue;\r
-    }\r
+  UINT64         SubLength;\r
+  UINT32         MtrrNumber;\r
+  BOOLEAN        UseLeastAlignment;\r
 \r
+  UseLeastAlignment = TRUE;\r
+  SubLength = 0;\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
+}\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
+  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
+\r
+  @retval TRUE  Left precedes Right.\r
+  @retval FALSE Left doesn't precede Right.\r
+**/\r
+BOOLEAN\r
+MtrrLibTypeLeftPrecedeRight (\r
+  IN MTRR_MEMORY_CACHE_TYPE  Left,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Right\r
+)\r
+{\r
+  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
+  BaseAlignment = 0;\r
+\r
+  //\r
+  // Get the optimal left subtraction solution.\r
+  //\r
+  if (BaseAddress != 0) {\r
+    SubtractiveBaseAddress = 0;\r
+    SubtractiveLength      = 0;\r
+    //\r
+    // Get the MTRR number needed without left subtraction.\r
+    //\r
+    LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
+\r
+    //\r
+    // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
     //\r
-    // Combine same attribute MTRR range\r
-    //\r
-    if (Attributes == VariableMtrr[Index].Type) {\r
+    for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
+      Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+\r
       //\r
-      // if the Mtrr range contain the request range, return RETURN_SUCCESS\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 (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
-        *Length = 0;\r
-        return RETURN_SUCCESS;\r
+      if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
+        break;\r
       }\r
-      //\r
-      // invalid this MTRR, and program the combine range\r
-      //\r
-      CombineStart  =\r
-        (*Base) < VariableMtrr[Index].BaseAddress ?\r
-          (*Base) :\r
-          VariableMtrr[Index].BaseAddress;\r
-      CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
 \r
-      //\r
-      // Record the MTRR usage status in VariableMtrr array.\r
-      //\r
-      InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
-      *Base       = CombineStart;\r
-      *Length     = CombineEnd - CombineStart + 1;\r
-      EndAddress  = CombineEnd;\r
-      *OverwriteExistingMtrr = TRUE;\r
-      continue;\r
-    } else {\r
-      //\r
-      // The cache type is different, but the range is convered by one MTRR\r
-      //\r
-      if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
-        InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
-        continue;\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
-    if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
-         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
-        (Attributes == MTRR_CACHE_WRITE_BACK &&\r
-         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
-        (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
-        (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
-     ) {\r
-      *OverwriteExistingMtrr = TRUE;\r
-      continue;\r
+  //\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
-    // Other type memory overlap is invalid\r
+    // SubtractiveCount = Number of MTRRs used for subtraction\r
     //\r
-    return RETURN_ACCESS_DENIED;\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 RETURN_SUCCESS;\r
+  return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
 }\r
 \r
-\r
 /**\r
-  Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
+  Initializes the valid bits mask and valid address mask for MTRRs.\r
 \r
-  @param  MemoryLength        The number to pass in.\r
-  @return The maximum value which is align to power of 2 and less the MemoryLength\r
+  This function initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+  @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR\r
 \r
 **/\r
-UINT64\r
-Power2MaxMemory (\r
-  IN UINT64                     MemoryLength\r
+VOID\r
+MtrrLibInitializeMtrrMask (\r
+  OUT UINT64 *MtrrValidBitsMask,\r
+  OUT UINT64 *MtrrValidAddressMask\r
   )\r
 {\r
-  UINT64  Result;\r
-\r
-  if (RShiftU64 (MemoryLength, 32)) {\r
-    Result = LShiftU64 (\r
-               (UINT64) GetPowerOfTwo32 (\r
-                          (UINT32) RShiftU64 (MemoryLength, 32)\r
-                          ),\r
-               32\r
-               );\r
+  UINT32                          MaxExtendedFunction;\r
+  CPUID_VIR_PHY_ADDRESS_SIZE_EAX  VirPhyAddressSize;\r
+\r
+\r
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
+\r
+  if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
+    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
   } else {\r
-    Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
+    VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
   }\r
 \r
-  return Result;\r
+  *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
+  *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
 }\r
 \r
 \r
 /**\r
-  Check the direction to program variable MTRRs.\r
-\r
-  This function determines which direction of programming the variable\r
-  MTRRs will use fewer MTRRs.\r
+  Determines the real attribute of a memory range.\r
 \r
-  @param  Input       Length of Memory to program MTRR\r
-  @param  MtrrNumber  Pointer to the number of necessary MTRRs\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
+  please refer the IA32 Software Developer's Manual, Volume 3,\r
+  Section "MTRR Precedences".\r
 \r
-  @retval TRUE        Positive direction is better.\r
-          FALSE       Negtive direction is better.\r
+  @param[in]  MtrrType1    The first kind of Memory type\r
+  @param[in]  MtrrType2    The second kind of memory type\r
 \r
 **/\r
-BOOLEAN\r
-GetDirection (\r
-  IN UINT64      Input,\r
-  IN UINTN       *MtrrNumber\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrLibPrecedence (\r
+  IN MTRR_MEMORY_CACHE_TYPE    MtrrType1,\r
+  IN MTRR_MEMORY_CACHE_TYPE    MtrrType2\r
   )\r
 {\r
-  UINT64  TempQword;\r
-  UINT32  Positive;\r
-  UINT32  Subtractive;\r
-\r
-  TempQword   = Input;\r
-  Positive    = 0;\r
-  Subtractive = 0;\r
-\r
-  do {\r
-    TempQword -= Power2MaxMemory (TempQword);\r
-    Positive++;\r
-  } while (TempQword != 0);\r
-\r
-  TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\r
-  Subtractive++;\r
-  do {\r
-    TempQword -= Power2MaxMemory (TempQword);\r
-    Subtractive++;\r
-  } while (TempQword != 0);\r
-\r
-  if (Positive <= Subtractive) {\r
-    *MtrrNumber = Positive;\r
-    return TRUE;\r
+  if (MtrrType1 == MtrrType2) {\r
+    return MtrrType1;\r
+  }\r
+\r
+  ASSERT (\r
+    MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
+    MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
+  );\r
+\r
+  if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
+    return MtrrType1;\r
   } else {\r
-    *MtrrNumber = Subtractive;\r
-    return FALSE;\r
+    return MtrrType2;\r
   }\r
 }\r
 \r
 /**\r
-  Invalid variable MTRRs according to the value in the shadow array.\r
+  Worker function will get the memory cache type of the specific address.\r
 \r
-  This function programs MTRRs according to the values specified\r
-  in the shadow array.\r
+  If MtrrSetting is not NULL, gets the memory cache type from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
 \r
-  @param  VariableMtrr   The array to shadow variable MTRRs content\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
+  @param[in]  Address            The specific address\r
+\r
+  @return Memory cache type of the specific address\r
 \r
 **/\r
-STATIC\r
-VOID\r
-InvalidateMtrr (\r
-   IN     VARIABLE_MTRR      *VariableMtrr\r
-   )\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetMemoryAttributeByAddressWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS   Address\r
+  )\r
 {\r
-  UINTN Index;\r
-  UINTN Cr4;\r
-  UINTN VariableMtrrCount;\r
-\r
-  Cr4 = PreMtrrChange ();\r
-  Index = 0;\r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
-  while (Index < VariableMtrrCount) {\r
-    if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
-       VariableMtrr[Index].Used = FALSE;\r
-    }\r
-    Index ++;\r
-  }\r
-  PostMtrrChange (Cr4);\r
-}\r
+  MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
+  UINT64                          FixedMtrr;\r
+  UINTN                           Index;\r
+  UINTN                           SubIndex;\r
+  MTRR_MEMORY_CACHE_TYPE          MtrrType;\r
+  VARIABLE_MTRR                   VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT64                          MtrrValidBitsMask;\r
+  UINT64                          MtrrValidAddressMask;\r
+  UINT32                          VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS          VariableSettings;\r
 \r
+  //\r
+  // Check if MTRR is enabled, if not, return UC as attribute\r
+  //\r
+  if (MtrrSetting == NULL) {\r
+    DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
+  } else {\r
+    DefType.Uint64 = MtrrSetting->MtrrDefType;\r
+  }\r
 \r
-/**\r
-  Programs variable MTRRs\r
-\r
-  This function programs variable MTRRs\r
+  if (DefType.Bits.E == 0) {\r
+    return CacheUncacheable;\r
+  }\r
 \r
-  @param  MtrrNumber            Index of MTRR to program.\r
-  @param  BaseAddress           Base address of memory region.\r
-  @param  Length                Length of memory region.\r
-  @param  MemoryCacheType       Memory type to set.\r
-  @param  MtrrValidAddressMask  The valid address mask for MTRR\r
+  //\r
+  // If address is less than 1M, then try to go through the fixed MTRR\r
+  //\r
+  if (Address < BASE_1MB) {\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 < 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
 \r
-**/\r
-STATIC\r
-VOID\r
-ProgramVariableMtrr (\r
-  IN UINTN                    MtrrNumber,\r
-  IN PHYSICAL_ADDRESS         BaseAddress,\r
-  IN UINT64                   Length,\r
-  IN UINT64                   MemoryCacheType,\r
-  IN UINT64                   MtrrValidAddressMask\r
-  )\r
-{\r
-  UINT64  TempQword;\r
-  UINTN   Cr4;\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+    &VariableSettings,\r
+    VariableMtrrCount,\r
+    MtrrValidBitsMask,\r
+    MtrrValidAddressMask,\r
+    VariableMtrr\r
+  );\r
 \r
   //\r
-  // MTRR Physical Base\r
+  // Go through the variable MTRR\r
   //\r
-  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
-  AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
+  MtrrType = CacheInvalid;\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid) {\r
+      if (Address >= VariableMtrr[Index].BaseAddress &&\r
+          Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
+        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
 \r
   //\r
-  // MTRR Physical Mask\r
+  // If there is no MTRR which covers the Address, use the default MTRR type.\r
   //\r
-  TempQword = ~(Length - 1);\r
-  AsmWriteMsr64 (\r
-    (UINT32) (MtrrNumber + 1),\r
-    (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
-    );\r
+  if (MtrrType == CacheInvalid) {\r
+    MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
+  }\r
 \r
-  PostMtrrChange (Cr4);\r
+  return MtrrType;\r
 }\r
 \r
 \r
 /**\r
-  Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
+  This function will get the memory cache type of the specific address.\r
+\r
+  This function is mainly for debug purpose.\r
 \r
-  @param  MtrrType  MTRR memory type\r
+  @param[in]  Address   The specific address\r
 \r
-  @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
+  @return Memory cache type of the specific address\r
 \r
 **/\r
-STATIC\r
 MTRR_MEMORY_CACHE_TYPE\r
-GetMemoryCacheTypeFromMtrrType (\r
-  IN UINT64                MtrrType\r
+EFIAPI\r
+MtrrGetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS   Address\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
+  if (!IsMtrrSupported ()) {\r
     return CacheUncacheable;\r
   }\r
+\r
+  return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
 }\r
 \r
 /**\r
-  Initializes the valid bits mask and valid address mask for MTRRs.\r
-\r
-  This function initializes the valid bits mask and valid address mask for MTRRs.\r
+  Worker function prints all MTRRs for debugging.\r
 \r
-  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
-  @param  MtrrValidAddressMask  The valid address mask for the MTRR\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
-STATIC\r
 VOID\r
-MtrrLibInitializeMtrrMask (\r
-  OUT UINT64 *MtrrValidBitsMask,\r
-  OUT UINT64 *MtrrValidAddressMask\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
   )\r
 {\r
-  UINT32                              RegEax;\r
-  UINT8                               PhysicalAddressBits;\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
-  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+    DEBUG((DEBUG_CACHE, "=============\n"));\r
 \r
-  if (RegEax >= 0x80000008) {\r
-    AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+    if (MtrrSetting != NULL) {\r
+      Mtrrs = MtrrSetting;\r
+    } else {\r
+      MtrrGetAllMtrrs (&LocalMtrrs);\r
+      Mtrrs = &LocalMtrrs;\r
+    }\r
 \r
-    PhysicalAddressBits = (UINT8) RegEax;\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
-    *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;\r
-    *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
-  } else {\r
-    *MtrrValidBitsMask    = MTRR_LIB_CACHE_VALID_ADDRESS;\r
-    *MtrrValidAddressMask = 0xFFFFFFFF;\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
-  Determing the real attribute of a memory range.\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
-  This function is to arbitrate the real attribute of the memory when\r
-  there are 2 MTRR 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
+/**\r
+  Update the Ranges array to change the specified range identified by\r
+  BaseAddress and Length to Type.\r
+\r
+  @param Ranges      Array holding memory type settings for all memory regions.\r
+  @param Capacity    The maximum count of memory ranges the array can hold.\r
+  @param Count       Return the new memory range count in the array.\r
+  @param BaseAddress The base address of the memory range to change type.\r
+  @param Length      The length of the memory range to change type.\r
+  @param Type        The new type of the specified memory range.\r
+\r
+  @retval RETURN_SUCCESS          The type of the specified memory range is\r
+                                  changed successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
+                                  range exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryType (\r
+  IN MEMORY_RANGE                 *Ranges,\r
+  IN UINT32                        Capacity,\r
+  IN OUT UINT32                    *Count,\r
+  IN UINT64                        BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type\r
+  )\r
+{\r
+  UINT32                           Index;\r
+  UINT64                           Limit;\r
+  UINT64                           LengthLeft;\r
+  UINT64                           LengthRight;\r
+  UINT32                           StartIndex;\r
+  UINT32                           EndIndex;\r
+  UINT32                           DeltaCount;\r
+\r
+  LengthRight = 0;\r
+  LengthLeft  = 0;\r
+  Limit = BaseAddress + Length;\r
+  StartIndex = *Count;\r
+  EndIndex = *Count;\r
+  for (Index = 0; Index < *Count; Index++) {\r
+    if ((StartIndex == *Count) &&\r
+        (Ranges[Index].BaseAddress <= BaseAddress) &&\r
+        (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+      StartIndex = Index;\r
+      LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
+    }\r
+\r
+    if ((EndIndex == *Count) &&\r
+        (Ranges[Index].BaseAddress < Limit) &&\r
+        (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+      EndIndex = Index;\r
+      LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT (StartIndex != *Count && EndIndex != *Count);\r
+  if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
+    return RETURN_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // The type change may cause merging with previous range or next range.\r
+  // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
+  // logic doesn't need to consider merging.\r
+  //\r
+  if (StartIndex != 0) {\r
+    if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
+      StartIndex--;\r
+      Length += Ranges[StartIndex].Length;\r
+      BaseAddress -= Ranges[StartIndex].Length;\r
+    }\r
+  }\r
+  if (EndIndex != (*Count) - 1) {\r
+    if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
+      EndIndex++;\r
+      Length += Ranges[EndIndex].Length;\r
+    }\r
+  }\r
+\r
+  //\r
+  // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount  Count (Count = 4)\r
+  //   |++++++++++++++++++|    0          3         1=3-0-2    3\r
+  //   |+++++++|               0          1        -1=1-0-2    5\r
+  //   |+|                     0          0        -2=0-0-2    6\r
+  // |+++|                     0          0        -1=0-0-2+1  5\r
+  //\r
+  //\r
+  DeltaCount = EndIndex - StartIndex - 2;\r
+  if (LengthLeft == 0) {\r
+    DeltaCount++;\r
+  }\r
+  if (LengthRight == 0) {\r
+    DeltaCount++;\r
+  }\r
+  if (*Count - DeltaCount > Capacity) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
 \r
-  @param  MtrrType1    the first kind of Memory type\r
-  @param  MtrrType2    the second kind of memory type\r
+  //\r
+  // Reserve (-DeltaCount) space\r
+  //\r
+  CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
+  *Count -= DeltaCount;\r
 \r
+  if (LengthLeft != 0) {\r
+    Ranges[StartIndex].Length = LengthLeft;\r
+    StartIndex++;\r
+  }\r
+  if (LengthRight != 0) {\r
+    Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
+    Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
+    Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
+  }\r
+  Ranges[StartIndex].BaseAddress = BaseAddress;\r
+  Ranges[StartIndex].Length = Length;\r
+  Ranges[StartIndex].Type = Type;\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the memory range.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
 **/\r
-UINT64\r
-MtrrPrecedence (\r
-  UINT64    MtrrType1,\r
-  UINT64    MtrrType2\r
-  )\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+  IN CONST MEMORY_RANGE           *Ranges,\r
+  IN UINT32                        RangeCount,\r
+  IN OUT VARIABLE_MTRR             *VariableMtrr,\r
+  IN UINT32                        VariableMtrrCapacity,\r
+  IN OUT UINT32                    *VariableMtrrCount,\r
+  IN UINT64                        BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type,\r
+  IN UINT64                        Alignment0\r
+  );\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
+  to allocate variable MTRRs when the range contains several sub-ranges\r
+  with different attributes.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the range.\r
+                              If it's CacheInvalid, the memory range may\r
+                              contains several sub-ranges with different\r
+                              attributes.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibAddVariableMtrr (\r
+  IN CONST MEMORY_RANGE           *Ranges,\r
+  IN UINT32                        RangeCount,\r
+  IN OUT VARIABLE_MTRR             *VariableMtrr,\r
+  IN UINT32                        VariableMtrrCapacity,\r
+  IN OUT UINT32                    *VariableMtrrCount,\r
+  IN PHYSICAL_ADDRESS              BaseAddress,\r
+  IN UINT64                        Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE        Type,\r
+  IN UINT64                        Alignment0\r
+)\r
 {\r
-  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
+  RETURN_STATUS                    Status;\r
+  UINT32                           Index;\r
+  UINT64                           SubLength;\r
+\r
+  MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
+  if (Type == CacheInvalid) {\r
+    ASSERT (Ranges != NULL);\r
+    for (Index = 0; Index < RangeCount; Index++) {\r
+      if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+\r
+        //\r
+        // Because the Length may not be aligned to BaseAddress, below code calls\r
+        // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
+        // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
+        // aligned ranges.\r
+        //\r
+        if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
+          return MtrrLibSetMemoryAttributeInVariableMtrr (\r
+            Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+            BaseAddress, Length, Ranges[Index].Type, Alignment0\r
+          );\r
+        } else {\r
+          SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
+          Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
+            Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+            BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
+          );\r
+          if (RETURN_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+          BaseAddress += SubLength;\r
+          Length -= SubLength;\r
+        }\r
+      }\r
     }\r
-    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
+    //\r
+    // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
+    //\r
+    ASSERT (FALSE);\r
+    return RETURN_DEVICE_ERROR;\r
+  } else {\r
+    for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
+      if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
+        ASSERT (VariableMtrr[Index].Type == Type);\r
+        break;\r
+      }\r
     }\r
-    break;\r
-  case MTRR_CACHE_WRITE_PROTECTED:\r
-    if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
-        MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
-      MtrrType = MtrrType2;\r
+    if (Index == *VariableMtrrCount) {\r
+      if (*VariableMtrrCount == VariableMtrrCapacity) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
+      }\r
+      VariableMtrr[Index].BaseAddress = BaseAddress;\r
+      VariableMtrr[Index].Length = Length;\r
+      VariableMtrr[Index].Type = Type;\r
+      VariableMtrr[Index].Valid = TRUE;\r
+      VariableMtrr[Index].Used = TRUE;\r
+      (*VariableMtrrCount)++;\r
     }\r
-    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
+    return RETURN_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Allocate one or more variable MTRR to cover the range identified by\r
+  BaseAddress and Length.\r
+\r
+  @param Ranges               Memory range array holding the memory type\r
+                              settings for all memory address.\r
+  @param RangeCount           Count of memory ranges.\r
+  @param VariableMtrr         Variable MTRR array.\r
+  @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+  @param VariableMtrrCount    Count of variable MTRR.\r
+  @param BaseAddress          Base address of the memory range.\r
+  @param Length               Length of the memory range.\r
+  @param Type                 MTRR type of the memory range.\r
+  @param Alignment0           Alignment of 0.\r
+\r
+  @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+  IN CONST MEMORY_RANGE     *Ranges,\r
+  IN UINT32                 RangeCount,\r
+  IN OUT VARIABLE_MTRR      *VariableMtrr,\r
+  IN UINT32                 VariableMtrrCapacity,\r
+  IN OUT UINT32             *VariableMtrrCount,\r
+  IN UINT64                 BaseAddress,\r
+  IN UINT64                 Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE Type,\r
+  IN UINT64                 Alignment0\r
+)\r
+{\r
+  UINT64                    Alignment;\r
+  UINT32                    MtrrNumber;\r
+  UINT32                    SubtractiveLeft;\r
+  UINT32                    SubtractiveRight;\r
+  BOOLEAN                   UseLeastAlignment;\r
+\r
+  Alignment = 0;\r
+\r
+  MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
+                                     BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
+\r
+  if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  while (SubtractiveLeft-- != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+    ASSERT (Alignment <= Length);\r
+\r
+    MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
+    BaseAddress -= Alignment;\r
+    Length += Alignment;\r
+  }\r
+\r
+  while (Length != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+    if (Alignment > Length) {\r
+      break;\r
     }\r
-    break;\r
-  case MTRR_CACHE_INVALID_TYPE:\r
-    MtrrType = MtrrType2;\r
-    break;\r
-  default:\r
-    break;\r
+    MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress, Alignment, Type, Alignment0);\r
+    BaseAddress += Alignment;\r
+    Length -= Alignment;\r
   }\r
 \r
-  if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
-    MtrrType = MtrrType1;\r
+  while (SubtractiveRight-- != 0) {\r
+    Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
+    MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
+    Length += Alignment;\r
   }\r
-  return MtrrType;\r
+\r
+  UseLeastAlignment = TRUE;\r
+  while (Length != 0) {\r
+    if (UseLeastAlignment) {\r
+      Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+      if (Alignment > Length) {\r
+        UseLeastAlignment = FALSE;\r
+      }\r
+    }\r
+\r
+    if (!UseLeastAlignment) {\r
+      Alignment = GetPowerOfTwo64 (Length);\r
+    }\r
+\r
+    MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+                            BaseAddress, Alignment, Type, Alignment0);\r
+    BaseAddress += Alignment;\r
+    Length -= Alignment;\r
+  }\r
+  return RETURN_SUCCESS;\r
 }\r
 \r
+/**\r
+  Return an array of memory ranges holding memory type settings for all memory\r
+  address.\r
+\r
+  @param DefaultType       The default memory type.\r
+  @param TotalLength       The total length of the memory.\r
+  @param VariableMtrr      The variable MTRR array.\r
+  @param VariableMtrrCount The count of variable MTRRs.\r
+  @param Ranges            Return the memory range array holding memory type\r
+                           settings for all memory address.\r
+  @param RangeCapacity     The capacity of memory range array.\r
+  @param RangeCount        Return the count of memory range.\r
+\r
+  @retval RETURN_SUCCESS          The memory range array is returned successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibGetMemoryTypes (\r
+  IN MTRR_MEMORY_CACHE_TYPE      DefaultType,\r
+  IN UINT64                      TotalLength,\r
+  IN CONST VARIABLE_MTRR         *VariableMtrr,\r
+  IN UINT32                      VariableMtrrCount,\r
+  OUT MEMORY_RANGE               *Ranges,\r
+  IN UINT32                      RangeCapacity,\r
+  OUT UINT32                     *RangeCount\r
+)\r
+{\r
+  RETURN_STATUS                  Status;\r
+  UINTN                          Index;\r
+\r
+  //\r
+  // WT > WB\r
+  // UC > *\r
+  // UC > * (except WB, UC) > WB\r
+  //\r
+\r
+  //\r
+  // 0. Set whole range as DefaultType\r
+  //\r
+  *RangeCount = 1;\r
+  Ranges[0].BaseAddress = 0;\r
+  Ranges[0].Length = TotalLength;\r
+  Ranges[0].Type = DefaultType;\r
+\r
+  //\r
+  // 1. Set WB\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 2. Set other types than WB or UC\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 3. Set UC\r
+  //\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
+      Status = MtrrLibSetMemoryType (\r
+        Ranges, RangeCapacity, RangeCount,\r
+        VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
 \r
 /**\r
-  This function attempts to set the attributes for a memory range.\r
+  Worker function attempts to set the attributes for a memory range.\r
 \r
-  @param  BaseAddress            The physical address that is the start\r
-                                 address of a memory region.\r
-  @param  Length                 The size in bytes of the memory region.\r
-  @param  Attributes             The bit mask of attributes to set for the\r
-                                 memory region.\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
+\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
 \r
   @retval RETURN_SUCCESS            The attributes were set for the memory\r
-                                    region.\r
+                                    range.\r
   @retval RETURN_INVALID_PARAMETER  Length is zero.\r
   @retval RETURN_UNSUPPORTED        The processor does not support one or\r
                                     more bytes of the memory resource range\r
-                                    specified by BaseAddress and Length.\r
-  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
-                                    for the memory resource range specified\r
-                                    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
+                                    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
 \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
+MtrrSetMemoryAttributeWorker (\r
+  IN OUT MTRR_SETTINGS           *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS            BaseAddress,\r
+  IN UINT64                      Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE      Type\r
   )\r
 {\r
-  UINT64                    TempQword;\r
   RETURN_STATUS             Status;\r
-  UINT64                    MemoryType;\r
-  UINT64                    Remainder;\r
-  BOOLEAN                   OverLap;\r
-  BOOLEAN                   Positive;\r
-  UINT32                    MsrNum;\r
-  UINTN                     MtrrNumber;\r
-  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
-  UINT32                    UsedMtrr;\r
+  UINT32                    Index;\r
+  UINT32                    WorkingIndex;\r
+  //\r
+  // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).\r
+  //\r
+  MEMORY_RANGE              Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];\r
+  UINT32                    RangeCount;\r
   UINT64                    MtrrValidBitsMask;\r
   UINT64                    MtrrValidAddressMask;\r
-  UINTN                     Cr4;\r
-  BOOLEAN                   OverwriteExistingMtrr;\r
-  UINT32                    FirmwareVariableMtrrCount;\r
-  UINT32                    VariableMtrrEnd;\r
-\r
-  if (!IsMtrrSupported ()) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
+  UINT64                    Alignment0;\r
+  MTRR_CONTEXT              MtrrContext;\r
+  BOOLEAN                   MtrrContextValid;\r
 \r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
-  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
+  MTRR_MEMORY_CACHE_TYPE    DefaultType;\r
 \r
-  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\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
 \r
-  TempQword = 0;\r
-  MemoryType = (UINT64)Attribute;\r
-  OverwriteExistingMtrr = FALSE;\r
+  UINT32                    FirmwareVariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
+  UINT32                    OriginalVariableMtrrCount;\r
+  VARIABLE_MTRR             OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT32                    WorkingVariableMtrrCount;\r
+  VARIABLE_MTRR             WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  BOOLEAN                   VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINTN                     FreeVariableMtrrCount;\r
 \r
-  //\r
-  // Check for an invalid parameter\r
-  //\r
   if (Length == 0) {\r
     return RETURN_INVALID_PARAMETER;\r
   }\r
 \r
-  if (\r
-       (BaseAddress &~MtrrValidAddressMask) != 0 ||\r
-       (Length &~MtrrValidAddressMask) != 0\r
-     ) {\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
     return RETURN_UNSUPPORTED;\r
   }\r
+  OriginalVariableMtrrCount = 0;\r
+  VariableSettings          = NULL;\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
 \r
   //\r
   // Check if Fixed MTRR\r
   //\r
-  Status = RETURN_SUCCESS;\r
-  while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
-    Cr4 = PreMtrrChange ();\r
-    Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
-    PostMtrrChange (Cr4);\r
-    if (RETURN_ERROR (Status)) {\r
-      return Status;\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
+      }\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
+      } 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
+      }\r
     }\r
-  }\r
 \r
-  if (Length == 0) {\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
-    //\r
-    goto Done;\r
+    if (Length == 0) {\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
+      //\r
+      goto Done;\r
+    }\r
   }\r
 \r
   //\r
-  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
-  // we can set the bade to 0 to save variable MTRRs.\r
+  // Read the default MTRR type\r
   //\r
-  if (BaseAddress == BASE_1MB) {\r
-    BaseAddress = 0;\r
-    Length += SIZE_1MB;\r
-  }\r
+  DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
 \r
   //\r
-  // Check memory base address alignment\r
+  // Read all variable MTRRs and convert to Ranges.\r
   //\r
-  DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);\r
-  if (Remainder != 0) {\r
-    DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);\r
-    if (Remainder != 0) {\r
-      Status = RETURN_UNSUPPORTED;\r
-      goto Done;\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
   }\r
+  MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);\r
+\r
+  Status = MtrrLibGetMemoryTypes (\r
+    DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,\r
+    Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount\r
+  );\r
+  ASSERT (Status == RETURN_SUCCESS);\r
+\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
+  ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
 \r
   //\r
-  // Check for overlap\r
+  // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
   //\r
-  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
-  OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
-  if (OverLap) {\r
-    Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
-    if (RETURN_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
+  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
+  ASSERT (Status == RETURN_SUCCESS);\r
+  //\r
+  // Apply Type to [BaseAddress, BaseAddress + Length)\r
+  //\r
+  Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
+  if (RETURN_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-    if (Length == 0) {\r
+  Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
+  WorkingVariableMtrrCount = 0;\r
+  ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    if (Ranges[Index].Type != DefaultType) {\r
       //\r
-      // Combined successfully\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 = RETURN_SUCCESS;\r
-      goto Done;\r
+      Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
+        Ranges, RangeCount,\r
+        WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,\r
+        Ranges[Index].BaseAddress, Ranges[Index].Length,\r
+        Ranges[Index].Type, Alignment0\r
+      );\r
+      if (RETURN_ERROR (Status)) {\r
+        return Status;\r
+      }\r
     }\r
   }\r
 \r
   //\r
-  // Program Variable MTRRs\r
-  //\r
-  // Avoid hardcode here and read data dynamically\r
+  // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
   //\r
-  if (UsedMtrr >= FirmwareVariableMtrrCount) {\r
-    Status = RETURN_OUT_OF_RESOURCES;\r
-    goto Done;\r
+  if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {\r
+    ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);\r
+    WorkingVariableMtrrCount--;\r
+    CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));\r
   }\r
 \r
-  //\r
-  // The memory type is the same with the type specified by\r
-  // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
-  //\r
-  if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {\r
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr(VariableMtrr);\r
-    goto Done;\r
+  if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
   }\r
 \r
-  TempQword = Length;\r
-\r
-\r
-  if (TempQword == Power2MaxMemory (TempQword)) {\r
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr(VariableMtrr);\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    VariableSettingModified[Index] = FALSE;\r
 \r
-    //\r
-    // Find first unused MTRR\r
-    //\r
-    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
-         MsrNum < VariableMtrrEnd;\r
-         MsrNum += 2\r
-        ) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    if (!OriginalVariableMtrr[Index].Valid) {\r
+      continue;\r
+    }\r
+    for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
+      if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&\r
+          OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&\r
+          OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {\r
         break;\r
       }\r
     }\r
 \r
-    ProgramVariableMtrr (\r
-      MsrNum,\r
-      BaseAddress,\r
-      Length,\r
-      MemoryType,\r
-      MtrrValidAddressMask\r
-      );\r
-  } else {\r
-\r
-    Positive = GetDirection (TempQword, &MtrrNumber);\r
-\r
-    if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
-      Status = RETURN_OUT_OF_RESOURCES;\r
-      goto Done;\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
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr(VariableMtrr);\r
-\r
     //\r
-    // Find first unused MTRR\r
+    // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.\r
     //\r
-    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
-         MsrNum < VariableMtrrEnd;\r
-         MsrNum += 2\r
-        ) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-        break;\r
-      }\r
-    }\r
-\r
-    if (!Positive) {\r
-      Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
-      ProgramVariableMtrr (\r
-        MsrNum,\r
-        BaseAddress,\r
-        Length,\r
-        MemoryType,\r
-        MtrrValidAddressMask\r
-        );\r
-      BaseAddress += Length;\r
-      TempQword   = Length - TempQword;\r
-      MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
-    }\r
+  }\r
 \r
-    do {\r
-      //\r
-      // Find unused MTRR\r
-      //\r
-      for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-        if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+  //\r
+  // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr\r
+  //\r
+  for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (!OriginalVariableMtrr[Index].Valid) {\r
+      for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
+        if (WorkingVariableMtrr[WorkingIndex].Valid) {\r
           break;\r
         }\r
       }\r
-\r
-      Length = Power2MaxMemory (TempQword);\r
-      if (!Positive) {\r
-        BaseAddress -= Length;\r
-      }\r
-\r
-      ProgramVariableMtrr (\r
-        MsrNum,\r
-        BaseAddress,\r
-        Length,\r
-        MemoryType,\r
-        MtrrValidAddressMask\r
-        );\r
-\r
-      if (Positive) {\r
-        BaseAddress += Length;\r
+      if (WorkingIndex == WorkingVariableMtrrCount) {\r
+        FreeVariableMtrrCount++;\r
+      } else {\r
+        CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
+        VariableSettingModified[Index] = TRUE;\r
+        WorkingIndex++;\r
       }\r
-      TempQword -= Length;\r
-\r
-    } while (TempQword > 0);\r
+    }\r
   }\r
+  ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
 \r
-Done:\r
-  return Status;\r
-\r
-}\r
-\r
-\r
-/**\r
-  This function will get the memory cache type of the specific address.\r
-\r
-  This function is mainly for debug purpose.\r
-\r
-  @param  Address   The specific address\r
-\r
-  @return Memory cache type of the sepcific address\r
-\r
-**/\r
-MTRR_MEMORY_CACHE_TYPE\r
-EFIAPI\r
-MtrrGetMemoryAttribute (\r
-  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
+  //\r
+  // Move MTRRs after the FirmwareVariableMtrrCount position to beginning\r
+  //\r
+  if (FirmwareVariableMtrrCount < OriginalVariableMtrrCount) {\r
+    WorkingIndex = FirmwareVariableMtrrCount;\r
+    for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+      if (!OriginalVariableMtrr[Index].Valid) {\r
+        //\r
+        // Found an empty MTRR in WorkingIndex position\r
+        //\r
+        for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
+          if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
+            break;\r
+          }\r
+        }\r
 \r
-  if (!IsMtrrSupported ()) {\r
-    return CacheUncacheable;\r
+        if (WorkingIndex != OriginalVariableMtrrCount) {\r
+          CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
+          VariableSettingModified[Index] = TRUE;\r
+          VariableSettingModified[WorkingIndex] = TRUE;\r
+          OriginalVariableMtrr[WorkingIndex].Valid = FALSE;\r
+        }\r
+      }\r
+    }\r
   }\r
 \r
   //\r
-  // Check if MTRR is enabled, if not, return UC as attribute\r
+  // Convert OriginalVariableMtrr to VariableSettings\r
+  // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
   //\r
-  TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
-  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (VariableSettingModified[Index]) {\r
+      if (OriginalVariableMtrr[Index].Valid) {\r
+        VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;\r
+        VariableSettings->Mtrr[Index].Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
+      } else {\r
+        VariableSettings->Mtrr[Index].Base = 0;\r
+        VariableSettings->Mtrr[Index].Mask = 0;\r
+      }\r
+    }\r
+  }\r
 \r
-  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-    return CacheUncacheable;\r
+Done:\r
+  if (MtrrSetting != NULL) {\r
+    ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;\r
+    return RETURN_SUCCESS;\r
   }\r
 \r
+  MtrrContextValid = FALSE;\r
   //\r
-  // If address is less than 1M, then try to go through the fixed MTRR\r
+  // Write fixed MTRRs that have been modified\r
   //\r
-  if (Address < BASE_1MB) {\r
-    if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
-      //\r
-      // Go through the fixed MTRR\r
-      //\r
-      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-         if (Address >= MtrrLibFixedMtrrTable[Index].BaseAddress &&\r
-             Address  < (\r
-                          MtrrLibFixedMtrrTable[Index].BaseAddress +\r
-                          (MtrrLibFixedMtrrTable[Index].Length * 8)\r
-                        )\r
-            ) {\r
-           SubIndex =\r
-             ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /\r
-               MtrrLibFixedMtrrTable[Index].Length;\r
-           TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
-           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
-           return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
-         }\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; 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
+        );\r
     }\r
   }\r
-  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
-  MtrrGetMemoryAttributeInVariableMtrr(\r
-    MtrrValidBitsMask,\r
-    MtrrValidAddressMask,\r
-    VariableMtrr\r
-    );\r
 \r
   //\r
-  // Go through the variable MTRR\r
+  // Write variable MTRRs\r
+  // When only fixed MTRRs were changed, below loop doesn't run\r
+  // because OriginalVariableMtrrCount equals to 0.\r
   //\r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
-  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
-\r
-  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-    if (VariableMtrr[Index].Valid) {\r
-      if (Address >= VariableMtrr[Index].BaseAddress &&\r
-          Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
-        TempMtrrType = VariableMtrr[Index].Type;\r
-        MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
+  for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
+    if (VariableSettingModified[Index]) {\r
+      if (!MtrrContextValid) {\r
+        MtrrLibPreMtrrChange (&MtrrContext);\r
+        MtrrContextValid = TRUE;\r
       }\r
+      AsmWriteMsr64 (\r
+        MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+        VariableSettings->Mtrr[Index].Base\r
+      );\r
+      AsmWriteMsr64 (\r
+        MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
+        VariableSettings->Mtrr[Index].Mask\r
+      );\r
     }\r
   }\r
-  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
+  if (MtrrContextValid) {\r
+    MtrrLibPostMtrrChange (&MtrrContext);\r
+  }\r
 \r
-  return CacheType;\r
+  return RETURN_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  This function will get the raw value in variable MTRRs\r
+  This function attempts to set the attributes for a memory range.\r
 \r
-  @param  VariableSettings   A buffer to hold variable 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]  Attributes         The bit mask of attributes to set for the\r
+                                 memory range.\r
 \r
-  @return The VariableSettings input pointer\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
-MTRR_VARIABLE_SETTINGS*\r
+RETURN_STATUS\r
 EFIAPI\r
-MtrrGetVariableMtrr (\r
-  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+MtrrSetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
   )\r
 {\r
-  UINT32  Index;\r
-  UINT32  VariableMtrrCount;\r
+  RETURN_STATUS              Status;\r
 \r
   if (!IsMtrrSupported ()) {\r
-    return VariableSettings;\r
+    return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
-  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\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
-  for (Index = 0; Index < VariableMtrrCount; Index++) {\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
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrsWorker (NULL);\r
   }\r
-\r
-  return  VariableSettings;\r
+  return Status;\r
 }\r
 \r
+/**\r
+  This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
+\r
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
+  @param[in]       BaseAddress  The physical address that is the start address\r
+                                of a memory range.\r
+  @param[in]       Length       The size in bytes of the memory range.\r
+  @param[in]       Attribute    The bit mask of attributes to set for the\r
+                                memory range.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory range.\r
+  @retval RETURN_INVALID_PARAMETER  Length is zero.\r
+  @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the\r
+                                    memory resource range specified by BaseAddress and Length.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource\r
+                                    range specified by BaseAddress and Length.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by\r
+                                    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
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttributeInMtrrSettings (\r
+  IN OUT MTRR_SETTINGS       *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  )\r
+{\r
+  RETURN_STATUS              Status;\r
+  Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",\r
+         MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
+\r
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
+  }\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   Worker function setting variable MTRRs\r
 \r
-  @param  VariableSettings   A buffer to hold variable MTRRs content.\r
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.\r
 \r
 **/\r
 VOID\r
@@ -1245,16 +2227,16 @@ MtrrSetVariableMtrrWorker (
   UINT32  Index;\r
   UINT32  VariableMtrrCount;\r
 \r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
 \r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
+      MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
       VariableSettings->Mtrr[Index].Base\r
       );\r
     AsmWriteMsr64 (\r
-      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
+      MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
       VariableSettings->Mtrr[Index].Mask\r
       );\r
   }\r
@@ -1264,7 +2246,7 @@ MtrrSetVariableMtrrWorker (
 /**\r
   This function sets variable MTRRs\r
 \r
-  @param  VariableSettings   A buffer to hold variable MTRRs content.\r
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.\r
 \r
   @return The pointer of VariableSettings\r
 \r
@@ -1275,51 +2257,24 @@ MtrrSetVariableMtrr (
   IN MTRR_VARIABLE_SETTINGS         *VariableSettings\r
   )\r
 {\r
-  UINTN  Cr4;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
   if (!IsMtrrSupported ()) {\r
     return VariableSettings;\r
   }\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  MtrrLibPreMtrrChange (&MtrrContext);\r
   MtrrSetVariableMtrrWorker (VariableSettings);\r
-  PostMtrrChange (Cr4);\r
-  return  VariableSettings;\r
-}\r
-\r
-\r
-/**\r
-  This function gets the content in fixed MTRRs\r
-\r
-  @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
-\r
-  @retval The pointer of FixedSettings\r
-\r
-**/\r
-MTRR_FIXED_SETTINGS*\r
-EFIAPI\r
-MtrrGetFixedMtrr (\r
-  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
-  )\r
-{\r
-  UINT32  Index;\r
+  MtrrLibPostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
 \r
-  if (!IsMtrrSupported ()) {\r
-    return FixedSettings;\r
-  }\r
-\r
-  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-      FixedSettings->Mtrr[Index] =\r
-        AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
-  };\r
-\r
-  return FixedSettings;\r
+  return  VariableSettings;\r
 }\r
 \r
 /**\r
   Worker function setting fixed MTRRs\r
 \r
-  @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.\r
 \r
 **/\r
 VOID\r
@@ -1331,7 +2286,7 @@ MtrrSetFixedMtrrWorker (
 \r
   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
      AsmWriteMsr64 (\r
-       MtrrLibFixedMtrrTable[Index].Msr,\r
+       mMtrrLibFixedMtrrTable[Index].Msr,\r
        FixedSettings->Mtrr[Index]\r
        );\r
   }\r
@@ -1341,7 +2296,7 @@ MtrrSetFixedMtrrWorker (
 /**\r
   This function sets fixed MTRRs\r
 \r
-  @param  FixedSettings  A buffer to hold fixed Mtrrs content.\r
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.\r
 \r
   @retval The pointer of FixedSettings\r
 \r
@@ -1352,15 +2307,16 @@ MtrrSetFixedMtrr (
   IN MTRR_FIXED_SETTINGS          *FixedSettings\r
   )\r
 {\r
-  UINTN  Cr4;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
   if (!IsMtrrSupported ()) {\r
     return FixedSettings;\r
   }\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  MtrrLibPreMtrrChange (&MtrrContext);\r
   MtrrSetFixedMtrrWorker (FixedSettings);\r
-  PostMtrrChange (Cr4);\r
+  MtrrLibPostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
 \r
   return FixedSettings;\r
 }\r
@@ -1369,7 +2325,7 @@ MtrrSetFixedMtrr (
 /**\r
   This function gets the content in all MTRRs (variable and fixed)\r
 \r
-  @param  MtrrSetting  A buffer to hold all Mtrrs content.\r
+  @param[out]  MtrrSetting  A buffer to hold all MTRRs content.\r
 \r
   @retval the pointer of MtrrSetting\r
 \r
@@ -1387,17 +2343,21 @@ MtrrGetAllMtrrs (
   //\r
   // Get fixed MTRRs\r
   //\r
-  MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
+  MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
 \r
   //\r
   // Get variable MTRRs\r
   //\r
-  MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
+  MtrrGetVariableMtrrWorker (\r
+    NULL,\r
+    GetVariableMtrrCountWorker (),\r
+    &MtrrSetting->Variables\r
+    );\r
 \r
   //\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
@@ -1406,7 +2366,7 @@ MtrrGetAllMtrrs (
 /**\r
   This function sets all MTRRs (variable and fixed)\r
 \r
-  @param  MtrrSetting  A buffer holding all MTRRs content.\r
+  @param[in]  MtrrSetting  A buffer holding all MTRRs content.\r
 \r
   @retval The pointer of MtrrSetting\r
 \r
@@ -1417,13 +2377,13 @@ MtrrSetAllMtrrs (
   IN MTRR_SETTINGS                *MtrrSetting\r
   )\r
 {\r
-  UINTN  Cr4;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
   if (!IsMtrrSupported ()) {\r
     return MtrrSetting;\r
   }\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  MtrrLibPreMtrrChange (&MtrrContext);\r
 \r
   //\r
   // Set fixed MTRRs\r
@@ -1438,54 +2398,14 @@ 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
-  PostMtrrChange (Cr4);\r
+  MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
 \r
   return MtrrSetting;\r
 }\r
 \r
 \r
-/**\r
-  This function prints all MTRRs for debugging.\r
-**/\r
-VOID\r
-MtrrDebugPrintAllMtrrs (\r
-  )\r
-{\r
-  DEBUG_CODE (\r
-    {\r
-      MTRR_SETTINGS  MtrrSettings;\r
-      UINTN          Index;\r
-      UINTN          VariableMtrrCount;\r
-\r
-      if (!IsMtrrSupported ()) {\r
-        return;\r
-      }\r
-\r
-      MtrrGetAllMtrrs (&MtrrSettings);\r
-      DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));\r
-      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-        DEBUG((\r
-          EFI_D_ERROR, "Fixed[%02d] = %016lx\n",\r
-          Index,\r
-          MtrrSettings.Fixed.Mtrr[Index]\r
-          ));\r
-      }\r
-\r
-      VariableMtrrCount = GetVariableMtrrCount ();\r
-      for (Index = 0; Index < VariableMtrrCount; Index++) {\r
-        DEBUG((\r
-          EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",\r
-          Index,\r
-          MtrrSettings.Variables.Mtrr[Index].Base,\r
-          MtrrSettings.Variables.Mtrr[Index].Mask\r
-          ));\r
-      }\r
-    }\r
-  );\r
-}\r
-\r
 /**\r
   Checks if MTRR is supported.\r
 \r
@@ -1499,26 +2419,26 @@ IsMtrrSupported (
   VOID\r
   )\r
 {\r
-  UINT32  RegEdx;\r
-  UINT64  MtrrCap;\r
+  CPUID_VERSION_INFO_EDX    Edx;\r
+  MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
 \r
   //\r
   // Check CPUID(1).EDX[12] for MTRR capability\r
   //\r
-  AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
-  if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
+  if (Edx.Bits.MTRR == 0) {\r
     return FALSE;\r
   }\r
 \r
   //\r
-  // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
-  // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
+  // Check number of variable MTRRs and fixed MTRRs existence.\r
+  // If number of variable MTRRs is zero, or fixed MTRRs do not\r
   // exist, return false.\r
   //\r
-  MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
-  if  ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
+  MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
+  if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
     return FALSE;\r
   }\r
-\r
   return TRUE;\r
 }\r
+\r