--- /dev/null
+/** @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