]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Add worker functions not invoke IsMtrrSupported()
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index a95a72bfa3c8933b88be3f526cf7790b2e9bd930..b1c12aa32e01026a4a2765b9f08a4bd13d51c39f 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   MTRR setting library\r
 \r
-  Copyright (c) 2008 - 2010, Intel Corporation\r
-  All rights reserved. This program and the accompanying materials\r
+  Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
   http://opensource.org/licenses/bsd-license.php\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \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
 //\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
     0,\r
@@ -79,9 +86,41 @@ FIXED_MTRR    MtrrLibFixedMtrrTable[] = {
     MTRR_LIB_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
+  UINT32  VariableMtrrCount;\r
+\r
+  VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  return VariableMtrrCount;\r
+}\r
+\r
 /**\r
   Returns the variable MTRR count for the CPU.\r
 \r
@@ -89,11 +128,38 @@ FIXED_MTRR    MtrrLibFixedMtrrTable[] = {
 \r
 **/\r
 UINT32\r
+EFIAPI\r
 GetVariableMtrrCount (\r
   VOID\r
   )\r
 {\r
-  return (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
+  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 VariableMtrrCount - ReservedMtrrNumber;\r
 }\r
 \r
 /**\r
@@ -103,120 +169,155 @@ GetVariableMtrrCount (
 \r
 **/\r
 UINT32\r
+EFIAPI\r
 GetFirmwareVariableMtrrCount (\r
   VOID\r
   )\r
 {\r
-  return GetVariableMtrrCount () - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;\r
+  if (!IsMtrrSupported ()) {\r
+    return 0;\r
+  }\r
+  return GetFirmwareVariableMtrrCountWorker ();\r
 }\r
 \r
 /**\r
-  Returns the default MTRR cache type for the system.\r
+  Worker function 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
+MtrrGetDefaultMemoryTypeWorker (\r
   VOID\r
-)\r
+  )\r
 {\r
-  return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);\r
+  return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
 }\r
 \r
 \r
+/**\r
+  Returns the default MTRR cache type for the system.\r
+\r
+  @return  The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetDefaultMemoryType (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
+  return MtrrGetDefaultMemoryTypeWorker ();\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
+VOID\r
 PreMtrrChange (\r
-  VOID\r
+  OUT MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
-  UINTN  Value;\r
-\r
   //\r
-  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
+  // Disable interrupts and save current interrupt state\r
   //\r
-  Value = AsmReadCr0 ();\r
-  Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 1);\r
-  Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
-  AsmWriteCr0 (Value);\r
+  MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
+\r
   //\r
-  // Flush cache\r
+  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
   //\r
-  AsmWbinvd ();\r
+  AsmDisableCache ();\r
+\r
   //\r
-  // Clear PGE flag Bit 7\r
+  // Save original CR4 value and clear PGE flag (Bit 7)\r
   //\r
-  Value = AsmReadCr4 ();\r
-  AsmWriteCr4 ((UINTN) BitFieldWrite64 (Value, 7, 7, 0));\r
+  MtrrContext->Cr4 = AsmReadCr4 ();\r
+  AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
+\r
   //\r
   // Flush all TLBs\r
   //\r
   CpuFlushTlb ();\r
+\r
   //\r
-  // Disable Mtrrs\r
+  // Disable MTRRs\r
   //\r
   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
-\r
-  return Value;\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
+PostMtrrChangeEnableCache (\r
+  IN MTRR_CONTEXT  *MtrrContext\r
   )\r
 {\r
-  UINTN  Value;\r
+  //\r
+  // Flush all TLBs\r
+  //\r
+  CpuFlushTlb ();\r
 \r
   //\r
-  // Enable Cache MTRR\r
+  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
   //\r
-  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
+  AsmEnableCache ();\r
 \r
   //\r
-  // Flush all TLBs and cache the second time\r
+  // Restore original CR4 value\r
   //\r
-  AsmWbinvd ();\r
-  CpuFlushTlb ();\r
+  AsmWriteCr4 (MtrrContext->Cr4);\r
 \r
   //\r
-  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
+  // Restore original interrupt state\r
   //\r
-  Value = AsmReadCr0 ();\r
-  Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 0);\r
-  Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
-  AsmWriteCr0 (Value);\r
+  SetInterruptState (MtrrContext->InterruptState);\r
+}\r
 \r
-  AsmWriteCr4 (Cr4);\r
+/**\r
+  Cleaning up after programming MTRRs.\r
 \r
-  return ;\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
+PostMtrrChange (\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
+  PostMtrrChangeEnableCache (MtrrContext);\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]      MemoryCacheType  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
 \r
   @retval RETURN_SUCCESS      The cache type was updated successfully\r
   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
@@ -241,11 +342,11 @@ ProgramFixedMtrr (
   ClearMask = 0;\r
 \r
   for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
-    if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\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,8 +364,8 @@ ProgramFixedMtrr (
   for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
     if (*Base ==\r
          (\r
-           MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
-           (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)\r
+           mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+           (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
          )\r
        ) {\r
       break;\r
@@ -277,13 +378,13 @@ ProgramFixedMtrr (
 \r
   for (\r
         ;\r
-        ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));\r
+        ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[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
+    *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
+    *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
   }\r
 \r
   if (ByteShift < 8 && (*Length != 0)) {\r
@@ -291,58 +392,48 @@ ProgramFixedMtrr (
   }\r
 \r
   TempQword =\r
-    (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
-  AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
+    (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
+  AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
   return RETURN_SUCCESS;\r
 }\r
 \r
 \r
 /**\r
-  Get the attribute of variable MTRRs.\r
+  Gets the attribute of variable MTRRs.\r
 \r
-  This function shadows the content of variable MTRRs into\r
-  an internal array: VariableMtrr\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 since the base address in\r
-                                   MTRR must align to 4K, so valid address mask equal to\r
-                                   MtrrValidBitsMask & 0xfffffffffffff000ULL\r
-  @param  VariableMtrrCount        On input, it means the array number of variable MTRRs passed in.\r
-                                   On output, it means the number of MTRRs which has been used if EFI_SUCCESS,\r
-                                   or the number of MTRR required if BUFFER_TOO_SMALL.\r
-  @param  VariableMtrr             The array to shadow variable MTRRs content\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
-  @retval RETURN_SUCCESS           The variable MTRRs are returned.\r
-  @retval RETURN_BUFFER_TOO_SMALL  The input buffer is too small to hold the variable MTRRs.\r
+  @return                       The return value of this paramter indicates the\r
+                                number of MTRRs which has been used.\r
 \r
 **/\r
-RETURN_STATUS\r
+UINT32\r
 EFIAPI\r
 MtrrGetMemoryAttributeInVariableMtrr (\r
   IN  UINT64                    MtrrValidBitsMask,\r
   IN  UINT64                    MtrrValidAddressMask,\r
-  IN OUT UINT32                 *VariableMtrrCount,\r
   OUT VARIABLE_MTRR             *VariableMtrr\r
   )\r
 {\r
   UINTN   Index;\r
   UINT32  MsrNum;\r
   UINT32  UsedMtrr;\r
-  UINT  FirmwareVariableMtrrCount;\r
+  UINT32  FirmwareVariableMtrrCount;\r
   UINT32  VariableMtrrEnd;\r
 \r
-  //\r
-  // Check if input buffer is large enough\r
-  //\r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
-  if (*VariableMtrrCount < FirmwareVariableMtrrCount) {\r
-    *VariableMtrrCount = (UINT32)FirmwareVariableMtrrCount;\r
-    return RETURN_BUFFER_TOO_SMALL;\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) * (*VariableMtrrCount));\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
@@ -368,17 +459,16 @@ MtrrGetMemoryAttributeInVariableMtrr (
       Index++;\r
     }\r
   }\r
-  *VariableMtrrCount = UsedMtrr;\r
-  return RETURN_SUCCESS;\r
+  return UsedMtrr;\r
 }\r
 \r
 \r
 /**\r
   Checks overlap between given memory range and 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
+  @param[in]  Start                      The start address of memory range.\r
+  @param[in]  End                        The end address of memory range.\r
+  @param[in]  VariableMtrr               The array to shadow variable MTRRs content\r
 \r
   @retval TRUE             Overlap exists.\r
   @retval FALSE            No overlap.\r
@@ -414,9 +504,9 @@ CheckMemoryAttributeOverlap (
 /**\r
   Marks a variable MTRR as non-valid.\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[in]   Index         The index of the array VariableMtrr to be invalidated\r
+  @param[in]   VariableMtrr  The array to shadow variable MTRRs content\r
+  @param[out]  UsedMtrr      The number of MTRRs which has already been used\r
 \r
 **/\r
 VOID\r
@@ -432,16 +522,16 @@ InvalidateShadowMtrr (
 \r
 \r
 /**\r
-  Combine memory attributes.\r
+  Combines 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
+  @param[in]       Attributes                 The memory type to set.\r
+  @param[in, out]  Base                       The base address of memory range.\r
+  @param[in, out]  Length                     The length of memory range.\r
+  @param[in]       VariableMtrr               The array to shadow variable MTRRs content\r
+  @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used\r
+  @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used\r
 \r
   @retval EFI_SUCCESS            Memory region successfully combined.\r
   @retval EFI_ACCESS_DENIED      Memory region cannot be combined.\r
@@ -463,10 +553,12 @@ CombineMemoryAttribute (
   UINT64  MtrrEnd;\r
   UINT64  EndAddress;\r
   UINT32  FirmwareVariableMtrrCount;\r
+  BOOLEAN CoveredByExistingMtrr;\r
 \r
   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
 \r
   *OverwriteExistingMtrr = FALSE;\r
+  CoveredByExistingMtrr = FALSE;\r
   EndAddress = *Base +*Length - 1;\r
 \r
   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
@@ -487,11 +579,12 @@ CombineMemoryAttribute (
     //\r
     if (Attributes == VariableMtrr[Index].Type) {\r
       //\r
-      // if the Mtrr range contain the request range, return RETURN_SUCCESS\r
+      // if the MTRR range contain the request range, set a flag, then continue to\r
+      // invalidate any MTRR of the same request range with higher priority cache type.\r
       //\r
       if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
-        *Length = 0;\r
-        return RETURN_SUCCESS;\r
+        CoveredByExistingMtrr = TRUE;\r
+        continue;\r
       }\r
       //\r
       // invalid this MTRR, and program the combine range\r
@@ -538,14 +631,19 @@ CombineMemoryAttribute (
     return RETURN_ACCESS_DENIED;\r
   }\r
 \r
+  if (CoveredByExistingMtrr) {\r
+    *Length = 0;\r
+  }\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
 \r
 /**\r
-  Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
+  Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
+\r
+  @param[in]  MemoryLength        The number to pass in.\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
 \r
 **/\r
@@ -556,7 +654,7 @@ Power2MaxMemory (
 {\r
   UINT64  Result;\r
 \r
-  if (RShiftU64 (MemoryLength, 32)) {\r
+  if (RShiftU64 (MemoryLength, 32) != 0) {\r
     Result = LShiftU64 (\r
                (UINT64) GetPowerOfTwo32 (\r
                           (UINT32) RShiftU64 (MemoryLength, 32)\r
@@ -572,29 +670,60 @@ Power2MaxMemory (
 \r
 \r
 /**\r
-  Check the direction to program variable MTRRs.\r
+  Determines the MTRR numbers used to program a memory range.\r
+\r
+  This function first checks the alignment of the base address.\r
+  If the alignment of the base address <= Length, cover the memory range\r
+ (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
+  Length -= alignment. Repeat the step until alignment > Length.\r
 \r
-  This function determines which direction of programming the variable\r
-  MTRRs will use fewer MTRRs.\r
+  Then this function determines which direction of programming the variable\r
+  MTRRs for the remaining length will use fewer MTRRs.\r
 \r
-  @param  Input       Length of Memory to program MTRR\r
-  @param  MtrrNumber  Pointer to the number of necessary MTRRs\r
+  @param[in]  BaseAddress Length of Memory to program MTRR\r
+  @param[in]  Length      Length of Memory to program MTRR\r
+  @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs\r
 \r
   @retval TRUE        Positive direction is better.\r
-          FALSE       Negtive direction is better.\r
+          FALSE       Negative direction is better.\r
 \r
 **/\r
 BOOLEAN\r
-GetDirection (\r
-  IN UINT64      Input,\r
+GetMtrrNumberAndDirection (\r
+  IN UINT64      BaseAddress,\r
+  IN UINT64      Length,\r
   IN UINTN       *MtrrNumber\r
   )\r
 {\r
   UINT64  TempQword;\r
+  UINT64  Alignment;\r
   UINT32  Positive;\r
   UINT32  Subtractive;\r
 \r
-  TempQword   = Input;\r
+  *MtrrNumber = 0;\r
+\r
+  if (BaseAddress != 0) {\r
+    do {\r
+      //\r
+      // Calculate the alignment of the base address.\r
+      //\r
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+      if (Alignment > Length) {\r
+        break;\r
+      }\r
+\r
+      (*MtrrNumber)++;\r
+      BaseAddress += Alignment;\r
+      Length -= Alignment;\r
+    } while (TRUE);\r
+\r
+    if (Length == 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  TempQword   = Length;\r
   Positive    = 0;\r
   Subtractive = 0;\r
 \r
@@ -603,7 +732,7 @@ GetDirection (
     Positive++;\r
   } while (TempQword != 0);\r
 \r
-  TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\r
+  TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
   Subtractive++;\r
   do {\r
     TempQword -= Power2MaxMemory (TempQword);\r
@@ -611,10 +740,10 @@ GetDirection (
   } while (TempQword != 0);\r
 \r
   if (Positive <= Subtractive) {\r
-    *MtrrNumber = Positive;\r
+    *MtrrNumber += Positive;\r
     return TRUE;\r
   } else {\r
-    *MtrrNumber = Subtractive;\r
+    *MtrrNumber += Subtractive;\r
     return FALSE;\r
   }\r
 }\r
@@ -625,31 +754,30 @@ GetDirection (
   This function programs MTRRs according to the values specified\r
   in the shadow array.\r
 \r
-  @param  VariableMtrr   The array to shadow variable MTRRs content\r
+  @param[in, out]  VariableMtrr       Shadow of variable MTRR contents\r
 \r
 **/\r
-STATIC\r
 VOID\r
 InvalidateMtrr (\r
-   IN     VARIABLE_MTRR      *VariableMtrr\r
-   )\r
+  IN OUT VARIABLE_MTRR           *VariableMtrr\r
+  )\r
 {\r
-  UINTN Index;\r
-  UINTN Cr4;\r
-  UINTN VariableMtrrCount;\r
+  UINTN         Index;\r
+  UINTN         VariableMtrrCount;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  PreMtrrChange (&MtrrContext);\r
   Index = 0;\r
   VariableMtrrCount = GetVariableMtrrCount ();\r
   while (Index < VariableMtrrCount) {\r
-    if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
+    if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\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
+  PostMtrrChange (&MtrrContext);\r
 }\r
 \r
 \r
@@ -658,14 +786,13 @@ InvalidateMtrr (
 \r
   This function programs variable MTRRs\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
+  @param[in]       MtrrNumber            Index of MTRR to program.\r
+  @param[in]       BaseAddress           Base address of memory region.\r
+  @param[in]       Length                Length of memory region.\r
+  @param[in]       MemoryCacheType       Memory type to set.\r
+  @param[in]       MtrrValidAddressMask  The valid address mask for MTRR\r
 \r
 **/\r
-STATIC\r
 VOID\r
 ProgramVariableMtrr (\r
   IN UINTN                    MtrrNumber,\r
@@ -675,10 +802,10 @@ ProgramVariableMtrr (
   IN UINT64                   MtrrValidAddressMask\r
   )\r
 {\r
-  UINT64  TempQword;\r
-  UINTN   Cr4;\r
+  UINT64        TempQword;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  PreMtrrChange (&MtrrContext);\r
 \r
   //\r
   // MTRR Physical Base\r
@@ -695,19 +822,18 @@ ProgramVariableMtrr (
     (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
     );\r
 \r
-  PostMtrrChange (Cr4);\r
+  PostMtrrChange (&MtrrContext);\r
 }\r
 \r
 \r
 /**\r
-  Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
+  Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
 \r
-  @param  MtrrType  MTRR memory type\r
+  @param[in]  MtrrType           MTRR memory type\r
 \r
   @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
 \r
 **/\r
-STATIC\r
 MTRR_MEMORY_CACHE_TYPE\r
 GetMemoryCacheTypeFromMtrrType (\r
   IN UINT64                MtrrType\r
@@ -727,9 +853,9 @@ GetMemoryCacheTypeFromMtrrType (
   default:\r
     //\r
     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
-    // no mtrr covers the range\r
+    // no MTRR covers the range\r
     //\r
-    return CacheUncacheable;\r
+    return MtrrGetDefaultMemoryType ();\r
   }\r
 }\r
 \r
@@ -738,19 +864,18 @@ GetMemoryCacheTypeFromMtrrType (
 \r
   This function initializes the valid bits mask and valid address mask for MTRRs.\r
 \r
-  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
-  @param  MtrrValidAddressMask  The valid address mask for the MTRR\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
-STATIC\r
 VOID\r
 MtrrLibInitializeMtrrMask (\r
   OUT UINT64 *MtrrValidBitsMask,\r
   OUT UINT64 *MtrrValidAddressMask\r
   )\r
 {\r
-  UINT32                              RegEax;\r
-  UINT8                               PhysicalAddressBits;\r
+  UINT32  RegEax;\r
+  UINT8   PhysicalAddressBits;\r
 \r
   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
 \r
@@ -762,28 +887,28 @@ MtrrLibInitializeMtrrMask (
     *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;\r
     *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
   } else {\r
-    *MtrrValidBitsMask    = MTRR_LIB_CACHE_VALID_ADDRESS;\r
-    *MtrrValidAddressMask = 0xFFFFFFFF;\r
+    *MtrrValidBitsMask    = MTRR_LIB_MSR_VALID_MASK;\r
+    *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
   }\r
 }\r
 \r
 \r
 /**\r
-  Determing the real attribute of a memory range.\r
+  Determines the real attribute of a memory range.\r
 \r
   This function is to arbitrate the real attribute of the memory when\r
-  there are 2 MTRR covers the same memory range.  For further details,\r
+  there are 2 MTRRs covers the same memory range.  For further details,\r
   please refer the IA32 Software Developer's Manual, Volume 3,\r
   Section 10.11.4.1.\r
 \r
-  @param  MtrrType1    the first kind of Memory type\r
-  @param  MtrrType2    the second kind of memory type\r
+  @param[in]  MtrrType1    The first kind of Memory type\r
+  @param[in]  MtrrType2    The second kind of memory type\r
 \r
 **/\r
 UINT64\r
 MtrrPrecedence (\r
-  UINT64    MtrrType1,\r
-  UINT64    MtrrType2\r
+  IN UINT64    MtrrType1,\r
+  IN UINT64    MtrrType2\r
   )\r
 {\r
   UINT64 MtrrType;\r
@@ -843,11 +968,11 @@ MtrrPrecedence (
 /**\r
   This 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
+  @param[in]       BaseAddress       The physical address that is the start\r
+                                     address of a memory region.\r
+  @param[in]       Length            The size in bytes of the memory region.\r
+  @param[in]       Attribute         The bit mask of attributes to set for the\r
+                                     memory region.\r
 \r
   @retval RETURN_SUCCESS            The attributes were set for the memory\r
                                     region.\r
@@ -877,19 +1002,26 @@ MtrrSetMemoryAttribute (
   UINT64                    TempQword;\r
   RETURN_STATUS             Status;\r
   UINT64                    MemoryType;\r
-  UINT64                    Remainder;\r
+  UINT64                    Alignment;\r
   BOOLEAN                   OverLap;\r
   BOOLEAN                   Positive;\r
   UINT32                    MsrNum;\r
   UINTN                     MtrrNumber;\r
-  VARIABLE_MTRR             VariableMtrr[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
   UINT32                    UsedMtrr;\r
   UINT64                    MtrrValidBitsMask;\r
   UINT64                    MtrrValidAddressMask;\r
-  UINTN                     Cr4;\r
   BOOLEAN                   OverwriteExistingMtrr;\r
   UINT32                    FirmwareVariableMtrrCount;\r
   UINT32                    VariableMtrrEnd;\r
+  MTRR_CONTEXT              MtrrContext;\r
+\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
 \r
   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
   VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
@@ -904,14 +1036,16 @@ MtrrSetMemoryAttribute (
   // Check for an invalid parameter\r
   //\r
   if (Length == 0) {\r
-    return RETURN_INVALID_PARAMETER;\r
+    Status = RETURN_INVALID_PARAMETER;\r
+    goto Done;\r
   }\r
 \r
   if (\r
-       (BaseAddress &~MtrrValidAddressMask) != 0 ||\r
-       (Length &~MtrrValidAddressMask) != 0\r
+       (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
+       (Length & ~MtrrValidAddressMask) != 0\r
      ) {\r
-    return RETURN_UNSUPPORTED;\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
   }\r
 \r
   //\r
@@ -919,11 +1053,11 @@ MtrrSetMemoryAttribute (
   //\r
   Status = RETURN_SUCCESS;\r
   while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
-    Cr4 = PreMtrrChange ();\r
+    PreMtrrChange (&MtrrContext);\r
     Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
-    PostMtrrChange (Cr4);\r
+    PostMtrrChange (&MtrrContext);\r
     if (RETURN_ERROR (Status)) {\r
-      return Status;\r
+      goto Done;\r
     }\r
   }\r
 \r
@@ -938,30 +1072,17 @@ MtrrSetMemoryAttribute (
 \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
+  // we can set the base to 0 to save variable MTRRs.\r
   //\r
   if (BaseAddress == BASE_1MB) {\r
     BaseAddress = 0;\r
     Length += SIZE_1MB;\r
   }\r
 \r
-  //\r
-  // Check memory base address alignment\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
-  }\r
-\r
   //\r
   // Check for overlap\r
   //\r
-  UsedMtrr = MAX_MTRR_NUMBER_OF_VARIABLE_MTRR;\r
-  MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, &UsedMtrr, VariableMtrr);\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
@@ -971,28 +1092,19 @@ MtrrSetMemoryAttribute (
 \r
     if (Length == 0) {\r
       //\r
-      // Combined successfully\r
+      // Combined successfully, invalidate the now-unused MTRRs\r
       //\r
+      InvalidateMtrr(VariableMtrr);\r
       Status = RETURN_SUCCESS;\r
       goto Done;\r
     }\r
   }\r
 \r
-  //\r
-  // Program Variable MTRRs\r
-  //\r
-  // Avoid hardcode here and read data dynamically\r
-  //\r
-  if (UsedMtrr >= FirmwareVariableMtrrCount) {\r
-    Status = RETURN_OUT_OF_RESOURCES;\r
-    goto Done;\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
+  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
     //\r
     // Invalidate the now-unused MTRRs\r
     //\r
@@ -1000,22 +1112,75 @@ MtrrSetMemoryAttribute (
     goto Done;\r
   }\r
 \r
-  TempQword = Length;\r
+  Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
 \r
+  if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
+    Status = RETURN_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
 \r
-  if (TempQword == Power2MaxMemory (TempQword)) {\r
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr(VariableMtrr);\r
+  //\r
+  // Invalidate the now-unused MTRRs\r
+  //\r
+  InvalidateMtrr(VariableMtrr);\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
+      break;\r
+    }\r
+  }\r
+\r
+  if (BaseAddress != 0) {\r
+    do {\r
+      //\r
+      // Calculate the alignment of the base address.\r
+      //\r
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+      if (Alignment > Length) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Find unused MTRR\r
+      //\r
+      for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
+        if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      ProgramVariableMtrr (\r
+        MsrNum,\r
+        BaseAddress,\r
+        Alignment,\r
+        MemoryType,\r
+        MtrrValidAddressMask\r
+        );\r
+      BaseAddress += Alignment;\r
+      Length -= Alignment;\r
+    } while (TRUE);\r
+\r
+    if (Length == 0) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  TempQword = Length;\r
+\r
+  if (!Positive) {\r
+    Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
 \r
     //\r
-    // Find first unused MTRR\r
+    // Find unused MTRR\r
     //\r
-    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
-         MsrNum < VariableMtrrEnd;\r
-         MsrNum += 2\r
-        ) {\r
+    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
@@ -1028,80 +1193,48 @@ MtrrSetMemoryAttribute (
       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
-    }\r
-\r
-    //\r
-    // Invalidate the now-unused MTRRs\r
-    //\r
-    InvalidateMtrr(VariableMtrr);\r
+    BaseAddress += Length;\r
+    TempQword   = Length - TempQword;\r
+    MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
+  }\r
 \r
+  do {\r
     //\r
-    // Find first unused MTRR\r
+    // Find unused MTRR\r
     //\r
-    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
-         MsrNum < VariableMtrrEnd;\r
-         MsrNum += 2\r
-        ) {\r
+    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
     }\r
 \r
+    Length = Power2MaxMemory (TempQword);\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
+      BaseAddress -= Length;\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
-          break;\r
-        }\r
-      }\r
-\r
-      Length = Power2MaxMemory (TempQword);\r
-      if (!Positive) {\r
-        BaseAddress -= Length;\r
-      }\r
+    ProgramVariableMtrr (\r
+      MsrNum,\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType,\r
+      MtrrValidAddressMask\r
+      );\r
 \r
-      ProgramVariableMtrr (\r
-        MsrNum,\r
-        BaseAddress,\r
-        Length,\r
-        MemoryType,\r
-        MtrrValidAddressMask\r
-        );\r
+    if (Positive) {\r
+      BaseAddress += Length;\r
+    }\r
+    TempQword -= Length;\r
 \r
-      if (Positive) {\r
-        BaseAddress += Length;\r
-      }\r
-      TempQword -= Length;\r
+  } while (TempQword > 0);\r
 \r
-    } while (TempQword > 0);\r
+Done:\r
+  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrs ();\r
   }\r
 \r
-Done:\r
   return Status;\r
-\r
 }\r
 \r
 \r
@@ -1110,9 +1243,9 @@ Done:
 \r
   This function is mainly for debug purpose.\r
 \r
-  @param  Address   The specific address\r
+  @param[in]  Address            The specific address\r
 \r
-  @return Memory cache type of the sepcific address\r
+  @return Memory cache type of the specific address\r
 \r
 **/\r
 MTRR_MEMORY_CACHE_TYPE\r
@@ -1127,11 +1260,14 @@ MtrrGetMemoryAttribute (
   UINT64                  MtrrType;\r
   UINT64                  TempMtrrType;\r
   MTRR_MEMORY_CACHE_TYPE  CacheType;\r
-  VARIABLE_MTRR           VariableMtrr[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
   UINT64                  MtrrValidBitsMask;\r
   UINT64                  MtrrValidAddressMask;\r
   UINTN                   VariableMtrrCount;\r
-  UINT32                  UsedMtrr;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
 \r
   //\r
   // Check if MTRR is enabled, if not, return UC as attribute\r
@@ -1152,16 +1288,16 @@ MtrrGetMemoryAttribute (
       // Go through the fixed MTRR\r
       //\r
       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
-         if (Address >= MtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+         if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
              Address  < (\r
-                          MtrrLibFixedMtrrTable[Index].BaseAddress +\r
-                          (MtrrLibFixedMtrrTable[Index].Length * 8)\r
+                          mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
+                          (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
                         )\r
             ) {\r
            SubIndex =\r
-             ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /\r
-               MtrrLibFixedMtrrTable[Index].Length;\r
-           TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
+             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+               mMtrrLibFixedMtrrTable[Index].Length;\r
+           TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
            MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
            return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
          }\r
@@ -1169,11 +1305,9 @@ MtrrGetMemoryAttribute (
     }\r
   }\r
   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
-  UsedMtrr = MAX_MTRR_NUMBER_OF_VARIABLE_MTRR;\r
   MtrrGetMemoryAttributeInVariableMtrr(\r
     MtrrValidBitsMask,\r
     MtrrValidAddressMask,\r
-    &UsedMtrr,\r
     VariableMtrr\r
     );\r
 \r
@@ -1181,6 +1315,8 @@ MtrrGetMemoryAttribute (
   // Go through the variable MTRR\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
@@ -1197,23 +1333,24 @@ MtrrGetMemoryAttribute (
 \r
 \r
 /**\r
-  This function will get the raw value in variable MTRRs\r
+  Worker function will get the raw value in variable MTRRs\r
 \r
-  @param  VariableSettings   A buffer to hold variable MTRRs content.\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
+MtrrGetVariableMtrrWorker (\r
+  OUT MTRR_VARIABLE_SETTINGS  *VariableSettings\r
   )\r
 {\r
   UINT32  Index;\r
   UINT32  VariableMtrrCount;\r
 \r
   VariableMtrrCount = GetVariableMtrrCount ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
   for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     VariableSettings->Mtrr[Index].Base =\r
       AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
@@ -1224,11 +1361,34 @@ MtrrGetVariableMtrr (
   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
+           VariableSettings\r
+           );\r
+}\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
@@ -1240,6 +1400,8 @@ MtrrSetVariableMtrrWorker (
   UINT32  VariableMtrrCount;\r
 \r
   VariableMtrrCount = GetVariableMtrrCount ();\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
@@ -1256,7 +1418,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
@@ -1267,26 +1429,28 @@ 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
+  PreMtrrChange (&MtrrContext);\r
   MtrrSetVariableMtrrWorker (VariableSettings);\r
-  PostMtrrChange (Cr4);\r
+  PostMtrrChange (&MtrrContext);\r
   return  VariableSettings;\r
 }\r
 \r
-\r
 /**\r
-  This function gets the content in fixed MTRRs\r
+  Worker function gets the content in fixed MTRRs\r
 \r
-  @param  FixedSettings  A buffer to hold fixed Mtrrs content.\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
+MtrrGetFixedMtrrWorker (\r
   OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
   )\r
 {\r
@@ -1294,16 +1458,38 @@ MtrrGetFixedMtrr (
 \r
   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
       FixedSettings->Mtrr[Index] =\r
-        AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
-  };\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
   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
@@ -1315,7 +1501,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
@@ -1325,7 +1511,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
@@ -1336,11 +1522,15 @@ MtrrSetFixedMtrr (
   IN MTRR_FIXED_SETTINGS          *FixedSettings\r
   )\r
 {\r
-  UINTN  Cr4;\r
+  MTRR_CONTEXT  MtrrContext;\r
 \r
-  Cr4 = PreMtrrChange ();\r
+  if (!IsMtrrSupported ()) {\r
+    return FixedSettings;\r
+  }\r
+\r
+  PreMtrrChange (&MtrrContext);\r
   MtrrSetFixedMtrrWorker (FixedSettings);\r
-  PostMtrrChange (Cr4);\r
+  PostMtrrChange (&MtrrContext);\r
 \r
   return FixedSettings;\r
 }\r
@@ -1349,7 +1539,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
@@ -1360,6 +1550,10 @@ MtrrGetAllMtrrs (
   OUT MTRR_SETTINGS                *MtrrSetting\r
   )\r
 {\r
+  if (!IsMtrrSupported ()) {\r
+    return MtrrSetting;\r
+  }\r
+\r
   //\r
   // Get fixed MTRRs\r
   //\r
@@ -1382,7 +1576,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
@@ -1393,9 +1587,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
+  PreMtrrChange (&MtrrContext);\r
 \r
   //\r
   // Set fixed MTRRs\r
@@ -1412,45 +1610,191 @@ MtrrSetAllMtrrs (
   //\r
   AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
 \r
-  PostMtrrChange (Cr4);\r
+  PostMtrrChangeEnableCache (&MtrrContext);\r
 \r
   return MtrrSetting;\r
 }\r
 \r
-\r
 /**\r
   This function prints all MTRRs for debugging.\r
 **/\r
 VOID\r
+EFIAPI\r
 MtrrDebugPrintAllMtrrs (\r
+  VOID\r
   )\r
 {\r
   DEBUG_CODE (\r
-    {\r
-      MTRR_SETTINGS  MtrrSettings;\r
-      UINTN          Index;\r
-      UINTN          VariableMtrrCount;\r
+    MTRR_SETTINGS  MtrrSettings;\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
-      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
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+    DEBUG((DEBUG_CACHE, "=============\n"));\r
+\r
+    MtrrGetAllMtrrs (&MtrrSettings);\r
+    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));\r
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));\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
+    VariableMtrrCount = GetVariableMtrrCount ();\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+        Index,\r
+        MtrrSettings.Variables.Mtrr[Index].Base,\r
+        MtrrSettings.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 (MtrrSettings.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 = MtrrGetMemoryAttribute (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 ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+          //\r
+          // If mask is not valid, then do not display range\r
+          //\r
+          continue;\r
+        }\r
+        MtrrBase  = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
+        MtrrLimit = MtrrBase + ((~(MtrrSettings.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
+  Checks if MTRR is supported.\r
+\r
+  @retval TRUE  MTRR is supported.\r
+  @retval FALSE MTRR is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsMtrrSupported (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  RegEdx;\r
+  UINT64  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
+    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
+  // 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
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r