]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Reduce hardware init when program fixed MTRRs
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index b1c12aa32e01026a4a2765b9f08a4bd13d51c39f..322f47b0976cfaedca2120042236de877586d9b2 100644 (file)
@@ -311,6 +311,103 @@ 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
+  @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  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
+    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
+}\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
+           GetVariableMtrrCountWorker (),\r
+           VariableSettings\r
+           );\r
+}\r
 \r
 /**\r
   Programs fixed MTRRs registers.\r
@@ -318,6 +415,9 @@ 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[out]     ReturnMsrNum     The 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,9 +426,12 @@ 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
+  OUT    UINT32               *ReturnMsrNum,\r
+  OUT    UINT64               *ReturnClearMask,\r
+  OUT    UINT64               *ReturnOrMask\r
   )\r
 {\r
   UINT32  MsrNum;\r
@@ -391,13 +494,58 @@ ProgramFixedMtrr (
     return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  TempQword =\r
-    (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
-  AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
+  *ReturnMsrNum    = 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
@@ -420,52 +568,32 @@ 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
+    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 +604,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 +655,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 +670,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 +684,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,21 +883,21 @@ GetMtrrNumberAndDirection (
   This function programs MTRRs according to the values specified\r
   in the shadow array.\r
 \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     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
     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
        AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
@@ -965,110 +1094,387 @@ MtrrPrecedence (
 }\r
 \r
 \r
+\r
 /**\r
-  This function attempts to set the attributes for a memory range.\r
+  This 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
+  This function is mainly for debug purpose.\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]  Address            The specific address\r
+\r
+  @return Memory cache type of the specific address\r
 \r
 **/\r
-RETURN_STATUS\r
+MTRR_MEMORY_CACHE_TYPE\r
 EFIAPI\r
-MtrrSetMemoryAttribute (\r
-  IN PHYSICAL_ADDRESS        BaseAddress,\r
-  IN UINT64                  Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+MtrrGetMemoryAttribute (\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
+    return CacheUncacheable;\r
   }\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
-\r
   //\r
-  // Check for an invalid parameter\r
+  // Check if MTRR is enabled, if not, return UC as attribute\r
   //\r
-  if (Length == 0) {\r
-    Status = RETURN_INVALID_PARAMETER;\r
-    goto Done;\r
-  }\r
+  TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
+  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
 \r
-  if (\r
-       (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
-       (Length & ~MtrrValidAddressMask) != 0\r
-     ) {\r
-    Status = RETURN_UNSUPPORTED;\r
-    goto Done;\r
+  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    return CacheUncacheable;\r
   }\r
 \r
   //\r
-  // Check if Fixed MTRR\r
+  // If address is less than 1M, then try to go through the 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 (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
+      }\r
     }\r
   }\r
+  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\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
-  }\r
+  MtrrGetVariableMtrrWorker (\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 (MtrrType);\r
+\r
+  return CacheType;\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
+  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
+  This function attempts to set the attributes for a memory range.\r
+\r
+  @param[in]       BaseAddress       The physical address that is the start\r
+                                     address of a memory region.\r
+  @param[in]       Length            The size in bytes of the memory region.\r
+  @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
+EFIAPI\r
+MtrrSetMemoryAttribute (\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
+  UINT32                    VariableMtrrEnd;\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
+  MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;\r
+  UINT32                    Index;\r
+  UINT64                    ClearMask;\r
+  UINT64                    OrMask;\r
+  UINT64                    NewValue;\r
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  MtrrContextValid = FALSE;\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    FixedSettingsValid[Index]    = FALSE;\r
+    FixedSettingsModified[Index] = FALSE;\r
+  }\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\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
+\r
+  //\r
+  // Check for an invalid parameter\r
+  //\r
+  if (Length == 0) {\r
+    Status = RETURN_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
+\r
+  if (\r
+       (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
+       (Length & ~MtrrValidAddressMask) != 0\r
+     ) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Check if Fixed MTRR\r
+  //\r
+  Status = RETURN_SUCCESS;\r
+  if (BaseAddress < BASE_1MB) {\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 (!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
+    if (Length == 0) {\r
+      //\r
+      // A Length of 0 can only make sense for fixed MTTR ranges.\r
+      // Since we just handled the fixed MTRRs, we can skip the\r
+      // variable MTRR section.\r
+      //\r
+      goto Done;\r
+    }\r
+  }\r
 \r
   //\r
   // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
@@ -1079,13 +1485,41 @@ MtrrSetMemoryAttribute (
     Length += SIZE_1MB;\r
   }\r
 \r
+  //\r
+  // Read all variable MTRRs\r
+  //\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings);\r
+  CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
+  VariableSettings = &WorkingVariableSettings;\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
+\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 +1528,7 @@ MtrrSetMemoryAttribute (
       //\r
       // Combined successfully, invalidate the now-unused MTRRs\r
       //\r
-      InvalidateMtrr(VariableMtrr);\r
+      InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
       Status = RETURN_SUCCESS;\r
       goto Done;\r
     }\r
@@ -1108,7 +1542,7 @@ MtrrSetMemoryAttribute (
     //\r
     // Invalidate the now-unused MTRRs\r
     //\r
-    InvalidateMtrr(VariableMtrr);\r
+    InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
     goto Done;\r
   }\r
 \r
@@ -1122,7 +1556,7 @@ MtrrSetMemoryAttribute (
   //\r
   // Invalidate the now-unused MTRRs\r
   //\r
-  InvalidateMtrr(VariableMtrr);\r
+  InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
 \r
   //\r
   // Find first unused MTRR\r
@@ -1195,196 +1629,68 @@ MtrrSetMemoryAttribute (
       );\r
     BaseAddress += Length;\r
     TempQword   = Length - TempQword;\r
-    MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
-  }\r
-\r
-  do {\r
-    //\r
-    // Find unused MTRR\r
-    //\r
-    for (; MsrNum < 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
-\r
-    ProgramVariableMtrr (\r
-      MsrNum,\r
-      BaseAddress,\r
-      Length,\r
-      MemoryType,\r
-      MtrrValidAddressMask\r
-      );\r
-\r
-    if (Positive) {\r
-      BaseAddress += Length;\r
-    }\r
-    TempQword -= Length;\r
-\r
-  } while (TempQword > 0);\r
-\r
-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
-  //\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
-      }\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
-  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
-\r
-  return CacheType;\r
-}\r
-\r
-\r
-/**\r
-  Worker 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
-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
-    VariableSettings->Mtrr[Index].Mask =\r
-      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
+    MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
   }\r
 \r
-  return  VariableSettings;\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
-/**\r
-  This function will get the raw value in variable MTRRs\r
+    Length = Power2MaxMemory (TempQword);\r
+    if (!Positive) {\r
+      BaseAddress -= Length;\r
+    }\r
 \r
-  @param[out]  VariableSettings   A buffer to hold variable MTRRs content.\r
+    ProgramVariableMtrr (\r
+      MsrNum,\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType,\r
+      MtrrValidAddressMask\r
+      );\r
 \r
-  @return The VariableSettings input pointer\r
+    if (Positive) {\r
+      BaseAddress += Length;\r
+    }\r
+    TempQword -= Length;\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
+  } while (TempQword > 0);\r
+\r
+Done:\r
+\r
+  //\r
+  // Write fixed MTRRs that have been modified\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
 \r
-  return MtrrGetVariableMtrrWorker (\r
-           VariableSettings\r
-           );\r
-}\r
+  if (MtrrContextValid) {\r
+    PostMtrrChange (&MtrrContext);\r
+  }\r
 \r
+  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
+  if (!RETURN_ERROR (Status)) {\r
+    MtrrDebugPrintAllMtrrs ();\r
+  }\r
 \r
+  return Status;\r
+}\r
 /**\r
   Worker function setting variable MTRRs\r
 \r
@@ -1399,7 +1705,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
@@ -1441,55 +1747,10 @@ MtrrSetVariableMtrr (
   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
-\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[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 +1772,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
@@ -1539,7 +1800,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 +1818,15 @@ 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
+    GetVariableMtrrCountWorker (),\r
+    &MtrrSetting->Variables\r
+    );\r
 \r
   //\r
   // Get MTRR_DEF_TYPE value\r
@@ -1615,153 +1879,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
 \r