]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg: Fix typos in comments
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index b1c12aa32e01026a4a2765b9f08a4bd13d51c39f..7783b63d8267e222e2e060d2de5f43b88628e1c1 100644 (file)
@@ -1,7 +1,11 @@
 /** @file\r
   MTRR setting library\r
 \r
-  Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\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 - 2016, 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
@@ -20,6 +24,9 @@
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \r
+#define OR_SEED      0x0101010101010101ull\r
+#define CLEAR_SEED   0xFFFFFFFFFFFFFFFFull\r
+\r
 //\r
 // Context to save and restore when MTRRs are programmed\r
 //\r
@@ -183,15 +190,25 @@ GetFirmwareVariableMtrrCount (
 /**\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
-  VOID\r
+  IN MTRR_SETTINGS      *MtrrSetting\r
   )\r
 {\r
-  return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
+  if (MtrrSetting == NULL) {\r
+    return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
+  } else {\r
+    return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
+  }\r
 }\r
 \r
 \r
@@ -210,7 +227,7 @@ MtrrGetDefaultMemoryType (
   if (!IsMtrrSupported ()) {\r
     return CacheUncacheable;\r
   }\r
-  return MtrrGetDefaultMemoryTypeWorker ();\r
+  return MtrrGetDefaultMemoryTypeWorker (NULL);\r
 }\r
 \r
 /**\r
@@ -311,6 +328,116 @@ PostMtrrChange (
   PostMtrrChangeEnableCache (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 (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
+    } 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
@@ -318,6 +445,10 @@ PostMtrrChange (
   @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
+  @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
@@ -326,22 +457,25 @@ PostMtrrChange (
 **/\r
 RETURN_STATUS\r
 ProgramFixedMtrr (\r
-  IN     UINT64     MemoryCacheType,\r
-  IN OUT UINT64     *Base,\r
-  IN OUT UINT64     *Length\r
+  IN     UINT64               MemoryCacheType,\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
+  //\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
@@ -354,50 +488,114 @@ ProgramFixedMtrr (
     }\r
   }\r
 \r
-  if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
+  if (MsrNum >= MTRR_NUMBER_OF_FIXED_MTRR) {\r
     return RETURN_UNSUPPORTED;\r
   }\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
-           mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
-           (ByteShift * mMtrrLibFixedMtrrTable[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 >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
-        ByteShift++\r
-      ) {\r
-    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
-    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
-    *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
-    *Base += mMtrrLibFixedMtrrTable[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
-  if (ByteShift < 8 && (*Length != 0)) {\r
-    return RETURN_UNSUPPORTED;\r
+  ClearMask = CLEAR_SEED;\r
+  OrMask    = MultU64x32 (OR_SEED, (UINT32)MemoryCacheType);\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 (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 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
-  AsmWriteMsr64 (mMtrrLibFixedMtrrTable[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
+  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[in]   VariableSettings           The variable MTRR values to shadow\r
+  @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware\r
+  @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR\r
+  @param[in]   MtrrValidAddressMask       The valid address mask for MTRR\r
+  @param[out]  VariableMtrr               The array to shadow variable MTRRs content\r
+\r
+  @return                       The return value of this parameter indicates the\r
+                                number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN  UINTN                   FirmwareVariableMtrrCount,\r
+  IN  UINT64                  MtrrValidBitsMask,\r
+  IN  UINT64                  MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR           *VariableMtrr\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT32  UsedMtrr;\r
+\r
+  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+    if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
+      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
+}\r
+\r
+\r
 /**\r
   Gets the attribute of variable MTRRs.\r
 \r
@@ -408,7 +606,7 @@ ProgramFixedMtrr (
   @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
+  @return                       The return value of this parameter indicates the\r
                                 number of MTRRs which has been used.\r
 \r
 **/\r
@@ -420,52 +618,33 @@ MtrrGetMemoryAttributeInVariableMtrr (
   OUT VARIABLE_MTRR             *VariableMtrr\r
   )\r
 {\r
-  UINTN   Index;\r
-  UINT32  MsrNum;\r
-  UINT32  UsedMtrr;\r
-  UINT32  FirmwareVariableMtrrCount;\r
-  UINT32  VariableMtrrEnd;\r
+  MTRR_VARIABLE_SETTINGS  VariableSettings;\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
+  MtrrGetVariableMtrrWorker (\r
+    NULL,\r
+    GetVariableMtrrCountWorker (),\r
+    &VariableSettings\r
+    );\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
-    }\r
-  }\r
-  return UsedMtrr;\r
+  return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+           &VariableSettings,\r
+           GetFirmwareVariableMtrrCountWorker (),\r
+           MtrrValidBitsMask,\r
+           MtrrValidAddressMask,\r
+           VariableMtrr\r
+           );\r
 }\r
 \r
 \r
 /**\r
   Checks overlap between given memory range and MTRRs.\r
 \r
+  @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available\r
+                                         to firmware.\r
   @param[in]  Start                      The start address of memory range.\r
   @param[in]  End                        The end address of memory range.\r
   @param[in]  VariableMtrr               The array to shadow variable MTRRs content\r
@@ -476,14 +655,15 @@ MtrrGetMemoryAttributeInVariableMtrr (
 **/\r
 BOOLEAN\r
 CheckMemoryAttributeOverlap (\r
-  IN PHYSICAL_ADDRESS     Start,\r
-  IN PHYSICAL_ADDRESS     End,\r
-  IN VARIABLE_MTRR      *VariableMtrr\r
+  IN UINTN             FirmwareVariableMtrrCount,\r
+  IN PHYSICAL_ADDRESS  Start,\r
+  IN PHYSICAL_ADDRESS  End,\r
+  IN VARIABLE_MTRR     *VariableMtrr\r
   )\r
 {\r
   UINT32  Index;\r
 \r
-  for (Index = 0; Index < 6; Index++) {\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
     if (\r
          VariableMtrr[Index].Valid &&\r
          !(\r
@@ -526,6 +706,8 @@ InvalidateShadowMtrr (
 \r
   If overlap exists between given memory range and MTRRs, try to combine them.\r
 \r
+  @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs\r
+                                              available to firmware.\r
   @param[in]       Attributes                 The memory type to set.\r
   @param[in, out]  Base                       The base address of memory range.\r
   @param[in, out]  Length                     The length of memory range.\r
@@ -539,6 +721,7 @@ InvalidateShadowMtrr (
 **/\r
 RETURN_STATUS\r
 CombineMemoryAttribute (\r
+  IN     UINT32             FirmwareVariableMtrrCount,\r
   IN     UINT64             Attributes,\r
   IN OUT UINT64             *Base,\r
   IN OUT UINT64             *Length,\r
@@ -552,11 +735,8 @@ CombineMemoryAttribute (
   UINT64  CombineEnd;\r
   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
@@ -754,30 +934,27 @@ GetMtrrNumberAndDirection (
   This function programs MTRRs according to the values specified\r
   in the shadow array.\r
 \r
+  @param[in, out]  VariableSettings   Variable MTRR settings\r
+  @param[in]       VariableMtrrCount  Number of variable MTRRs\r
   @param[in, out]  VariableMtrr       Shadow of variable MTRR contents\r
 \r
 **/\r
 VOID\r
 InvalidateMtrr (\r
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN     UINTN                   VariableMtrrCount,\r
   IN OUT VARIABLE_MTRR           *VariableMtrr\r
   )\r
 {\r
   UINTN         Index;\r
-  UINTN         VariableMtrrCount;\r
-  MTRR_CONTEXT  MtrrContext;\r
 \r
-  PreMtrrChange (&MtrrContext);\r
-  Index = 0;\r
-  VariableMtrrCount = GetVariableMtrrCount ();\r
-  while (Index < VariableMtrrCount) {\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
+       VariableSettings->Mtrr[Index].Base = 0;\r
+       VariableSettings->Mtrr[Index].Mask = 0;\r
        VariableMtrr[Index].Used = FALSE;\r
     }\r
-    Index ++;\r
   }\r
-  PostMtrrChange (&MtrrContext);\r
 }\r
 \r
 \r
@@ -786,6 +963,7 @@ InvalidateMtrr (
 \r
   This function programs variable MTRRs\r
 \r
+  @param[in, out]  VariableSettings      Variable MTRR settings.\r
   @param[in]       MtrrNumber            Index of MTRR to program.\r
   @param[in]       BaseAddress           Base address of memory region.\r
   @param[in]       Length                Length of memory region.\r
@@ -795,40 +973,38 @@ InvalidateMtrr (
 **/\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
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN     UINTN                   MtrrNumber,\r
+  IN     PHYSICAL_ADDRESS        BaseAddress,\r
+  IN     UINT64                  Length,\r
+  IN     UINT64                  MemoryCacheType,\r
+  IN     UINT64                  MtrrValidAddressMask\r
   )\r
 {\r
   UINT64        TempQword;\r
-  MTRR_CONTEXT  MtrrContext;\r
-\r
-  PreMtrrChange (&MtrrContext);\r
 \r
   //\r
   // MTRR Physical Base\r
   //\r
   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
-  AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
+  VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
 \r
   //\r
   // MTRR Physical Mask\r
   //\r
   TempQword = ~(Length - 1);\r
-  AsmWriteMsr64 (\r
-    (UINT32) (MtrrNumber + 1),\r
-    (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
-    );\r
-\r
-  PostMtrrChange (&MtrrContext);\r
+  VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
 }\r
 \r
 \r
 /**\r
   Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
 \r
+  If MtrrSetting is not NULL, gets the default memory attribute from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
+\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
   @param[in]  MtrrType           MTRR memory type\r
 \r
   @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
@@ -836,6 +1012,7 @@ ProgramVariableMtrr (
 **/\r
 MTRR_MEMORY_CACHE_TYPE\r
 GetMemoryCacheTypeFromMtrrType (\r
+  IN MTRR_SETTINGS         *MtrrSetting,\r
   IN UINT64                MtrrType\r
   )\r
 {\r
@@ -855,7 +1032,7 @@ GetMemoryCacheTypeFromMtrrType (
     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
     // no MTRR covers the range\r
     //\r
-    return MtrrGetDefaultMemoryType ();\r
+    return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
   }\r
 }\r
 \r
@@ -964,79 +1141,406 @@ MtrrPrecedence (
   return MtrrType;\r
 }\r
 \r
-\r
 /**\r
-  This function attempts to set the attributes for a memory range.\r
+  Worker function will get the memory cache type of the specific address.\r
 \r
-  @param[in]       BaseAddress       The physical address that is the start\r
-                                     address of a memory region.\r
-  @param[in]       Length            The size in bytes of the memory region.\r
-  @param[in]       Attribute         The bit mask of attributes to set for the\r
-                                     memory region.\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
-  @retval RETURN_SUCCESS            The attributes were set for the memory\r
-                                    region.\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
+  @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
-RETURN_STATUS\r
-EFIAPI\r
-MtrrSetMemoryAttribute (\r
-  IN PHYSICAL_ADDRESS        BaseAddress,\r
-  IN UINT64                  Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetMemoryAttributeByAddressWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS   Address\r
   )\r
 {\r
-  UINT64                    TempQword;\r
-  RETURN_STATUS             Status;\r
-  UINT64                    MemoryType;\r
-  UINT64                    Alignment;\r
-  BOOLEAN                   OverLap;\r
-  BOOLEAN                   Positive;\r
-  UINT32                    MsrNum;\r
-  UINTN                     MtrrNumber;\r
-  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
-  UINT32                    UsedMtrr;\r
-  UINT64                    MtrrValidBitsMask;\r
-  UINT64                    MtrrValidAddressMask;\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
+  UINT64                  TempQword;\r
+  UINTN                   Index;\r
+  UINTN                   SubIndex;\r
+  UINT64                  MtrrType;\r
+  UINT64                  TempMtrrType;\r
+  MTRR_MEMORY_CACHE_TYPE  CacheType;\r
+  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT64                  MtrrValidBitsMask;\r
+  UINT64                  MtrrValidAddressMask;\r
+  UINTN                   VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS  VariableSettings;\r
 \r
-  if (!IsMtrrSupported ()) {\r
-    Status = RETURN_UNSUPPORTED;\r
-    goto Done;\r
+  //\r
+  // Check if MTRR is enabled, if not, return UC as attribute\r
+  //\r
+  if (MtrrSetting == NULL) {\r
+    TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
+  } else {\r
+    TempQword = MtrrSetting->MtrrDefType;\r
   }\r
+  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
 \r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
-  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
-\r
-  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
-\r
-  TempQword = 0;\r
-  MemoryType = (UINT64)Attribute;\r
-  OverwriteExistingMtrr = FALSE;\r
+  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    return CacheUncacheable;\r
+  }\r
 \r
   //\r
-  // Check for an invalid parameter\r
+  // If address is less than 1M, then try to go through the fixed MTRR\r
   //\r
-  if (Length == 0) {\r
-    Status = RETURN_INVALID_PARAMETER;\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 >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+             Address  < (\r
+                          mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
+                          (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
+                        )\r
+            ) {\r
+           SubIndex =\r
+             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+               mMtrrLibFixedMtrrTable[Index].Length;\r
+           if (MtrrSetting == NULL) {\r
+             TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
+           } else {\r
+             TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
+           }\r
+           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
+           return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+         }\r
+      }\r
+    }\r
+  }\r
+  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+  MtrrGetVariableMtrrWorker (\r
+    MtrrSetting,\r
+    GetVariableMtrrCountWorker (),\r
+    &VariableSettings\r
+    );\r
+\r
+  MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+           &VariableSettings,\r
+           GetFirmwareVariableMtrrCountWorker (),\r
+           MtrrValidBitsMask,\r
+           MtrrValidAddressMask,\r
+           VariableMtrr\r
+           );\r
+\r
+  //\r
+  // Go through the variable MTRR\r
+  //\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  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
+      }\r
+    }\r
+  }\r
+  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+\r
+  return CacheType;\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[in]  Address   The specific address\r
+\r
+  @return Memory cache type of the specific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS   Address\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
+\r
+  return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
+}\r
+\r
+/**\r
+  Worker function prints all MTRRs for debugging.\r
+\r
+  If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
+  settings buffer.\r
+  If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+  @param  MtrrSetting    A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
+  )\r
+{\r
+  DEBUG_CODE (\r
+    MTRR_SETTINGS  LocalMtrrs;\r
+    MTRR_SETTINGS  *Mtrrs;\r
+    UINTN          Index;\r
+    UINTN          Index1;\r
+    UINTN          VariableMtrrCount;\r
+    UINT64         Base;\r
+    UINT64         Limit;\r
+    UINT64         MtrrBase;\r
+    UINT64         MtrrLimit;\r
+    UINT64         RangeBase;\r
+    UINT64         RangeLimit;\r
+    UINT64         NoRangeBase;\r
+    UINT64         NoRangeLimit;\r
+    UINT32         RegEax;\r
+    UINTN          MemoryType;\r
+    UINTN          PreviousMemoryType;\r
+    BOOLEAN        Found;\r
+\r
+    if (!IsMtrrSupported ()) {\r
+      return;\r
+    }\r
+\r
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+    DEBUG((DEBUG_CACHE, "=============\n"));\r
+\r
+    if (MtrrSetting != NULL) {\r
+      Mtrrs = MtrrSetting;\r
+    } else {\r
+      MtrrGetAllMtrrs (&LocalMtrrs);\r
+      Mtrrs = &LocalMtrrs;\r
+    }\r
+\r
+    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
+    }\r
+\r
+    VariableMtrrCount = GetVariableMtrrCount ();\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+        Index,\r
+        Mtrrs->Variables.Mtrr[Index].Base,\r
+        Mtrrs->Variables.Mtrr[Index].Mask\r
+        ));\r
+    }\r
+    DEBUG((DEBUG_CACHE, "\n"));\r
+    DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
+    DEBUG((DEBUG_CACHE, "====================================\n"));\r
+\r
+    Base = 0;\r
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
+      for (Index1 = 0; Index1 < 8; Index1++) {\r
+      MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
+        if (MemoryType > CacheWriteBack) {\r
+          MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+        }\r
+        if (MemoryType != PreviousMemoryType) {\r
+          if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+            DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+          }\r
+          PreviousMemoryType = MemoryType;\r
+          DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+        }\r
+        Base += mMtrrLibFixedMtrrTable[Index].Length;\r
+      }\r
+    }\r
+    DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+\r
+    VariableMtrrCount = GetVariableMtrrCount ();\r
+\r
+    Limit        = BIT36 - 1;\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000008) {\r
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+      Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
+    }\r
+    Base = BASE_1MB;\r
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+    do {\r
+      MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
+      if (MemoryType > CacheWriteBack) {\r
+        MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+      }\r
+\r
+      if (MemoryType != PreviousMemoryType) {\r
+        if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+          DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+        }\r
+        PreviousMemoryType = MemoryType;\r
+        DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+      }\r
+\r
+      RangeBase    = BASE_1MB;\r
+      NoRangeBase  = BASE_1MB;\r
+      RangeLimit   = Limit;\r
+      NoRangeLimit = Limit;\r
+\r
+      for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
+        if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+          //\r
+          // If mask is not valid, then do not display range\r
+          //\r
+          continue;\r
+        }\r
+        MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
+        MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
+\r
+        if (Base >= MtrrBase && Base < MtrrLimit) {\r
+          Found = TRUE;\r
+        }\r
+\r
+        if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
+          RangeBase = MtrrBase;\r
+        }\r
+        if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
+          RangeBase = MtrrLimit + 1;\r
+        }\r
+        if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
+          RangeLimit = MtrrBase - 1;\r
+        }\r
+        if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
+          RangeLimit = MtrrLimit;\r
+        }\r
+\r
+        if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
+          NoRangeBase = MtrrLimit + 1;\r
+        }\r
+        if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
+          NoRangeLimit = MtrrBase - 1;\r
+        }\r
+      }\r
+\r
+      if (Found) {\r
+        Base = RangeLimit + 1;\r
+      } else {\r
+        Base = NoRangeLimit + 1;\r
+      }\r
+    } while (Base < Limit);\r
+    DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
+  );\r
+}\r
+\r
+\r
+/**\r
+  This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+EFIAPI\r
+MtrrDebugPrintAllMtrrs (\r
+  VOID\r
+  )\r
+{\r
+  MtrrDebugPrintAllMtrrsWorker (NULL);\r
+}\r
+\r
+\r
+/**\r
+  Worker function attempts to set the attributes for a memory range.\r
+\r
+  If MtrrSettings is not NULL, set the attributes into the input MTRR\r
+  settings buffer.\r
+  If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
+\r
+  @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.\r
+  @param[in]       BaseAddress       The physical address that is the start\r
+                                     address of a memory region.\r
+  @param[in]       Length            The size in bytes of the memory region.\r
+  @param[in]       Attribute         The bit mask of attributes to set for the\r
+                                     memory region.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory\r
+                                    region.\r
+  @retval RETURN_INVALID_PARAMETER  Length is zero.\r
+  @retval RETURN_UNSUPPORTED        The processor does not support one or\r
+                                    more bytes of the memory resource range\r
+                                    specified by BaseAddress and Length.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
+                                    for the memory resource range specified\r
+                                    by BaseAddress and Length.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource\r
+                                    range specified by BaseAddress and Length\r
+                                    cannot be modified.\r
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
+                                    modify the attributes of the memory\r
+                                    resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+MtrrSetMemoryAttributeWorker (\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
+  UINT64                    TempQword;\r
+  RETURN_STATUS             Status;\r
+  UINT64                    MemoryType;\r
+  UINT64                    Alignment;\r
+  BOOLEAN                   OverLap;\r
+  BOOLEAN                   Positive;\r
+  UINT32                    MsrNum;\r
+  UINTN                     MtrrNumber;\r
+  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT32                    UsedMtrr;\r
+  UINT64                    MtrrValidBitsMask;\r
+  UINT64                    MtrrValidAddressMask;\r
+  BOOLEAN                   OverwriteExistingMtrr;\r
+  UINT32                    FirmwareVariableMtrrCount;\r
+  MTRR_CONTEXT              MtrrContext;\r
+  BOOLEAN                   MtrrContextValid;\r
+  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
+  UINT32                    VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
+  BOOLEAN                   ProgramVariableSettings;\r
+  MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;\r
+  UINT32                    Index;\r
+  UINT64                    ClearMask;\r
+  UINT64                    OrMask;\r
+  UINT64                    NewValue;\r
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+\r
+  MtrrContextValid  = FALSE;\r
+  VariableMtrrCount = 0;\r
+  ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    FixedSettingsValid[Index]    = FALSE;\r
+    FixedSettingsModified[Index] = FALSE;\r
+  }\r
+  ProgramVariableSettings = FALSE;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+  TempQword = 0;\r
+  MemoryType = (UINT64)Attribute;\r
+  OverwriteExistingMtrr = FALSE;\r
+\r
+  //\r
+  // Check for an invalid parameter\r
+  //\r
+  if (Length == 0) {\r
+    Status = RETURN_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
 \r
@@ -1052,22 +1556,37 @@ MtrrSetMemoryAttribute (
   // Check if Fixed MTRR\r
   //\r
   Status = RETURN_SUCCESS;\r
-  while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
-    PreMtrrChange (&MtrrContext);\r
-    Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
-    PostMtrrChange (&MtrrContext);\r
-    if (RETURN_ERROR (Status)) {\r
-      goto Done;\r
+  if (BaseAddress < BASE_1MB) {\r
+    MsrNum = (UINT32)-1;\r
+    while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
+      Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
+      if (RETURN_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      if (MtrrSetting != NULL) {\r
+        MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+        MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
+      } else {\r
+        if (!FixedSettingsValid[MsrNum]) {\r
+          WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
+          FixedSettingsValid[MsrNum] = TRUE;\r
+        }\r
+        NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+        if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
+          WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
+          FixedSettingsModified[MsrNum] = TRUE;\r
+        }\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
@@ -1079,13 +1598,46 @@ MtrrSetMemoryAttribute (
     Length += SIZE_1MB;\r
   }\r
 \r
+  //\r
+  // Read all variable MTRRs\r
+  //\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
+  if (MtrrSetting != NULL) {\r
+    VariableSettings = &MtrrSetting->Variables;\r
+  } else {\r
+    MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
+    CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
+    ProgramVariableSettings = TRUE;\r
+    VariableSettings = &WorkingVariableSettings;\r
+  }\r
+\r
   //\r
   // Check for overlap\r
   //\r
-  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
-  OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
+  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+               VariableSettings,\r
+               FirmwareVariableMtrrCount,\r
+               MtrrValidBitsMask,\r
+               MtrrValidAddressMask,\r
+               VariableMtrr\r
+               );\r
+  OverLap = CheckMemoryAttributeOverlap (\r
+              FirmwareVariableMtrrCount,\r
+              BaseAddress,\r
+              BaseAddress + Length - 1,\r
+              VariableMtrr\r
+              );\r
   if (OverLap) {\r
-    Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
+    Status = CombineMemoryAttribute (\r
+               FirmwareVariableMtrrCount,\r
+               MemoryType,\r
+               &BaseAddress,\r
+               &Length,\r
+               VariableMtrr,\r
+               &UsedMtrr,\r
+               &OverwriteExistingMtrr\r
+               );\r
     if (RETURN_ERROR (Status)) {\r
       goto Done;\r
     }\r
@@ -1094,7 +1646,7 @@ MtrrSetMemoryAttribute (
       //\r
       // Combined successfully, invalidate the now-unused MTRRs\r
       //\r
-      InvalidateMtrr(VariableMtrr);\r
+      InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
       Status = RETURN_SUCCESS;\r
       goto Done;\r
     }\r
@@ -1104,11 +1656,11 @@ MtrrSetMemoryAttribute (
   // The memory type is the same with the type specified by\r
   // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
   //\r
-  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
+  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {\r
     //\r
     // Invalidate the now-unused MTRRs\r
     //\r
-    InvalidateMtrr(VariableMtrr);\r
+    InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
     goto Done;\r
   }\r
 \r
@@ -1122,16 +1674,13 @@ MtrrSetMemoryAttribute (
   //\r
   // Invalidate the now-unused MTRRs\r
   //\r
-  InvalidateMtrr(VariableMtrr);\r
+  InvalidateMtrr (VariableSettings, VariableMtrrCount, 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
+  for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
+    if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
       break;\r
     }\r
   }\r
@@ -1150,13 +1699,14 @@ MtrrSetMemoryAttribute (
       //\r
       // Find unused MTRR\r
       //\r
-      for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-        if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+      for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+        if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
           break;\r
         }\r
       }\r
 \r
       ProgramVariableMtrr (\r
+        VariableSettings,\r
         MsrNum,\r
         BaseAddress,\r
         Alignment,\r
@@ -1180,13 +1730,14 @@ MtrrSetMemoryAttribute (
     //\r
     // Find unused MTRR\r
     //\r
-    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
     }\r
 \r
     ProgramVariableMtrr (\r
+      VariableSettings,\r
       MsrNum,\r
       BaseAddress,\r
       Length,\r
@@ -1202,8 +1753,8 @@ MtrrSetMemoryAttribute (
     //\r
     // Find unused MTRR\r
     //\r
-    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
     }\r
@@ -1214,6 +1765,7 @@ MtrrSetMemoryAttribute (
     }\r
 \r
     ProgramVariableMtrr (\r
+      VariableSettings,\r
       MsrNum,\r
       BaseAddress,\r
       Length,\r
@@ -1229,162 +1781,143 @@ MtrrSetMemoryAttribute (
   } while (TempQword > 0);\r
 \r
 Done:\r
-  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
-  if (!RETURN_ERROR (Status)) {\r
-    MtrrDebugPrintAllMtrrs ();\r
-  }\r
-\r
-  return Status;\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[in]  Address            The specific address\r
-\r
-  @return Memory cache type of the specific 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
-  if (!IsMtrrSupported ()) {\r
-    return CacheUncacheable;\r
-  }\r
-\r
-  //\r
-  // Check if MTRR is enabled, if not, return UC as attribute\r
-  //\r
-  TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
-  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
-\r
-  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
-    return CacheUncacheable;\r
-  }\r
 \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 >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
-             Address  < (\r
-                          mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
-                          (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
-                        )\r
-            ) {\r
-           SubIndex =\r
-             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
-               mMtrrLibFixedMtrrTable[Index].Length;\r
-           TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[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
+        PreMtrrChange (&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
-  //\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
+  }\r
+\r
+  //\r
+  // Write variable MTRRs\r
+  //\r
+  if (ProgramVariableSettings) {\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
+          WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {\r
+        if (!MtrrContextValid) {\r
+          PreMtrrChange (&MtrrContext);\r
+          MtrrContextValid = TRUE;\r
+        }\r
+        AsmWriteMsr64 (\r
+          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
+          WorkingVariableSettings.Mtrr[Index].Base\r
+          );\r
+        AsmWriteMsr64 (\r
+          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
+          WorkingVariableSettings.Mtrr[Index].Mask\r
+          );\r
       }\r
     }\r
   }\r
-  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
+  if (MtrrContextValid) {\r
+    PostMtrrChange (&MtrrContext);\r
+  }\r
+\r
+  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
+  if (!RETURN_ERROR (Status)) {\r
+    if (MtrrSetting != NULL) {\r
+      MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
+    }\r
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
+  }\r
 \r
-  return CacheType;\r
+  return Status;\r
 }\r
 \r
-\r
 /**\r
-  Worker function will get the raw value in variable MTRRs\r
+  This function attempts to set the attributes for a memory range.\r
 \r
-  @param[out] VariableSettings   A buffer to hold variable MTRRs content.\r
+  @param[in]  BaseAddress        The physical address that is the start\r
+                                 address of a memory region.\r
+  @param[in]  Length             The size in bytes of the memory region.\r
+  @param[in]  Attributes         The bit mask of attributes to set for the\r
+                                 memory region.\r
 \r
-  @return The VariableSettings input pointer\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory\r
+                                    region.\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
-MtrrGetVariableMtrrWorker (\r
-  OUT MTRR_VARIABLE_SETTINGS  *VariableSettings\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
   )\r
 {\r
-  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
-    VariableSettings->Mtrr[Index].Mask =\r
-      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
-  }\r
-\r
-  return  VariableSettings;\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  return MtrrSetMemoryAttributeWorker (\r
+           NULL,\r
+           BaseAddress,\r
+           Length,\r
+           Attribute\r
+           );\r
 }\r
 \r
 /**\r
-  This function will get the raw value in variable MTRRs\r
+  This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
 \r
-  @param[out]  VariableSettings   A buffer to hold variable MTRRs content.\r
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
+  @param[in]       BaseAddress  The physical address that is the start address\r
+                                of a memory region.\r
+  @param[in]       Length       The size in bytes of the memory region.\r
+  @param[in]       Attribute    The bit mask of attributes to set for the\r
+                                memory region.\r
 \r
-  @return The VariableSettings input pointer\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory region.\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
-MTRR_VARIABLE_SETTINGS*\r
+RETURN_STATUS\r
 EFIAPI\r
-MtrrGetVariableMtrr (\r
-  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\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
-  if (!IsMtrrSupported ()) {\r
-    return VariableSettings;\r
-  }\r
-\r
-  return MtrrGetVariableMtrrWorker (\r
-           VariableSettings\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  return MtrrSetMemoryAttributeWorker (\r
+           MtrrSetting,\r
+           BaseAddress,\r
+           Length,\r
+           Attribute\r
            );\r
 }\r
 \r
-\r
 /**\r
   Worker function setting variable MTRRs\r
 \r
@@ -1399,7 +1932,7 @@ 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
@@ -1438,58 +1971,15 @@ MtrrSetVariableMtrr (
   PreMtrrChange (&MtrrContext);\r
   MtrrSetVariableMtrrWorker (VariableSettings);\r
   PostMtrrChange (&MtrrContext);\r
-  return  VariableSettings;\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
+  MtrrDebugPrintAllMtrrs ();\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
+  return  VariableSettings;\r
 }\r
 \r
 /**\r
   Worker function setting fixed MTRRs\r
 \r
-  @param[in]  FixedSettings  A buffer to hold fixed Mtrrs content.\r
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.\r
 \r
 **/\r
 VOID\r
@@ -1511,7 +2001,7 @@ MtrrSetFixedMtrrWorker (
 /**\r
   This function sets fixed MTRRs\r
 \r
-  @param[in]  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
@@ -1531,6 +2021,7 @@ MtrrSetFixedMtrr (
   PreMtrrChange (&MtrrContext);\r
   MtrrSetFixedMtrrWorker (FixedSettings);\r
   PostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
 \r
   return FixedSettings;\r
 }\r
@@ -1539,7 +2030,7 @@ MtrrSetFixedMtrr (
 /**\r
   This function gets the content in all MTRRs (variable and fixed)\r
 \r
-  @param[out]  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
@@ -1557,12 +2048,16 @@ 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
@@ -1615,152 +2110,6 @@ MtrrSetAllMtrrs (
   return MtrrSetting;\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
-    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
-    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((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