summaryrefslogtreecommitdiff
path: root/Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-22 17:11:19 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:14:50 +0800
commit2cc68ed95f4e6a5b6256a6cc1e9f6a585a7d2ba7 (patch)
treee6f0cc497ee0f06782388ab114fd2f3d37bddcc5 /Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
parenta6747ab91782ba4309b5f12301c8b43b1b4702dd (diff)
downloadedk2-platforms-2cc68ed95f4e6a5b6256a6cc1e9f6a585a7d2ba7.tar.xz
UefiCpuPkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c')
-rw-r--r--Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c2147
1 files changed, 2147 insertions, 0 deletions
diff --git a/Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
new file mode 100644
index 0000000000..6a6bf765c2
--- /dev/null
+++ b/Core/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
@@ -0,0 +1,2147 @@
+/** @file
+ MTRR setting library
+
+ Copyright (c) 2008 - 2016, 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 <Base.h>
+
+#include <Library/MtrrLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#define OR_SEED 0x0101010101010101ull
+#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
+
+//
+// Context to save and restore when MTRRs are programmed
+//
+typedef struct {
+ UINTN Cr4;
+ BOOLEAN InterruptState;
+} MTRR_CONTEXT;
+
+//
+// This table defines the offset, base and length of the fixed MTRRs
+//
+CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
+ {
+ MTRR_LIB_IA32_MTRR_FIX64K_00000,
+ 0,
+ SIZE_64KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX16K_80000,
+ 0x80000,
+ SIZE_16KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX16K_A0000,
+ 0xA0000,
+ SIZE_16KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_C0000,
+ 0xC0000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_C8000,
+ 0xC8000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_D0000,
+ 0xD0000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_D8000,
+ 0xD8000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_E0000,
+ 0xE0000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_E8000,
+ 0xE8000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_F0000,
+ 0xF0000,
+ SIZE_4KB
+ },
+ {
+ MTRR_LIB_IA32_MTRR_FIX4K_F8000,
+ 0xF8000,
+ SIZE_4KB
+ }
+};
+
+//
+// Lookup table used to print MTRRs
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
+ "UC", // CacheUncacheable
+ "WC", // CacheWriteCombining
+ "R*", // Invalid
+ "R*", // Invalid
+ "WT", // CacheWriteThrough
+ "WP", // CacheWriteProtected
+ "WB", // CacheWriteBack
+ "R*" // Invalid
+};
+
+/**
+ Worker function returns the variable MTRR count for the CPU.
+
+ @return Variable MTRR count
+
+**/
+UINT32
+GetVariableMtrrCountWorker (
+ VOID
+ )
+{
+ UINT32 VariableMtrrCount;
+
+ VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+ return VariableMtrrCount;
+}
+
+/**
+ Returns the variable MTRR count for the CPU.
+
+ @return Variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetVariableMtrrCount (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+ return GetVariableMtrrCountWorker ();
+}
+
+/**
+ Worker function returns the firmware usable variable MTRR count for the CPU.
+
+ @return Firmware usable variable MTRR count
+
+**/
+UINT32
+GetFirmwareVariableMtrrCountWorker (
+ VOID
+ )
+{
+ UINT32 VariableMtrrCount;
+ UINT32 ReservedMtrrNumber;
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
+ if (VariableMtrrCount < ReservedMtrrNumber) {
+ return 0;
+ }
+
+ return VariableMtrrCount - ReservedMtrrNumber;
+}
+
+/**
+ Returns the firmware usable variable MTRR count for the CPU.
+
+ @return Firmware usable variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetFirmwareVariableMtrrCount (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+ return GetFirmwareVariableMtrrCountWorker ();
+}
+
+/**
+ Worker function returns the default MTRR cache type for the system.
+
+ If MtrrSetting is not NULL, returns the default MTRR cache type from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+
+ @return The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetDefaultMemoryTypeWorker (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ if (MtrrSetting == NULL) {
+ return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
+ } else {
+ return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
+ }
+}
+
+
+/**
+ Returns the default MTRR cache type for the system.
+
+ @return The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetDefaultMemoryType (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return CacheUncacheable;
+ }
+ return MtrrGetDefaultMemoryTypeWorker (NULL);
+}
+
+/**
+ Preparation before programming MTRR.
+
+ This function will do some preparation for programming MTRRs:
+ disable cache, invalid cache and disable MTRR caching functionality
+
+ @param[out] MtrrContext Pointer to context to save
+
+**/
+VOID
+PreMtrrChange (
+ OUT MTRR_CONTEXT *MtrrContext
+ )
+{
+ //
+ // Disable interrupts and save current interrupt state
+ //
+ MtrrContext->InterruptState = SaveAndDisableInterrupts();
+
+ //
+ // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+ //
+ AsmDisableCache ();
+
+ //
+ // Save original CR4 value and clear PGE flag (Bit 7)
+ //
+ MtrrContext->Cr4 = AsmReadCr4 ();
+ AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
+
+ //
+ // Flush all TLBs
+ //
+ CpuFlushTlb ();
+
+ //
+ // Disable MTRRs
+ //
+ AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
+}
+
+/**
+ Cleaning up after programming MTRRs.
+
+ This function will do some clean up after programming MTRRs:
+ Flush all TLBs, re-enable caching, restore CR4.
+
+ @param[in] MtrrContext Pointer to context to restore
+
+**/
+VOID
+PostMtrrChangeEnableCache (
+ IN MTRR_CONTEXT *MtrrContext
+ )
+{
+ //
+ // Flush all TLBs
+ //
+ CpuFlushTlb ();
+
+ //
+ // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+ //
+ AsmEnableCache ();
+
+ //
+ // Restore original CR4 value
+ //
+ AsmWriteCr4 (MtrrContext->Cr4);
+
+ //
+ // Restore original interrupt state
+ //
+ SetInterruptState (MtrrContext->InterruptState);
+}
+
+/**
+ Cleaning up after programming MTRRs.
+
+ This function will do some clean up after programming MTRRs:
+ enable MTRR caching functionality, and enable cache
+
+ @param[in] MtrrContext Pointer to context to restore
+
+**/
+VOID
+PostMtrrChange (
+ IN MTRR_CONTEXT *MtrrContext
+ )
+{
+ //
+ // Enable Cache MTRR
+ //
+ AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
+
+ PostMtrrChangeEnableCache (MtrrContext);
+}
+
+/**
+ Worker function gets the content in fixed MTRRs
+
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.
+
+ @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+MtrrGetFixedMtrrWorker (
+ OUT MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ FixedSettings->Mtrr[Index] =
+ AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
+ }
+
+ return FixedSettings;
+}
+
+
+/**
+ This function gets the content in fixed MTRRs
+
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.
+
+ @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+EFIAPI
+MtrrGetFixedMtrr (
+ OUT MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return FixedSettings;
+ }
+
+ return MtrrGetFixedMtrrWorker (FixedSettings);
+}
+
+
+/**
+ Worker function will get the raw value in variable MTRRs
+
+ If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] VariableMtrrCount Number of variable MTRRs.
+ @param[out] VariableSettings A buffer to hold variable MTRRs content.
+
+ @return The VariableSettings input pointer
+
+**/
+MTRR_VARIABLE_SETTINGS*
+MtrrGetVariableMtrrWorker (
+ IN MTRR_SETTINGS *MtrrSetting,
+ IN UINT32 VariableMtrrCount,
+ OUT MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ UINT32 Index;
+
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (MtrrSetting == NULL) {
+ VariableSettings->Mtrr[Index].Base =
+ AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
+ VariableSettings->Mtrr[Index].Mask =
+ AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
+ } else {
+ VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
+ VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
+ }
+ }
+
+ return VariableSettings;
+}
+
+/**
+ This function will get the raw value in variable MTRRs
+
+ @param[out] VariableSettings A buffer to hold variable MTRRs content.
+
+ @return The VariableSettings input pointer
+
+**/
+MTRR_VARIABLE_SETTINGS*
+EFIAPI
+MtrrGetVariableMtrr (
+ OUT MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return VariableSettings;
+ }
+
+ return MtrrGetVariableMtrrWorker (
+ NULL,
+ GetVariableMtrrCountWorker (),
+ VariableSettings
+ );
+}
+
+/**
+ Programs fixed MTRRs registers.
+
+ @param[in] MemoryCacheType The memory type to set.
+ @param[in, out] Base The base address of memory range.
+ @param[in, out] Length The length of memory range.
+ @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.
+ On return, the current index of the fixed MTRR MSR to program.
+ @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
+ @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
+
+ @retval RETURN_SUCCESS The cache type was updated successfully
+ @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
+ for the fixed MTRRs.
+
+**/
+RETURN_STATUS
+ProgramFixedMtrr (
+ IN UINT64 MemoryCacheType,
+ IN OUT UINT64 *Base,
+ IN OUT UINT64 *Length,
+ IN OUT UINT32 *LastMsrNum,
+ OUT UINT64 *ReturnClearMask,
+ OUT UINT64 *ReturnOrMask
+ )
+{
+ UINT32 MsrNum;
+ UINT32 LeftByteShift;
+ UINT32 RightByteShift;
+ UINT64 OrMask;
+ UINT64 ClearMask;
+ UINT64 SubLength;
+
+ //
+ // Find the fixed MTRR index to be programmed
+ //
+ for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
+ if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
+ (*Base <
+ (
+ mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
+ (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
+ )
+ )
+ ) {
+ break;
+ }
+ }
+
+ if (MsrNum >= MTRR_NUMBER_OF_FIXED_MTRR) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Find the begin offset in fixed MTRR and calculate byte offset of left shift
+ //
+ LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)
+ / mMtrrLibFixedMtrrTable[MsrNum].Length;
+
+ if (LeftByteShift >= 8) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Find the end offset in fixed MTRR and calculate byte offset of right shift
+ //
+ SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);
+ if (*Length >= SubLength) {
+ RightByteShift = 0;
+ } else {
+ RightByteShift = 8 - LeftByteShift -
+ (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;
+ if ((LeftByteShift >= 8) ||
+ (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)
+ ) {
+ return RETURN_UNSUPPORTED;
+ }
+ //
+ // Update SubLength by actual length
+ //
+ SubLength = *Length;
+ }
+
+ ClearMask = CLEAR_SEED;
+ OrMask = MultU64x32 (OR_SEED, (UINT32)MemoryCacheType);
+
+ if (LeftByteShift != 0) {
+ //
+ // Clear the low bits by LeftByteShift
+ //
+ ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);
+ OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);
+ }
+
+ if (RightByteShift != 0) {
+ //
+ // Clear the high bits by RightByteShift
+ //
+ ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);
+ OrMask &= RShiftU64 (OrMask, RightByteShift * 8);
+ }
+
+ *Length -= SubLength;
+ *Base += SubLength;
+
+ *LastMsrNum = MsrNum;
+ *ReturnClearMask = ClearMask;
+ *ReturnOrMask = OrMask;
+
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Worker function gets the attribute of variable MTRRs.
+
+ This function shadows the content of variable MTRRs into an
+ internal array: VariableMtrr.
+
+ @param[in] VariableSettings The variable MTRR values to shadow
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+ @param[out] VariableMtrr The array to shadow variable MTRRs content
+
+ @return The return value of this parameter indicates the
+ number of MTRRs which has been used.
+
+**/
+UINT32
+MtrrGetMemoryAttributeInVariableMtrrWorker (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings,
+ IN UINTN FirmwareVariableMtrrCount,
+ IN UINT64 MtrrValidBitsMask,
+ IN UINT64 MtrrValidAddressMask,
+ OUT VARIABLE_MTRR *VariableMtrr
+ )
+{
+ UINTN Index;
+ UINT32 UsedMtrr;
+
+ ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
+ for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
+ if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
+ VariableMtrr[Index].Msr = (UINT32)Index;
+ VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
+ VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
+ VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);
+ VariableMtrr[Index].Valid = TRUE;
+ VariableMtrr[Index].Used = TRUE;
+ UsedMtrr++;
+ }
+ }
+ return UsedMtrr;
+}
+
+
+/**
+ Gets the attribute of variable MTRRs.
+
+ This function shadows the content of variable MTRRs into an
+ internal array: VariableMtrr.
+
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+ @param[out] VariableMtrr The array to shadow variable MTRRs content
+
+ @return The return value of this paramter indicates the
+ number of MTRRs which has been used.
+
+**/
+UINT32
+EFIAPI
+MtrrGetMemoryAttributeInVariableMtrr (
+ IN UINT64 MtrrValidBitsMask,
+ IN UINT64 MtrrValidAddressMask,
+ OUT VARIABLE_MTRR *VariableMtrr
+ )
+{
+ MTRR_VARIABLE_SETTINGS VariableSettings;
+
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+
+ MtrrGetVariableMtrrWorker (
+ NULL,
+ GetVariableMtrrCountWorker (),
+ &VariableSettings
+ );
+
+ return MtrrGetMemoryAttributeInVariableMtrrWorker (
+ &VariableSettings,
+ GetFirmwareVariableMtrrCountWorker (),
+ MtrrValidBitsMask,
+ MtrrValidAddressMask,
+ VariableMtrr
+ );
+}
+
+
+/**
+ Checks overlap between given memory range and MTRRs.
+
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available
+ to firmware.
+ @param[in] Start The start address of memory range.
+ @param[in] End The end address of memory range.
+ @param[in] VariableMtrr The array to shadow variable MTRRs content
+
+ @retval TRUE Overlap exists.
+ @retval FALSE No overlap.
+
+**/
+BOOLEAN
+CheckMemoryAttributeOverlap (
+ IN UINTN FirmwareVariableMtrrCount,
+ IN PHYSICAL_ADDRESS Start,
+ IN PHYSICAL_ADDRESS End,
+ IN VARIABLE_MTRR *VariableMtrr
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
+ if (
+ VariableMtrr[Index].Valid &&
+ !(
+ (Start > (VariableMtrr[Index].BaseAddress +
+ VariableMtrr[Index].Length - 1)
+ ) ||
+ (End < VariableMtrr[Index].BaseAddress)
+ )
+ ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Marks a variable MTRR as non-valid.
+
+ @param[in] Index The index of the array VariableMtrr to be invalidated
+ @param[in] VariableMtrr The array to shadow variable MTRRs content
+ @param[out] UsedMtrr The number of MTRRs which has already been used
+
+**/
+VOID
+InvalidateShadowMtrr (
+ IN UINTN Index,
+ IN VARIABLE_MTRR *VariableMtrr,
+ OUT UINT32 *UsedMtrr
+ )
+{
+ VariableMtrr[Index].Valid = FALSE;
+ *UsedMtrr = *UsedMtrr - 1;
+}
+
+
+/**
+ Combines memory attributes.
+
+ If overlap exists between given memory range and MTRRs, try to combine them.
+
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs
+ available to firmware.
+ @param[in] Attributes The memory type to set.
+ @param[in, out] Base The base address of memory range.
+ @param[in, out] Length The length of memory range.
+ @param[in] VariableMtrr The array to shadow variable MTRRs content
+ @param[in, out] UsedMtrr The number of MTRRs which has already been used
+ @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
+
+ @retval EFI_SUCCESS Memory region successfully combined.
+ @retval EFI_ACCESS_DENIED Memory region cannot be combined.
+
+**/
+RETURN_STATUS
+CombineMemoryAttribute (
+ IN UINT32 FirmwareVariableMtrrCount,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *Base,
+ IN OUT UINT64 *Length,
+ IN VARIABLE_MTRR *VariableMtrr,
+ IN OUT UINT32 *UsedMtrr,
+ OUT BOOLEAN *OverwriteExistingMtrr
+ )
+{
+ UINT32 Index;
+ UINT64 CombineStart;
+ UINT64 CombineEnd;
+ UINT64 MtrrEnd;
+ UINT64 EndAddress;
+ BOOLEAN CoveredByExistingMtrr;
+
+ *OverwriteExistingMtrr = FALSE;
+ CoveredByExistingMtrr = FALSE;
+ EndAddress = *Base +*Length - 1;
+
+ for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
+
+ MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
+ if (
+ !VariableMtrr[Index].Valid ||
+ (
+ *Base > (MtrrEnd) ||
+ (EndAddress < VariableMtrr[Index].BaseAddress)
+ )
+ ) {
+ continue;
+ }
+
+ //
+ // Combine same attribute MTRR range
+ //
+ if (Attributes == VariableMtrr[Index].Type) {
+ //
+ // if the MTRR range contain the request range, set a flag, then continue to
+ // invalidate any MTRR of the same request range with higher priority cache type.
+ //
+ if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
+ CoveredByExistingMtrr = TRUE;
+ continue;
+ }
+ //
+ // invalid this MTRR, and program the combine range
+ //
+ CombineStart =
+ (*Base) < VariableMtrr[Index].BaseAddress ?
+ (*Base) :
+ VariableMtrr[Index].BaseAddress;
+ CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
+
+ //
+ // Record the MTRR usage status in VariableMtrr array.
+ //
+ InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
+ *Base = CombineStart;
+ *Length = CombineEnd - CombineStart + 1;
+ EndAddress = CombineEnd;
+ *OverwriteExistingMtrr = TRUE;
+ continue;
+ } else {
+ //
+ // The cache type is different, but the range is convered by one MTRR
+ //
+ if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
+ InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
+ continue;
+ }
+
+ }
+
+ if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
+ VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
+ (Attributes == MTRR_CACHE_WRITE_BACK &&
+ VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
+ (Attributes == MTRR_CACHE_UNCACHEABLE) ||
+ (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
+ ) {
+ *OverwriteExistingMtrr = TRUE;
+ continue;
+ }
+ //
+ // Other type memory overlap is invalid
+ //
+ return RETURN_ACCESS_DENIED;
+ }
+
+ if (CoveredByExistingMtrr) {
+ *Length = 0;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Calculates the maximum value which is a power of 2, but less the MemoryLength.
+
+ @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 MemoryLength
+ )
+{
+ UINT64 Result;
+
+ if (RShiftU64 (MemoryLength, 32) != 0) {
+ Result = LShiftU64 (
+ (UINT64) GetPowerOfTwo32 (
+ (UINT32) RShiftU64 (MemoryLength, 32)
+ ),
+ 32
+ );
+ } else {
+ Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
+ }
+
+ return Result;
+}
+
+
+/**
+ Determines the MTRR numbers used to program a memory range.
+
+ This function first checks the alignment of the base address.
+ If the alignment of the base address <= Length, cover the memory range
+ (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
+ Length -= alignment. Repeat the step until alignment > Length.
+
+ Then this function determines which direction of programming the variable
+ MTRRs for the remaining length will use fewer MTRRs.
+
+ @param[in] BaseAddress Length of Memory to program MTRR
+ @param[in] Length Length of Memory to program MTRR
+ @param[in] MtrrNumber Pointer to the number of necessary MTRRs
+
+ @retval TRUE Positive direction is better.
+ FALSE Negative direction is better.
+
+**/
+BOOLEAN
+GetMtrrNumberAndDirection (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINTN *MtrrNumber
+ )
+{
+ UINT64 TempQword;
+ UINT64 Alignment;
+ UINT32 Positive;
+ UINT32 Subtractive;
+
+ *MtrrNumber = 0;
+
+ if (BaseAddress != 0) {
+ do {
+ //
+ // Calculate the alignment of the base address.
+ //
+ Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
+
+ if (Alignment > Length) {
+ break;
+ }
+
+ (*MtrrNumber)++;
+ BaseAddress += Alignment;
+ Length -= Alignment;
+ } while (TRUE);
+
+ if (Length == 0) {
+ return TRUE;
+ }
+ }
+
+ TempQword = Length;
+ Positive = 0;
+ Subtractive = 0;
+
+ do {
+ TempQword -= Power2MaxMemory (TempQword);
+ Positive++;
+ } while (TempQword != 0);
+
+ TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
+ Subtractive++;
+ do {
+ TempQword -= Power2MaxMemory (TempQword);
+ Subtractive++;
+ } while (TempQword != 0);
+
+ if (Positive <= Subtractive) {
+ *MtrrNumber += Positive;
+ return TRUE;
+ } else {
+ *MtrrNumber += Subtractive;
+ return FALSE;
+ }
+}
+
+/**
+ Invalid variable MTRRs according to the value in the shadow array.
+
+ This function programs MTRRs according to the values specified
+ in the shadow array.
+
+ @param[in, out] VariableSettings Variable MTRR settings
+ @param[in] VariableMtrrCount Number of variable MTRRs
+ @param[in, out] VariableMtrr Shadow of variable MTRR contents
+
+**/
+VOID
+InvalidateMtrr (
+ IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,
+ IN UINTN VariableMtrrCount,
+ IN OUT VARIABLE_MTRR *VariableMtrr
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
+ VariableSettings->Mtrr[Index].Base = 0;
+ VariableSettings->Mtrr[Index].Mask = 0;
+ VariableMtrr[Index].Used = FALSE;
+ }
+ }
+}
+
+
+/**
+ Programs variable MTRRs
+
+ This function programs variable MTRRs
+
+ @param[in, out] VariableSettings Variable MTRR settings.
+ @param[in] MtrrNumber Index of MTRR to program.
+ @param[in] BaseAddress Base address of memory region.
+ @param[in] Length Length of memory region.
+ @param[in] MemoryCacheType Memory type to set.
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+
+**/
+VOID
+ProgramVariableMtrr (
+ IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,
+ IN UINTN MtrrNumber,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 MemoryCacheType,
+ IN UINT64 MtrrValidAddressMask
+ )
+{
+ UINT64 TempQword;
+
+ //
+ // MTRR Physical Base
+ //
+ TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
+ VariableSettings->Mtrr[MtrrNumber].Base = TempQword;
+
+ //
+ // MTRR Physical Mask
+ //
+ TempQword = ~(Length - 1);
+ VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;
+}
+
+
+/**
+ Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
+
+ If MtrrSetting is not NULL, gets the default memory attribute from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, gets the default memory attribute from MSR.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] MtrrType MTRR memory type
+
+ @return The enum item in MTRR_MEMORY_CACHE_TYPE
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+GetMemoryCacheTypeFromMtrrType (
+ IN MTRR_SETTINGS *MtrrSetting,
+ IN UINT64 MtrrType
+ )
+{
+ switch (MtrrType) {
+ case MTRR_CACHE_UNCACHEABLE:
+ return CacheUncacheable;
+ case MTRR_CACHE_WRITE_COMBINING:
+ return CacheWriteCombining;
+ case MTRR_CACHE_WRITE_THROUGH:
+ return CacheWriteThrough;
+ case MTRR_CACHE_WRITE_PROTECTED:
+ return CacheWriteProtected;
+ case MTRR_CACHE_WRITE_BACK:
+ return CacheWriteBack;
+ default:
+ //
+ // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
+ // no MTRR covers the range
+ //
+ return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
+ }
+}
+
+/**
+ Initializes the valid bits mask and valid address mask for MTRRs.
+
+ This function initializes the valid bits mask and valid address mask for MTRRs.
+
+ @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[out] MtrrValidAddressMask The valid address mask for the MTRR
+
+**/
+VOID
+MtrrLibInitializeMtrrMask (
+ OUT UINT64 *MtrrValidBitsMask,
+ OUT UINT64 *MtrrValidAddressMask
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+
+ PhysicalAddressBits = (UINT8) RegEax;
+
+ *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
+ *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
+ } else {
+ *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;
+ *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
+ }
+}
+
+
+/**
+ Determines the real attribute of a memory range.
+
+ This function is to arbitrate the real attribute of the memory when
+ there are 2 MTRRs covers the same memory range. For further details,
+ please refer the IA32 Software Developer's Manual, Volume 3,
+ Section 10.11.4.1.
+
+ @param[in] MtrrType1 The first kind of Memory type
+ @param[in] MtrrType2 The second kind of memory type
+
+**/
+UINT64
+MtrrPrecedence (
+ IN UINT64 MtrrType1,
+ IN UINT64 MtrrType2
+ )
+{
+ UINT64 MtrrType;
+
+ MtrrType = MTRR_CACHE_INVALID_TYPE;
+ switch (MtrrType1) {
+ case MTRR_CACHE_UNCACHEABLE:
+ MtrrType = MTRR_CACHE_UNCACHEABLE;
+ break;
+ case MTRR_CACHE_WRITE_COMBINING:
+ if (
+ MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
+ MtrrType2==MTRR_CACHE_UNCACHEABLE
+ ) {
+ MtrrType = MtrrType2;
+ }
+ break;
+ case MTRR_CACHE_WRITE_THROUGH:
+ if (
+ MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
+ MtrrType2==MTRR_CACHE_WRITE_BACK
+ ) {
+ MtrrType = MTRR_CACHE_WRITE_THROUGH;
+ } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
+ MtrrType = MTRR_CACHE_UNCACHEABLE;
+ }
+ break;
+ case MTRR_CACHE_WRITE_PROTECTED:
+ if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
+ MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
+ MtrrType = MtrrType2;
+ }
+ break;
+ case MTRR_CACHE_WRITE_BACK:
+ if (
+ MtrrType2== MTRR_CACHE_UNCACHEABLE ||
+ MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
+ MtrrType2== MTRR_CACHE_WRITE_BACK
+ ) {
+ MtrrType = MtrrType2;
+ }
+ break;
+ case MTRR_CACHE_INVALID_TYPE:
+ MtrrType = MtrrType2;
+ break;
+ default:
+ break;
+ }
+
+ if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
+ MtrrType = MtrrType1;
+ }
+ return MtrrType;
+}
+
+/**
+ Worker function will get the memory cache type of the specific address.
+
+ If MtrrSetting is not NULL, gets the memory cache type from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, gets the memory cache type from MTRRs.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] Address The specific address
+
+ @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetMemoryAttributeByAddressWorker (
+ IN MTRR_SETTINGS *MtrrSetting,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 TempQword;
+ UINTN Index;
+ UINTN SubIndex;
+ UINT64 MtrrType;
+ UINT64 TempMtrrType;
+ MTRR_MEMORY_CACHE_TYPE CacheType;
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ UINTN VariableMtrrCount;
+ MTRR_VARIABLE_SETTINGS VariableSettings;
+
+ //
+ // Check if MTRR is enabled, if not, return UC as attribute
+ //
+ if (MtrrSetting == NULL) {
+ TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
+ } else {
+ TempQword = MtrrSetting->MtrrDefType;
+ }
+ MtrrType = MTRR_CACHE_INVALID_TYPE;
+
+ if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
+ return CacheUncacheable;
+ }
+
+ //
+ // If address is less than 1M, then try to go through the fixed MTRR
+ //
+ if (Address < BASE_1MB) {
+ if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
+ //
+ // Go through the fixed MTRR
+ //
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
+ Address < (
+ mMtrrLibFixedMtrrTable[Index].BaseAddress +
+ (mMtrrLibFixedMtrrTable[Index].Length * 8)
+ )
+ ) {
+ SubIndex =
+ ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
+ mMtrrLibFixedMtrrTable[Index].Length;
+ if (MtrrSetting == NULL) {
+ TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
+ } else {
+ TempQword = MtrrSetting->Fixed.Mtrr[Index];
+ }
+ MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
+ return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
+ }
+ }
+ }
+ }
+ MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
+
+ MtrrGetVariableMtrrWorker (
+ MtrrSetting,
+ GetVariableMtrrCountWorker (),
+ &VariableSettings
+ );
+
+ MtrrGetMemoryAttributeInVariableMtrrWorker (
+ &VariableSettings,
+ GetFirmwareVariableMtrrCountWorker (),
+ MtrrValidBitsMask,
+ MtrrValidAddressMask,
+ VariableMtrr
+ );
+
+ //
+ // Go through the variable MTRR
+ //
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (VariableMtrr[Index].Valid) {
+ if (Address >= VariableMtrr[Index].BaseAddress &&
+ Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
+ TempMtrrType = VariableMtrr[Index].Type;
+ MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
+ }
+ }
+ }
+ CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
+
+ return CacheType;
+}
+
+
+/**
+ This function will get the memory cache type of the specific address.
+
+ This function is mainly for debug purpose.
+
+ @param[in] Address The specific address
+
+ @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetMemoryAttribute (
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return CacheUncacheable;
+ }
+
+ return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
+}
+
+/**
+ Worker function prints all MTRRs for debugging.
+
+ If MtrrSetting is not NULL, print MTRR settings from from input MTRR
+ settings buffer.
+ If MtrrSetting is NULL, print MTRR settings from MTRRs.
+
+ @param MtrrSetting A buffer holding all MTRRs content.
+**/
+VOID
+MtrrDebugPrintAllMtrrsWorker (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ DEBUG_CODE (
+ MTRR_SETTINGS LocalMtrrs;
+ MTRR_SETTINGS *Mtrrs;
+ UINTN Index;
+ UINTN Index1;
+ UINTN VariableMtrrCount;
+ UINT64 Base;
+ UINT64 Limit;
+ UINT64 MtrrBase;
+ UINT64 MtrrLimit;
+ UINT64 RangeBase;
+ UINT64 RangeLimit;
+ UINT64 NoRangeBase;
+ UINT64 NoRangeLimit;
+ UINT32 RegEax;
+ UINTN MemoryType;
+ UINTN PreviousMemoryType;
+ BOOLEAN Found;
+
+ if (!IsMtrrSupported ()) {
+ return;
+ }
+
+ DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
+ DEBUG((DEBUG_CACHE, "=============\n"));
+
+ if (MtrrSetting != NULL) {
+ Mtrrs = MtrrSetting;
+ } else {
+ MtrrGetAllMtrrs (&LocalMtrrs);
+ Mtrrs = &LocalMtrrs;
+ }
+
+ DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
+ }
+
+ VariableMtrrCount = GetVariableMtrrCount ();
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
+ Index,
+ Mtrrs->Variables.Mtrr[Index].Base,
+ Mtrrs->Variables.Mtrr[Index].Mask
+ ));
+ }
+ DEBUG((DEBUG_CACHE, "\n"));
+ DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
+ DEBUG((DEBUG_CACHE, "====================================\n"));
+
+ Base = 0;
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
+ for (Index1 = 0; Index1 < 8; Index1++) {
+ MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
+ if (MemoryType > CacheWriteBack) {
+ MemoryType = MTRR_CACHE_INVALID_TYPE;
+ }
+ if (MemoryType != PreviousMemoryType) {
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+ }
+ PreviousMemoryType = MemoryType;
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
+ }
+ Base += mMtrrLibFixedMtrrTable[Index].Length;
+ }
+ }
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+
+ VariableMtrrCount = GetVariableMtrrCount ();
+
+ Limit = BIT36 - 1;
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ Limit = LShiftU64 (1, RegEax & 0xff) - 1;
+ }
+ Base = BASE_1MB;
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
+ do {
+ MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
+ if (MemoryType > CacheWriteBack) {
+ MemoryType = MTRR_CACHE_INVALID_TYPE;
+ }
+
+ if (MemoryType != PreviousMemoryType) {
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+ }
+ PreviousMemoryType = MemoryType;
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
+ }
+
+ RangeBase = BASE_1MB;
+ NoRangeBase = BASE_1MB;
+ RangeLimit = Limit;
+ NoRangeLimit = Limit;
+
+ for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
+ if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
+ //
+ // If mask is not valid, then do not display range
+ //
+ continue;
+ }
+ MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
+ MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
+
+ if (Base >= MtrrBase && Base < MtrrLimit) {
+ Found = TRUE;
+ }
+
+ if (Base >= MtrrBase && MtrrBase > RangeBase) {
+ RangeBase = MtrrBase;
+ }
+ if (Base > MtrrLimit && MtrrLimit > RangeBase) {
+ RangeBase = MtrrLimit + 1;
+ }
+ if (Base < MtrrBase && MtrrBase < RangeLimit) {
+ RangeLimit = MtrrBase - 1;
+ }
+ if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
+ RangeLimit = MtrrLimit;
+ }
+
+ if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
+ NoRangeBase = MtrrLimit + 1;
+ }
+ if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
+ NoRangeLimit = MtrrBase - 1;
+ }
+ }
+
+ if (Found) {
+ Base = RangeLimit + 1;
+ } else {
+ Base = NoRangeLimit + 1;
+ }
+ } while (Base < Limit);
+ DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
+ );
+}
+
+
+/**
+ This function prints all MTRRs for debugging.
+**/
+VOID
+EFIAPI
+MtrrDebugPrintAllMtrrs (
+ VOID
+ )
+{
+ MtrrDebugPrintAllMtrrsWorker (NULL);
+}
+
+
+/**
+ Worker function attempts to set the attributes for a memory range.
+
+ If MtrrSettings is not NULL, set the attributes into the input MTRR
+ settings buffer.
+ If MtrrSettings is NULL, set the attributes into MTRRs registers.
+
+ @param[in, out] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] Length The size in bytes of the memory region.
+ @param[in] Attribute The bit mask of attributes to set for the
+ memory region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Length is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or
+ more bytes of the memory resource range
+ specified by BaseAddress and Length.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
+ for the memory resource range specified
+ by BaseAddress and Length.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource
+ range specified by BaseAddress and Length
+ cannot be modified.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
+ modify the attributes of the memory
+ resource range.
+
+**/
+RETURN_STATUS
+MtrrSetMemoryAttributeWorker (
+ IN OUT MTRR_SETTINGS *MtrrSetting,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Attribute
+ )
+{
+ UINT64 TempQword;
+ RETURN_STATUS Status;
+ UINT64 MemoryType;
+ UINT64 Alignment;
+ BOOLEAN OverLap;
+ BOOLEAN Positive;
+ UINT32 MsrNum;
+ UINTN MtrrNumber;
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ UINT32 UsedMtrr;
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ BOOLEAN OverwriteExistingMtrr;
+ UINT32 FirmwareVariableMtrrCount;
+ MTRR_CONTEXT MtrrContext;
+ BOOLEAN MtrrContextValid;
+ BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
+ BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
+ MTRR_FIXED_SETTINGS WorkingFixedSettings;
+ UINT32 VariableMtrrCount;
+ MTRR_VARIABLE_SETTINGS OriginalVariableSettings;
+ BOOLEAN ProgramVariableSettings;
+ MTRR_VARIABLE_SETTINGS WorkingVariableSettings;
+ UINT32 Index;
+ UINT64 ClearMask;
+ UINT64 OrMask;
+ UINT64 NewValue;
+ MTRR_VARIABLE_SETTINGS *VariableSettings;
+
+ MtrrContextValid = FALSE;
+ VariableMtrrCount = 0;
+ ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ FixedSettingsValid[Index] = FALSE;
+ FixedSettingsModified[Index] = FALSE;
+ }
+ ProgramVariableSettings = FALSE;
+
+ if (!IsMtrrSupported ()) {
+ Status = RETURN_UNSUPPORTED;
+ goto Done;
+ }
+
+ MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
+
+ TempQword = 0;
+ MemoryType = (UINT64)Attribute;
+ OverwriteExistingMtrr = FALSE;
+
+ //
+ // Check for an invalid parameter
+ //
+ if (Length == 0) {
+ Status = RETURN_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (
+ (BaseAddress & ~MtrrValidAddressMask) != 0 ||
+ (Length & ~MtrrValidAddressMask) != 0
+ ) {
+ Status = RETURN_UNSUPPORTED;
+ goto Done;
+ }
+
+ //
+ // Check if Fixed MTRR
+ //
+ Status = RETURN_SUCCESS;
+ if (BaseAddress < BASE_1MB) {
+ MsrNum = (UINT32)-1;
+ while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
+ Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);
+ if (RETURN_ERROR (Status)) {
+ goto Done;
+ }
+ if (MtrrSetting != NULL) {
+ MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;
+ MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;
+ } else {
+ if (!FixedSettingsValid[MsrNum]) {
+ WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);
+ FixedSettingsValid[MsrNum] = TRUE;
+ }
+ NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;
+ if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {
+ WorkingFixedSettings.Mtrr[MsrNum] = NewValue;
+ FixedSettingsModified[MsrNum] = TRUE;
+ }
+ }
+ }
+
+ if (Length == 0) {
+ //
+ // A Length of 0 can only make sense for fixed MTTR ranges.
+ // Since we just handled the fixed MTRRs, we can skip the
+ // variable MTRR section.
+ //
+ goto Done;
+ }
+ }
+
+ //
+ // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
+ // we can set the base to 0 to save variable MTRRs.
+ //
+ if (BaseAddress == BASE_1MB) {
+ BaseAddress = 0;
+ Length += SIZE_1MB;
+ }
+
+ //
+ // Read all variable MTRRs
+ //
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
+ if (MtrrSetting != NULL) {
+ VariableSettings = &MtrrSetting->Variables;
+ } else {
+ MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);
+ CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));
+ ProgramVariableSettings = TRUE;
+ VariableSettings = &WorkingVariableSettings;
+ }
+
+ //
+ // Check for overlap
+ //
+ UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (
+ VariableSettings,
+ FirmwareVariableMtrrCount,
+ MtrrValidBitsMask,
+ MtrrValidAddressMask,
+ VariableMtrr
+ );
+ OverLap = CheckMemoryAttributeOverlap (
+ FirmwareVariableMtrrCount,
+ BaseAddress,
+ BaseAddress + Length - 1,
+ VariableMtrr
+ );
+ if (OverLap) {
+ Status = CombineMemoryAttribute (
+ FirmwareVariableMtrrCount,
+ MemoryType,
+ &BaseAddress,
+ &Length,
+ VariableMtrr,
+ &UsedMtrr,
+ &OverwriteExistingMtrr
+ );
+ if (RETURN_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Length == 0) {
+ //
+ // Combined successfully, invalidate the now-unused MTRRs
+ //
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+ Status = RETURN_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // The memory type is the same with the type specified by
+ // MTRR_LIB_IA32_MTRR_DEF_TYPE.
+ //
+ if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {
+ //
+ // Invalidate the now-unused MTRRs
+ //
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+ goto Done;
+ }
+
+ Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
+
+ if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Invalidate the now-unused MTRRs
+ //
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+
+ //
+ // Find first unused MTRR
+ //
+ for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
+ break;
+ }
+ }
+
+ if (BaseAddress != 0) {
+ do {
+ //
+ // Calculate the alignment of the base address.
+ //
+ Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
+
+ if (Alignment > Length) {
+ break;
+ }
+
+ //
+ // Find unused MTRR
+ //
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
+ break;
+ }
+ }
+
+ ProgramVariableMtrr (
+ VariableSettings,
+ MsrNum,
+ BaseAddress,
+ Alignment,
+ MemoryType,
+ MtrrValidAddressMask
+ );
+ BaseAddress += Alignment;
+ Length -= Alignment;
+ } while (TRUE);
+
+ if (Length == 0) {
+ goto Done;
+ }
+ }
+
+ TempQword = Length;
+
+ if (!Positive) {
+ Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
+
+ //
+ // Find unused MTRR
+ //
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
+ break;
+ }
+ }
+
+ ProgramVariableMtrr (
+ VariableSettings,
+ MsrNum,
+ BaseAddress,
+ Length,
+ MemoryType,
+ MtrrValidAddressMask
+ );
+ BaseAddress += Length;
+ TempQword = Length - TempQword;
+ MemoryType = MTRR_CACHE_UNCACHEABLE;
+ }
+
+ do {
+ //
+ // Find unused MTRR
+ //
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
+ break;
+ }
+ }
+
+ Length = Power2MaxMemory (TempQword);
+ if (!Positive) {
+ BaseAddress -= Length;
+ }
+
+ ProgramVariableMtrr (
+ VariableSettings,
+ MsrNum,
+ BaseAddress,
+ Length,
+ MemoryType,
+ MtrrValidAddressMask
+ );
+
+ if (Positive) {
+ BaseAddress += Length;
+ }
+ TempQword -= Length;
+
+ } while (TempQword > 0);
+
+Done:
+
+ //
+ // Write fixed MTRRs that have been modified
+ //
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ if (FixedSettingsModified[Index]) {
+ if (!MtrrContextValid) {
+ PreMtrrChange (&MtrrContext);
+ MtrrContextValid = TRUE;
+ }
+ AsmWriteMsr64 (
+ mMtrrLibFixedMtrrTable[Index].Msr,
+ WorkingFixedSettings.Mtrr[Index]
+ );
+ }
+ }
+
+ //
+ // Write variable MTRRs
+ //
+ if (ProgramVariableSettings) {
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||
+ WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {
+ if (!MtrrContextValid) {
+ PreMtrrChange (&MtrrContext);
+ MtrrContextValid = TRUE;
+ }
+ AsmWriteMsr64 (
+ MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
+ WorkingVariableSettings.Mtrr[Index].Base
+ );
+ AsmWriteMsr64 (
+ MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
+ WorkingVariableSettings.Mtrr[Index].Mask
+ );
+ }
+ }
+ }
+ if (MtrrContextValid) {
+ PostMtrrChange (&MtrrContext);
+ }
+
+ DEBUG((DEBUG_CACHE, " Status = %r\n", Status));
+ if (!RETURN_ERROR (Status)) {
+ if (MtrrSetting != NULL) {
+ MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;
+ }
+ MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
+ }
+
+ return Status;
+}
+
+/**
+ This function attempts to set the attributes for a memory range.
+
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] Length The size in bytes of the memory region.
+ @param[in] Attributes The bit mask of attributes to set for the
+ memory region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Length is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or
+ more bytes of the memory resource range
+ specified by BaseAddress and Length.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
+ for the memory resource range specified
+ by BaseAddress and Length.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource
+ range specified by BaseAddress and Length
+ cannot be modified.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
+ modify the attributes of the memory
+ resource range.
+
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttribute (
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Attribute
+ )
+{
+ DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
+ return MtrrSetMemoryAttributeWorker (
+ NULL,
+ BaseAddress,
+ Length,
+ Attribute
+ );
+}
+
+/**
+ This function attempts to set the attributes into MTRR setting buffer for a memory range.
+
+ @param[in, out] MtrrSetting MTRR setting buffer to be set.
+ @param[in] BaseAddress The physical address that is the start address
+ of a memory region.
+ @param[in] Length The size in bytes of the memory region.
+ @param[in] Attribute The bit mask of attributes to set for the
+ memory region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory region.
+ @retval RETURN_INVALID_PARAMETER Length is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
+ memory resource range specified by BaseAddress and Length.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttributeInMtrrSettings (
+ IN OUT MTRR_SETTINGS *MtrrSetting,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Attribute
+ )
+{
+ DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
+ return MtrrSetMemoryAttributeWorker (
+ MtrrSetting,
+ BaseAddress,
+ Length,
+ Attribute
+ );
+}
+
+/**
+ Worker function setting variable MTRRs
+
+ @param[in] VariableSettings A buffer to hold variable MTRRs content.
+
+**/
+VOID
+MtrrSetVariableMtrrWorker (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrCount;
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ AsmWriteMsr64 (
+ MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
+ VariableSettings->Mtrr[Index].Base
+ );
+ AsmWriteMsr64 (
+ MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
+ VariableSettings->Mtrr[Index].Mask
+ );
+ }
+}
+
+
+/**
+ This function sets variable MTRRs
+
+ @param[in] VariableSettings A buffer to hold variable MTRRs content.
+
+ @return The pointer of VariableSettings
+
+**/
+MTRR_VARIABLE_SETTINGS*
+EFIAPI
+MtrrSetVariableMtrr (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ MTRR_CONTEXT MtrrContext;
+
+ if (!IsMtrrSupported ()) {
+ return VariableSettings;
+ }
+
+ PreMtrrChange (&MtrrContext);
+ MtrrSetVariableMtrrWorker (VariableSettings);
+ PostMtrrChange (&MtrrContext);
+ MtrrDebugPrintAllMtrrs ();
+
+ return VariableSettings;
+}
+
+/**
+ Worker function setting fixed MTRRs
+
+ @param[in] FixedSettings A buffer to hold fixed MTRRs content.
+
+**/
+VOID
+MtrrSetFixedMtrrWorker (
+ IN MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ AsmWriteMsr64 (
+ mMtrrLibFixedMtrrTable[Index].Msr,
+ FixedSettings->Mtrr[Index]
+ );
+ }
+}
+
+
+/**
+ This function sets fixed MTRRs
+
+ @param[in] FixedSettings A buffer to hold fixed MTRRs content.
+
+ @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+EFIAPI
+MtrrSetFixedMtrr (
+ IN MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ MTRR_CONTEXT MtrrContext;
+
+ if (!IsMtrrSupported ()) {
+ return FixedSettings;
+ }
+
+ PreMtrrChange (&MtrrContext);
+ MtrrSetFixedMtrrWorker (FixedSettings);
+ PostMtrrChange (&MtrrContext);
+ MtrrDebugPrintAllMtrrs ();
+
+ return FixedSettings;
+}
+
+
+/**
+ This function gets the content in all MTRRs (variable and fixed)
+
+ @param[out] MtrrSetting A buffer to hold all MTRRs content.
+
+ @retval the pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrGetAllMtrrs (
+ OUT MTRR_SETTINGS *MtrrSetting
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return MtrrSetting;
+ }
+
+ //
+ // Get fixed MTRRs
+ //
+ MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+ //
+ // Get variable MTRRs
+ //
+ MtrrGetVariableMtrrWorker (
+ NULL,
+ GetVariableMtrrCountWorker (),
+ &MtrrSetting->Variables
+ );
+
+ //
+ // Get MTRR_DEF_TYPE value
+ //
+ MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
+
+ return MtrrSetting;
+}
+
+
+/**
+ This function sets all MTRRs (variable and fixed)
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+
+ @retval The pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrSetAllMtrrs (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ MTRR_CONTEXT MtrrContext;
+
+ if (!IsMtrrSupported ()) {
+ return MtrrSetting;
+ }
+
+ PreMtrrChange (&MtrrContext);
+
+ //
+ // Set fixed MTRRs
+ //
+ MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+ //
+ // Set variable MTRRs
+ //
+ MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
+
+ //
+ // Set MTRR_DEF_TYPE value
+ //
+ AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
+
+ PostMtrrChangeEnableCache (&MtrrContext);
+
+ MtrrDebugPrintAllMtrrs ();
+
+ return MtrrSetting;
+}
+
+
+/**
+ Checks if MTRR is supported.
+
+ @retval TRUE MTRR is supported.
+ @retval FALSE MTRR is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+IsMtrrSupported (
+ VOID
+ )
+{
+ UINT32 RegEdx;
+ UINT64 MtrrCap;
+
+ //
+ // Check CPUID(1).EDX[12] for MTRR capability
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
+ return FALSE;
+ }
+
+ //
+ // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
+ // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
+ // exist, return false.
+ //
+ MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
+ if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}