]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFspPkg/Library/BaseCacheLib/CacheLib.c
Add IntelFspPkg to support create FSP bin based on EDKII.
[mirror_edk2.git] / IntelFspPkg / Library / BaseCacheLib / CacheLib.c
diff --git a/IntelFspPkg/Library/BaseCacheLib/CacheLib.c b/IntelFspPkg/Library/BaseCacheLib/CacheLib.c
new file mode 100644 (file)
index 0000000..aaaeb8b
--- /dev/null
@@ -0,0 +1,749 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/CacheLib.h>\r
+#include <Library/CacheAsRamLib.h>\r
+#include "CacheLibInternal.h"\r
+\r
+/**\r
+  Calculate the maximum value which is a power of 2, but less the Input.\r
+\r
+  @param[in]  Input        The number to pass in.\r
+  @return The maximum value which is align to power of 2 and less the Input\r
+**/\r
+UINT32\r
+SetPower2 (\r
+  IN  UINT32                    Input\r
+  );\r
+\r
+/**\r
+  Search the memory cache type for specific memory from MTRR.\r
+\r
+  @param[in]  MemoryAddress         the address of target memory\r
+  @param[in]  MemoryLength          the length of target memory\r
+  @param[in]  ValidMtrrAddressMask  the MTRR address mask\r
+  @param[out] UsedMsrNum            the used MSR number\r
+  @param[out] UsedMemoryCacheType   the cache type for the target memory\r
+\r
+  @retval EFI_SUCCESS    The memory is found in MTRR and cache type is returned\r
+  @retval EFI_NOT_FOUND  The memory is not found in MTRR\r
+\r
+**/\r
+EFI_STATUS\r
+SearchForExactMtrr (\r
+  IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,\r
+  IN  UINT64                    MemoryLength,\r
+  IN  UINT64                    ValidMtrrAddressMask,\r
+  OUT UINT32                    *UsedMsrNum,\r
+  OUT EFI_MEMORY_CACHE_TYPE     *MemoryCacheType\r
+  );\r
+\r
+/**\r
+  Check if CacheType match current default setting.\r
+\r
+  @param[in] MemoryCacheType  input cache type to be checked.\r
+\r
+  @retval TRUE MemoryCacheType is default MTRR setting.\r
+  @retval TRUE MemoryCacheType is NOT default MTRR setting.\r
+**/\r
+BOOLEAN\r
+IsDefaultType (\r
+  IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType\r
+  );\r
+\r
+/**\r
+  Return MTRR alignment requirement for base address and size.\r
+\r
+  @param[in]  BaseAddress     Base address.\r
+  @param[in]  Size            Size.\r
+\r
+  @retval Zero      Alligned.\r
+  @retval Non-Zero  Not alligned.\r
+\r
+**/\r
+UINT32\r
+CheckMtrrAlignment (\r
+  IN  UINT64                    BaseAddress,\r
+  IN  UINT64                    Size\r
+  );\r
+\r
+typedef struct {\r
+  UINT32    Msr;\r
+  UINT32    BaseAddress;\r
+  UINT32    Length;\r
+} EFI_FIXED_MTRR;\r
+\r
+EFI_FIXED_MTRR mFixedMtrrTable[] = {\r
+  { EFI_MSR_IA32_MTRR_FIX64K_00000, 0,       0x10000},\r
+  { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000},\r
+  { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_C0000,  0xC0000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_C8000,  0xC8000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_D0000,  0xD0000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_D8000,  0xD8000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_E0000,  0xE0000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_E8000,  0xE8000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_F0000,  0xF0000, 0x1000},\r
+  { EFI_MSR_IA32_MTRR_FIX4K_F8000,  0xF8000, 0x1000}\r
+};\r
+\r
+/**\r
+  Given the input, check if the number of MTRR is lesser.\r
+  if positive or subtractive.\r
+\r
+  @param[in]  Input   Length of Memory to program MTRR.\r
+\r
+  @retval  Zero      do positive.\r
+  @retval  Non-Zero  do subtractive.\r
+\r
+**/\r
+INT8\r
+CheckDirection (\r
+  IN  UINT64                    Input\r
+  )\r
+{\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Disable cache and its mtrr.\r
+\r
+  @param[out]  OldMtrr To return the Old MTRR value\r
+\r
+**/\r
+VOID\r
+EfiDisableCacheMtrr (\r
+  OUT UINT64                   *OldMtrr\r
+  )\r
+{\r
+  UINT64  TempQword;\r
+\r
+  //\r
+  // Disable Cache MTRR\r
+  //\r
+  *OldMtrr = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);\r
+  TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;\r
+  AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);\r
+  AsmDisableCache ();\r
+}\r
+\r
+/**\r
+  Recover cache MTRR.\r
+\r
+  @param[in] EnableMtrr Whether to enable the MTRR\r
+  @param[in] OldMtrr    The saved old MTRR value to restore when not to enable the MTRR\r
+\r
+**/\r
+VOID\r
+EfiRecoverCacheMtrr (\r
+  IN BOOLEAN                  EnableMtrr,\r
+  IN UINT64                   OldMtrr\r
+  )\r
+{\r
+  UINT64  TempQword;\r
+\r
+  //\r
+  // Enable Cache MTRR\r
+  //\r
+  if (EnableMtrr) {\r
+    TempQword = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);\r
+    TempQword |= (B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);\r
+  } else {\r
+    TempQword = OldMtrr;\r
+  }\r
+\r
+  AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);\r
+\r
+  AsmEnableCache ();\r
+}\r
+\r
+/**\r
+  Programming MTRR according to Memory address, length, and type.\r
+\r
+  @param[in] MtrrNumber           the variable MTRR index number\r
+  @param[in] MemoryAddress        the address of target memory\r
+  @param[in] MemoryLength         the length of target memory\r
+  @param[in] MemoryCacheType      the cache type of target memory\r
+  @param[in] ValidMtrrAddressMask the MTRR address mask\r
+\r
+**/\r
+VOID\r
+EfiProgramMtrr (\r
+  IN  UINTN                     MtrrNumber,\r
+  IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,\r
+  IN  UINT64                    MemoryLength,\r
+  IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType,\r
+  IN  UINT64                    ValidMtrrAddressMask\r
+  )\r
+{\r
+  UINT64                        TempQword;\r
+  UINT64                        OldMtrr;\r
+\r
+  if (MemoryLength == 0) {\r
+    return;\r
+  }\r
+\r
+  EfiDisableCacheMtrr (&OldMtrr);\r
+\r
+  //\r
+  // MTRR Physical Base\r
+  //\r
+  TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType;\r
+  AsmWriteMsr64 (MtrrNumber, TempQword);\r
+\r
+  //\r
+  // MTRR Physical Mask\r
+  //\r
+  TempQword = ~(MemoryLength - 1);\r
+  AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);\r
+\r
+  EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
+}\r
+\r
+/**\r
+  Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
+\r
+  @param[in]  MemoryAddress       Memory address.\r
+  @param[in]  MemoryLength        The number to pass in.\r
+\r
+  @return The maximum value which is align to power of 2 and less the MemoryLength\r
+\r
+**/\r
+UINT64\r
+Power2MaxMemory (\r
+  IN UINT64                 MemoryAddress,\r
+  IN UINT64                 MemoryLength\r
+  )\r
+{\r
+  UINT64                    Result;\r
+\r
+  if (MemoryLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Compute inital power of 2 size to return\r
+  //\r
+  if (RShiftU64(MemoryLength, 32)) {\r
+    Result = LShiftU64((UINT64)SetPower2((UINT32) RShiftU64(MemoryLength, 32)), 32);\r
+  } else {\r
+    Result = (UINT64)SetPower2((UINT32)MemoryLength);\r
+  }\r
+\r
+  //\r
+  // Special case base of 0 as all ranges are valid\r
+  //\r
+  if (MemoryAddress == 0) {\r
+    return Result;\r
+  }\r
+\r
+  //\r
+  // Loop till a value that can be mapped to this base address is found\r
+  //\r
+  while (CheckMtrrAlignment (MemoryAddress, Result) != 0) {\r
+    //\r
+    // Need to try the next smaller power of 2\r
+    //\r
+    Result = RShiftU64 (Result, 1);\r
+  }\r
+\r
+  return Result;\r
+}\r
+\r
+/**\r
+  Return MTRR alignment requirement for base address and size.\r
+\r
+  @param[in]  BaseAddress     Base address.\r
+  @param[in]  Size            Size.\r
+\r
+  @retval Zero      Alligned.\r
+  @retval Non-Zero  Not alligned.\r
+\r
+**/\r
+UINT32\r
+CheckMtrrAlignment (\r
+  IN  UINT64    BaseAddress,\r
+  IN  UINT64    Size\r
+  )\r
+{\r
+  UINT32      ShiftedBase;\r
+  UINT32      ShiftedSize;\r
+\r
+  //\r
+  // Shift base and size right 12 bits to allow for larger memory sizes.  The\r
+  // MTRRs do not use the first 12 bits so this is safe for now.  Only supports\r
+  // up to 52 bits of physical address space.\r
+  //\r
+  ShiftedBase = (UINT32) RShiftU64 (BaseAddress, 12);\r
+  ShiftedSize = (UINT32) RShiftU64 (Size, 12);\r
+\r
+  //\r
+  // Return the results to the caller of the MOD\r
+  //\r
+  return ShiftedBase % ShiftedSize;\r
+}\r
+\r
+/**\r
+  Calculate the maximum value which is a power of 2, but less the Input.\r
+\r
+  @param[in]  Input        The number to pass in.\r
+\r
+  @return The maximum value which is align to power of 2 and less the Input.\r
+**/\r
+UINT32\r
+SetPower2 (\r
+  IN UINT32 Input\r
+  )\r
+{\r
+  UINT32 Result;\r
+\r
+  Result = 0;\r
+#if defined(__GCC__)\r
+  asm("bsr %1, \\r
+      %%eax; \\r
+     bts %%eax, \\r
+      %0;" :"=r"(Result) :\r
+    "r"(Input)\r
+  );\r
+#elif defined(_MSC_VER)\r
+  _asm {\r
+    bsr eax, Input\r
+    bts Result, eax\r
+  }\r
+#endif\r
+  return Result;\r
+}\r
+\r
+/**\r
+  Programs fixed MTRRs registers.\r
+\r
+  @param[in]  MemoryCacheType  The memory type to set.\r
+  @param[in]  Base             The base address of memory range.\r
+  @param[in]  Length           The length of memory range.\r
+\r
+  @retval RETURN_SUCCESS      The cache type was updated successfully\r
+  @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
+                              for the fixed MTRRs.\r
+\r
+**/\r
+EFI_STATUS\r
+ProgramFixedMtrr (\r
+  IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType,\r
+  IN  UINT64                    *Base,\r
+  IN  UINT64                    *Len\r
+  )\r
+{\r
+  UINT32                      MsrNum;\r
+  UINT32                      ByteShift;\r
+  UINT64                      TempQword;\r
+  UINT64                      OrMask;\r
+  UINT64                      ClearMask;\r
+\r
+  TempQword = 0;\r
+  OrMask =  0;\r
+  ClearMask = 0;\r
+\r
+  for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {\r
+    if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&\r
+        (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))) {\r
+      break;\r
+    }\r
+  }\r
+  if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // We found the fixed MTRR to be programmed\r
+  //\r
+  for (ByteShift=0; ByteShift < 8; ByteShift++) {\r
+    if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {\r
+      break;\r
+    }\r
+  }\r
+  if (ByteShift == 8 ) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  for (; ((ByteShift<8) && (*Len >= mFixedMtrrTable[MsrNum].Length));ByteShift++) {\r
+    OrMask |= LShiftU64((UINT64) MemoryCacheType, (UINT32) (ByteShift* 8));\r
+    ClearMask |= LShiftU64((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
+    *Len -= mFixedMtrrTable[MsrNum].Length;\r
+    *Base += mFixedMtrrTable[MsrNum].Length;\r
+  }\r
+  TempQword = AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask | OrMask);\r
+  AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if there is a valid variable MTRR that overlaps the given range.\r
+\r
+  @param[in]  Start  Base Address of the range to check.\r
+  @param[in]  End    End address of the range to check.\r
+\r
+  @retval TRUE   Mtrr overlap.\r
+  @retval FALSE  Mtrr not overlap.\r
+**/\r
+BOOLEAN\r
+CheckMtrrOverlap (\r
+  IN  EFI_PHYSICAL_ADDRESS      Start,\r
+  IN  EFI_PHYSICAL_ADDRESS      End\r
+  )\r
+{\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Given the memory range and cache type, programs the MTRRs.\r
+\r
+  @param[in] MemoryAddress           Base Address of Memory to program MTRR.\r
+  @param[in] MemoryLength            Length of Memory to program MTRR.\r
+  @param[in] MemoryCacheType         Cache Type.\r
+\r
+  @retval EFI_SUCCESS            Mtrr are set successfully.\r
+  @retval EFI_LOAD_ERROR         No empty MTRRs to use.\r
+  @retval EFI_INVALID_PARAMETER  The input parameter is not valid.\r
+  @retval others                 An error occurs when setting MTTR.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetCacheAttributes (\r
+  IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,\r
+  IN  UINT64                    MemoryLength,\r
+  IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                MsrNum, MsrNumEnd;\r
+  UINT64                TempQword;\r
+  UINT32                LastVariableMtrrForBios;\r
+  UINT64                OldMtrr;\r
+  UINT32                UsedMsrNum;\r
+  EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType;\r
+  UINT64                ValidMtrrAddressMask;\r
+  UINT32                Cpuid_RegEax;\r
+\r
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL);\r
+  if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
+    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL);\r
+    ValidMtrrAddressMask = (LShiftU64((UINT64) 1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF);\r
+  } else {\r
+    ValidMtrrAddressMask = (LShiftU64((UINT64) 1, 36) - 1) & (~(UINT64)0x0FFF);\r
+  }\r
+\r
+  //\r
+  // Check for invalid parameter\r
+  //\r
+  if ((MemoryAddress & ~ValidMtrrAddressMask) != 0 || (MemoryLength & ~ValidMtrrAddressMask) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MemoryLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (MemoryCacheType) {\r
+    case EFI_CACHE_UNCACHEABLE:\r
+    case EFI_CACHE_WRITECOMBINING:\r
+    case EFI_CACHE_WRITETHROUGH:\r
+    case EFI_CACHE_WRITEPROTECTED:\r
+    case EFI_CACHE_WRITEBACK:\r
+      break;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check if Fixed MTRR\r
+  //\r
+  if ((MemoryAddress + MemoryLength) <= (1 << 20)) {\r
+    Status = EFI_SUCCESS;\r
+    EfiDisableCacheMtrr (&OldMtrr);\r
+    while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) {\r
+      Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength);\r
+    }\r
+    EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Search if the range attribute has been set before\r
+  //\r
+  Status = SearchForExactMtrr(\r
+                              MemoryAddress,\r
+                              MemoryLength,\r
+                              ValidMtrrAddressMask,\r
+                              &UsedMsrNum,\r
+                              &UsedMemoryCacheType\r
+                              );\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    //\r
+    // Compare if it has the same type as current setting\r
+    //\r
+    if (UsedMemoryCacheType == MemoryCacheType) {\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      //\r
+      // Different type\r
+      //\r
+\r
+      //\r
+      // Check if the set type is the same as Default Type\r
+      //\r
+      if (IsDefaultType(MemoryCacheType)) {\r
+        //\r
+        // Clear the MTRR\r
+        //\r
+        AsmWriteMsr64(UsedMsrNum, 0);\r
+        AsmWriteMsr64(UsedMsrNum + 1, 0);\r
+\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        //\r
+        // Modify the MTRR type\r
+        //\r
+        EfiProgramMtrr(UsedMsrNum,\r
+                       MemoryAddress,\r
+                       MemoryLength,\r
+                       MemoryCacheType,\r
+                       ValidMtrrAddressMask\r
+                       );\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+#if 0\r
+  //\r
+  // @bug - Need to create memory map so that when checking for overlap we\r
+  //        can determine if an overlap exists based on all caching requests.\r
+  //\r
+  // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE\r
+  //\r
+  if (MemoryCacheType == (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE))  {\r
+    if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+#endif\r
+\r
+  //\r
+  // Find first unused MTRR\r
+  //\r
+  MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
+  for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {\r
+    if ((AsmReadMsr64(MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Reserve 1 MTRR pair for OS.\r
+  //\r
+  LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2);\r
+  if (MsrNum > LastVariableMtrrForBios) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  //\r
+  // Special case for 1 MB base address\r
+  //\r
+  if (MemoryAddress == BASE_1MB) {\r
+    MemoryAddress = 0;\r
+  }\r
+\r
+  //\r
+  // Program MTRRs\r
+  //\r
+  TempQword = MemoryLength;\r
+\r
+  if (TempQword == Power2MaxMemory(MemoryAddress, TempQword)) {\r
+    EfiProgramMtrr(MsrNum,\r
+                   MemoryAddress,\r
+                   MemoryLength,\r
+                   MemoryCacheType,\r
+                   ValidMtrrAddressMask\r
+                   );\r
+\r
+  } else {\r
+    //\r
+    // Fill in MTRRs with values.  Direction can not be checked for this method\r
+    // as we are using WB as the default cache type and only setting areas to UC.\r
+    //\r
+    do {\r
+      //\r
+      // Do boundary check so we don't go past last MTRR register\r
+      // for BIOS use.  Leave one MTRR pair for OS use.\r
+      //\r
+      if (MsrNum > LastVariableMtrrForBios) {\r
+        return EFI_LOAD_ERROR;\r
+      }\r
+\r
+      //\r
+      // Set next power of 2 region\r
+      //\r
+      MemoryLength = Power2MaxMemory(MemoryAddress, TempQword);\r
+      EfiProgramMtrr(MsrNum,\r
+                     MemoryAddress,\r
+                     MemoryLength,\r
+                     MemoryCacheType,\r
+                     ValidMtrrAddressMask\r
+                     );\r
+      MemoryAddress += MemoryLength;\r
+      TempQword -= MemoryLength;\r
+      MsrNum += 2;\r
+    } while (TempQword != 0);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset all the MTRRs to a known state.\r
+\r
+  @retval  EFI_SUCCESS All MTRRs have been reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ResetCacheAttributes (\r
+  VOID\r
+  )\r
+{\r
+  UINT32                      MsrNum, MsrNumEnd;\r
+  UINT16                      Index;\r
+  UINT64                      OldMtrr;\r
+  UINT64                      CacheType;\r
+  BOOLEAN                     DisableCar;\r
+  Index = 0;\r
+  DisableCar = TRUE;\r
+\r
+  //\r
+  // Determine default cache type\r
+  //\r
+  CacheType = EFI_CACHE_UNCACHEABLE;\r
+\r
+  //\r
+  // Set default cache type\r
+  //\r
+  AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType);\r
+\r
+  //\r
+  // Disable CAR\r
+  //\r
+  DisableCacheAsRam (DisableCar);\r
+\r
+  EfiDisableCacheMtrr (&OldMtrr);\r
+\r
+  //\r
+  // Reset Fixed MTRRs\r
+  //\r
+  for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {\r
+    AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0);\r
+  }\r
+\r
+  //\r
+  // Reset Variable MTRRs\r
+  //\r
+  MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
+  for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) {\r
+    AsmWriteMsr64 (MsrNum, 0);\r
+  }\r
+\r
+  //\r
+  // Enable Fixed and Variable MTRRs\r
+  //\r
+  EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Search the memory cache type for specific memory from MTRR.\r
+\r
+  @param[in]  MemoryAddress         the address of target memory\r
+  @param[in]  MemoryLength          the length of target memory\r
+  @param[in]  ValidMtrrAddressMask  the MTRR address mask\r
+  @param[out] UsedMsrNum            the used MSR number\r
+  @param[out] UsedMemoryCacheType   the cache type for the target memory\r
+\r
+  @retval EFI_SUCCESS    The memory is found in MTRR and cache type is returned\r
+  @retval EFI_NOT_FOUND  The memory is not found in MTRR\r
+\r
+**/\r
+EFI_STATUS\r
+SearchForExactMtrr (\r
+  IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,\r
+  IN  UINT64                    MemoryLength,\r
+  IN  UINT64                    ValidMtrrAddressMask,\r
+  OUT UINT32                    *UsedMsrNum,\r
+  OUT EFI_MEMORY_CACHE_TYPE     *UsedMemoryCacheType\r
+  )\r
+{\r
+  UINT32                      MsrNum, MsrNumEnd;\r
+  UINT64                      TempQword;\r
+\r
+  if (MemoryLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
+  for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {\r
+    TempQword = AsmReadMsr64(MsrNum+1);\r
+    if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {\r
+      continue;\r
+    }\r
+\r
+    if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) {\r
+      continue;\r
+    }\r
+\r
+    TempQword = AsmReadMsr64 (MsrNum);\r
+    if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) {\r
+      continue;\r
+    }\r
+\r
+    *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE);\r
+    *UsedMsrNum = MsrNum;\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Check if CacheType match current default setting.\r
+\r
+  @param[in] MemoryCacheType  input cache type to be checked.\r
+\r
+  @retval TRUE MemoryCacheType is default MTRR setting.\r
+  @retval TRUE MemoryCacheType is NOT default MTRR setting.\r
+**/\r
+BOOLEAN\r
+IsDefaultType (\r
+  IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType\r
+  )\r
+{\r
+  if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r