| /** @file | |
| MTRR setting library | |
| @par Note: | |
| Most of services in this library instance are suggested to be invoked by BSP only, | |
| except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs. | |
| 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 parameter 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); | |
| 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; | |
| } |