]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Fixed bug if length is less than Fixed-MTRR range
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index 0e76e2f92ad54822c9a00e8b0443fee771eae4f0..6a6bf765c2befbdaa1285bdb1bb1662d9f09411f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   MTRR setting library\r
 \r
-  Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\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 +20,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 +186,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 +223,7 @@ MtrrGetDefaultMemoryType (
   if (!IsMtrrSupported ()) {\r
     return CacheUncacheable;\r
   }\r
-  return MtrrGetDefaultMemoryTypeWorker ();\r
+  return MtrrGetDefaultMemoryTypeWorker (NULL);\r
 }\r
 \r
 /**\r
@@ -360,6 +373,12 @@ MtrrGetFixedMtrr (
 /**\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
@@ -367,6 +386,7 @@ MtrrGetFixedMtrr (
 **/\r
 MTRR_VARIABLE_SETTINGS*\r
 MtrrGetVariableMtrrWorker (\r
+  IN  MTRR_SETTINGS           *MtrrSetting,\r
   IN  UINT32                  VariableMtrrCount,\r
   OUT MTRR_VARIABLE_SETTINGS  *VariableSettings\r
   )\r
@@ -376,10 +396,15 @@ MtrrGetVariableMtrrWorker (
   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
+    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
@@ -404,6 +429,7 @@ MtrrGetVariableMtrr (
   }\r
 \r
   return MtrrGetVariableMtrrWorker (\r
+           NULL,\r
            GetVariableMtrrCountWorker (),\r
            VariableSettings\r
            );\r
@@ -415,7 +441,8 @@ MtrrGetVariableMtrr (
   @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[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
@@ -429,22 +456,22 @@ ProgramFixedMtrr (
   IN     UINT64               MemoryCacheType,\r
   IN OUT UINT64               *Base,\r
   IN OUT UINT64               *Length,\r
-  OUT    UINT32               *ReturnMsrNum,\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
@@ -457,44 +484,63 @@ 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
-  *ReturnMsrNum    = MsrNum;\r
+  *Length -= SubLength;\r
+  *Base   += SubLength;\r
+\r
+  *LastMsrNum      = MsrNum;\r
   *ReturnClearMask = ClearMask;\r
   *ReturnOrMask    = OrMask;\r
 \r
@@ -575,6 +621,7 @@ MtrrGetMemoryAttributeInVariableMtrr (
   }\r
 \r
   MtrrGetVariableMtrrWorker (\r
+    NULL,\r
     GetVariableMtrrCountWorker (),\r
     &VariableSettings\r
     );\r
@@ -949,6 +996,11 @@ ProgramVariableMtrr (
 /**\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
@@ -956,6 +1008,7 @@ ProgramVariableMtrr (
 **/\r
 MTRR_MEMORY_CACHE_TYPE\r
 GetMemoryCacheTypeFromMtrrType (\r
+  IN MTRR_SETTINGS         *MtrrSetting,\r
   IN UINT64                MtrrType\r
   )\r
 {\r
@@ -975,7 +1028,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
@@ -1084,21 +1137,22 @@ MtrrPrecedence (
   return MtrrType;\r
 }\r
 \r
-\r
-\r
 /**\r
-  This function will get the memory cache type of the specific address.\r
+  Worker function will get the memory cache type of the specific address.\r
 \r
-  This function is mainly for debug purpose.\r
+  If MtrrSetting is not NULL, gets the memory cache type from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
 \r
+  @param[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
 MTRR_MEMORY_CACHE_TYPE\r
-EFIAPI\r
-MtrrGetMemoryAttribute (\r
+MtrrGetMemoryAttributeByAddressWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting,\r
   IN PHYSICAL_ADDRESS   Address\r
   )\r
 {\r
@@ -1114,14 +1168,14 @@ MtrrGetMemoryAttribute (
   UINTN                   VariableMtrrCount;\r
   MTRR_VARIABLE_SETTINGS  VariableSettings;\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
+  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
   if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
@@ -1146,9 +1200,13 @@ MtrrGetMemoryAttribute (
            SubIndex =\r
              ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
                mMtrrLibFixedMtrrTable[Index].Length;\r
-           TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\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 (MtrrType);\r
+           return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
          }\r
       }\r
     }\r
@@ -1156,6 +1214,7 @@ MtrrGetMemoryAttribute (
   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
 \r
   MtrrGetVariableMtrrWorker (\r
+    MtrrSetting,\r
     GetVariableMtrrCountWorker (),\r
     &VariableSettings\r
     );\r
@@ -1183,24 +1242,52 @@ MtrrGetMemoryAttribute (
       }\r
     }\r
   }\r
-  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\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
-  This function prints all MTRRs for debugging.\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
-EFIAPI\r
-MtrrDebugPrintAllMtrrs (\r
-  VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
   )\r
 {\r
   DEBUG_CODE (\r
-    MTRR_SETTINGS  MtrrSettings;\r
+    MTRR_SETTINGS  LocalMtrrs;\r
+    MTRR_SETTINGS  *Mtrrs;\r
     UINTN          Index;\r
     UINTN          Index1;\r
     UINTN          VariableMtrrCount;\r
@@ -1224,18 +1311,24 @@ MtrrDebugPrintAllMtrrs (
     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
+    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, MtrrSettings.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
-        MtrrSettings.Variables.Mtrr[Index].Base,\r
-        MtrrSettings.Variables.Mtrr[Index].Mask\r
+        Mtrrs->Variables.Mtrr[Index].Base,\r
+        Mtrrs->Variables.Mtrr[Index].Mask\r
         ));\r
     }\r
     DEBUG((DEBUG_CACHE, "\n"));\r
@@ -1247,7 +1340,7 @@ MtrrDebugPrintAllMtrrs (
     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
+      MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
         if (MemoryType > CacheWriteBack) {\r
           MemoryType = MTRR_CACHE_INVALID_TYPE;\r
         }\r
@@ -1274,7 +1367,7 @@ MtrrDebugPrintAllMtrrs (
     Base = BASE_1MB;\r
     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
     do {\r
-      MemoryType = MtrrGetMemoryAttribute (Base);\r
+      MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
       if (MemoryType > CacheWriteBack) {\r
         MemoryType = MTRR_CACHE_INVALID_TYPE;\r
       }\r
@@ -1293,14 +1386,14 @@ MtrrDebugPrintAllMtrrs (
       NoRangeLimit = Limit;\r
 \r
       for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
-        if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {\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  = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
-        MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\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
@@ -1336,9 +1429,29 @@ MtrrDebugPrintAllMtrrs (
     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
-  This function attempts to set the attributes for a memory range.\r
+  Worker function attempts to set the attributes for a memory range.\r
 \r
+  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
@@ -1363,11 +1476,11 @@ MtrrDebugPrintAllMtrrs (
 \r
 **/\r
 RETURN_STATUS\r
-EFIAPI\r
-MtrrSetMemoryAttribute (\r
-  IN PHYSICAL_ADDRESS        BaseAddress,\r
-  IN UINT64                  Length,\r
-  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+MtrrSetMemoryAttributeWorker (\r
+  IN OUT MTRR_SETTINGS           *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS            BaseAddress,\r
+  IN UINT64                      Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE      Attribute\r
   )\r
 {\r
   UINT64                    TempQword;\r
@@ -1399,8 +1512,9 @@ MtrrSetMemoryAttribute (
   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
+  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
@@ -1439,19 +1553,25 @@ MtrrSetMemoryAttribute (
   //\r
   Status = RETURN_SUCCESS;\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 (!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
+      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
@@ -1479,10 +1599,14 @@ MtrrSetMemoryAttribute (
   //\r
   VariableMtrrCount = GetVariableMtrrCountWorker ();\r
   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
-  MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings);\r
-  CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
-  ProgramVariableSettings = TRUE;\r
-  VariableSettings = &WorkingVariableSettings;\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
@@ -1528,7 +1652,7 @@ 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
@@ -1698,11 +1822,98 @@ Done:
 \r
   DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
   if (!RETURN_ERROR (Status)) {\r
-    MtrrDebugPrintAllMtrrs ();\r
+    if (MtrrSetting != NULL) {\r
+      MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
+    }\r
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
   }\r
 \r
   return Status;\r
 }\r
+\r
+/**\r
+  This function attempts to set the attributes for a memory range.\r
+\r
+  @param[in]  BaseAddress        The physical address that is the start\r
+                                 address of a memory 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
+  @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
+  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 attempts to set the attributes into MTRR setting buffer for a memory range.\r
+\r
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
+  @param[in]       BaseAddress  The physical address that is the start address\r
+                                of a memory 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 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
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttributeInMtrrSettings (\r
+  IN OUT MTRR_SETTINGS       *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  )\r
+{\r
+  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
   Worker function setting variable MTRRs\r
 \r
@@ -1756,6 +1967,8 @@ MtrrSetVariableMtrr (
   PreMtrrChange (&MtrrContext);\r
   MtrrSetVariableMtrrWorker (VariableSettings);\r
   PostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
+\r
   return  VariableSettings;\r
 }\r
 \r
@@ -1804,6 +2017,7 @@ MtrrSetFixedMtrr (
   PreMtrrChange (&MtrrContext);\r
   MtrrSetFixedMtrrWorker (FixedSettings);\r
   PostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
 \r
   return FixedSettings;\r
 }\r
@@ -1836,6 +2050,7 @@ MtrrGetAllMtrrs (
   // Get variable MTRRs\r
   //\r
   MtrrGetVariableMtrrWorker (\r
+    NULL,\r
     GetVariableMtrrCountWorker (),\r
     &MtrrSetting->Variables\r
     );\r
@@ -1888,9 +2103,12 @@ MtrrSetAllMtrrs (
 \r
   PostMtrrChangeEnableCache (&MtrrContext);\r
 \r
+  MtrrDebugPrintAllMtrrs ();\r
+\r
   return MtrrSetting;\r
 }\r
 \r
+\r
 /**\r
   Checks if MTRR is supported.\r
 \r