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