X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=UefiCpuPkg%2FLibrary%2FMtrrLib%2FMtrrLib.c;h=f37b740fdf7db5929d7611f86561ab8b5a29b8d6;hb=57994d9c890493760c65922e4fbee7529cbad164;hp=2679725a179340df49b9e9c2b7f62e8725ad33aa;hpb=b8f015999e01100065322fed662efa9584697e37;p=mirror_edk2.git diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 2679725a17..f37b740fdf 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -16,8 +16,7 @@ **/ -#include - +#include #include #include @@ -29,6 +28,12 @@ #define OR_SEED 0x0101010101010101ull #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull +#define MAX_WEIGHT MAX_UINT8 +#define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB) +#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B); + +#define M(x,y) ((x) * VectorCount + (y)) +#define O(x,y) ((y) * VectorCount + (x)) // // Context to save and restore when MTRRs are programmed @@ -38,62 +43,76 @@ typedef struct { BOOLEAN InterruptState; } MTRR_CONTEXT; +typedef struct { + UINT64 Address; + UINT64 Alignment; + UINT64 Length; + UINT8 Type : 7; + + // + // Temprary use for calculating the best MTRR settings. + // + BOOLEAN Visited : 1; + UINT8 Weight; + UINT16 Previous; +} MTRR_LIB_ADDRESS; + // // This table defines the offset, base and length of the fixed MTRRs // CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = { { - MTRR_LIB_IA32_MTRR_FIX64K_00000, + MSR_IA32_MTRR_FIX64K_00000, 0, SIZE_64KB }, { - MTRR_LIB_IA32_MTRR_FIX16K_80000, + MSR_IA32_MTRR_FIX16K_80000, 0x80000, SIZE_16KB }, { - MTRR_LIB_IA32_MTRR_FIX16K_A0000, + MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_C0000, + MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_C8000, + MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_D0000, + MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_D8000, + MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_E0000, + MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_E8000, + MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_F0000, + MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, SIZE_4KB }, { - MTRR_LIB_IA32_MTRR_FIX4K_F8000, + MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, SIZE_4KB } @@ -113,6 +132,21 @@ GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = { "R*" // Invalid }; + +/** + Worker function prints all MTRRs for debugging. + + If MtrrSetting is not NULL, print MTRR settings 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 + ); + /** Worker function returns the variable MTRR count for the CPU. @@ -127,7 +161,7 @@ GetVariableMtrrCountWorker ( MSR_IA32_MTRRCAP_REGISTER MtrrCap; MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP); - ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR); + ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr)); return MtrrCap.Bits.VCNT; } @@ -207,11 +241,15 @@ MtrrGetDefaultMemoryTypeWorker ( IN MTRR_SETTINGS *MtrrSetting ) { + MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType; + if (MtrrSetting == NULL) { - return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); + DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE); } else { - return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7); + DefType.Uint64 = MtrrSetting->MtrrDefType; } + + return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type; } @@ -247,6 +285,7 @@ MtrrLibPreMtrrChange ( OUT MTRR_CONTEXT *MtrrContext ) { + MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType; // // Disable interrupts and save current interrupt state // @@ -271,7 +310,9 @@ MtrrLibPreMtrrChange ( // // Disable MTRRs // - AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0); + DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE); + DefType.Bits.E = 0; + AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64); } /** @@ -323,10 +364,14 @@ MtrrLibPostMtrrChange ( IN MTRR_CONTEXT *MtrrContext ) { + MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType; // // Enable Cache MTRR // - AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3); + DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE); + DefType.Bits.E = 1; + DefType.Bits.FE = 1; + AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64); MtrrLibPostMtrrChangeEnableCache (MtrrContext); } @@ -400,14 +445,17 @@ MtrrGetVariableMtrrWorker ( { UINT32 Index; - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->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); + VariableSettings->Mtrr[Index].Mask = AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1)); + // + // Skip to read the Base MSR when the Mask.V is not set. + // + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) { + VariableSettings->Mtrr[Index].Base = AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1)); + } } else { VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base; VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask; @@ -448,10 +496,10 @@ MtrrGetVariableMtrr ( @param[in] Type 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. + @param[in, out] LastMsrIndex 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. + @param[out] ClearMask The bits to clear in the fixed MTRR MSR. + @param[out] OrMask 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 @@ -463,27 +511,25 @@ MtrrLibProgramFixedMtrr ( IN MTRR_MEMORY_CACHE_TYPE Type, IN OUT UINT64 *Base, IN OUT UINT64 *Length, - IN OUT UINT32 *LastMsrNum, - OUT UINT64 *ReturnClearMask, - OUT UINT64 *ReturnOrMask + IN OUT UINT32 *LastMsrIndex, + OUT UINT64 *ClearMask, + OUT UINT64 *OrMask ) { - UINT32 MsrNum; + UINT32 MsrIndex; 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) && + for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) { + if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) && (*Base < ( - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + - (8 * mMtrrLibFixedMtrrTable[MsrNum].Length) + mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress + + (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length) ) ) ) { @@ -491,65 +537,63 @@ MtrrLibProgramFixedMtrr ( } } - if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) { - return RETURN_UNSUPPORTED; - } + ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable)); // // 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) { + if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) { + // + // Base address should be aligned to the begin of a certain Fixed MTRR range. + // return RETURN_UNSUPPORTED; } + LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length; + ASSERT (LeftByteShift < 8); // // Find the end offset in fixed MTRR and calculate byte offset of right shift // - SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift); + SubLength = mMtrrLibFixedMtrrTable[MsrIndex].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) - ) { + if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) { + // + // Length should be aligned to the end of a certain Fixed MTRR range. + // return RETURN_UNSUPPORTED; } + RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length; // // Update SubLength by actual length // SubLength = *Length; } - ClearMask = CLEAR_SEED; - OrMask = MultU64x32 (OR_SEED, (UINT32) Type); + *ClearMask = CLEAR_SEED; + *OrMask = MultU64x32 (OR_SEED, (UINT32) Type); if (LeftByteShift != 0) { // // Clear the low bits by LeftByteShift // - ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8); - OrMask &= LShiftU64 (OrMask, LeftByteShift * 8); + *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); + *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8); + *OrMask &= RShiftU64 (*OrMask, RightByteShift * 8); } *Length -= SubLength; *Base += SubLength; - *LastMsrNum = MsrNum; - *ReturnClearMask = ClearMask; - *ReturnOrMask = OrMask; + *LastMsrIndex = MsrIndex; return RETURN_SUCCESS; } @@ -561,20 +605,19 @@ MtrrLibProgramFixedMtrr ( 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 + @param[in] VariableSettings The variable MTRR values to shadow + @param[in] VariableMtrrCount The number of variable MTRRs + @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. + @return Number of MTRRs which has been used. **/ UINT32 MtrrGetMemoryAttributeInVariableMtrrWorker ( IN MTRR_VARIABLE_SETTINGS *VariableSettings, - IN UINTN FirmwareVariableMtrrCount, + IN UINTN VariableMtrrCount, IN UINT64 MtrrValidBitsMask, IN UINT64 MtrrValidAddressMask, OUT VARIABLE_MTRR *VariableMtrr @@ -583,12 +626,13 @@ MtrrGetMemoryAttributeInVariableMtrrWorker ( 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) { + ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr)); + for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) { + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 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].Length = + ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1; VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff); VariableMtrr[Index].Valid = TRUE; VariableMtrr[Index].Used = TRUE; @@ -598,6 +642,44 @@ MtrrGetMemoryAttributeInVariableMtrrWorker ( return UsedMtrr; } +/** + Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array. + One MTRR_MEMORY_RANGE element is created for each MTRR setting. + The routine doesn't remove the overlap or combine the near-by region. + + @param[in] VariableSettings The variable MTRR values to shadow + @param[in] VariableMtrrCount The number of variable MTRRs + @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 Number of MTRRs which has been used. + +**/ +UINT32 +MtrrLibGetRawVariableRanges ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN VariableMtrrCount, + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT MTRR_MEMORY_RANGE *VariableMtrr + ) +{ + UINTN Index; + UINT32 UsedMtrr; + + ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr)); + for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) { + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) { + VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask); + VariableMtrr[Index].Length = + ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1; + VariableMtrr[Index].Type = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff); + UsedMtrr++; + } + } + return UsedMtrr; +} /** Gets the attribute of variable MTRRs. @@ -642,401 +724,50 @@ MtrrGetMemoryAttributeInVariableMtrr ( ); } - -/** - 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 covered 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 biggest alignment (lowest set bit) of address. + The function is equivalent to: 1 << LowBitSet64 (Address). - @return The maximum value which is align to power of 2 and less the MemoryLength + @param Address The address to return the alignment. + @param Alignment0 The alignment to return when Address is 0. + @return The least alignment of the Address. **/ UINT64 -Power2MaxMemory ( - IN UINT64 MemoryLength - ) +MtrrLibBiggestAlignment ( + UINT64 Address, + UINT64 Alignment0 +) { - UINT64 Result; - - if (RShiftU64 (MemoryLength, 32) != 0) { - Result = LShiftU64 ( - (UINT64) GetPowerOfTwo32 ( - (UINT32) RShiftU64 (MemoryLength, 32) - ), - 32 - ); - } else { - Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength); + if (Address == 0) { + return Alignment0; } - return Result; + return Address & ((~Address) + 1); } - /** - Determines the MTRR numbers used to program a memory range. + Return whether the left MTRR type precedes the right MTRR type. - 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. + The MTRR type precedence rules are: + 1. UC precedes any other type + 2. WT precedes WB + For further details, please refer the IA32 Software Developer's Manual, + Volume 3, Section "MTRR Precedences". - 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. + @param Left The left MTRR type. + @param Right The right MTRR type. + @retval TRUE Left precedes Right. + @retval FALSE Left doesn't precede Right. **/ 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 - ) +MtrrLibTypeLeftPrecedeRight ( + IN MTRR_MEMORY_CACHE_TYPE Left, + IN MTRR_MEMORY_CACHE_TYPE Right +) { - 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); - } + return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack)); } /** @@ -1054,22 +785,20 @@ MtrrLibInitializeMtrrMask ( OUT UINT64 *MtrrValidAddressMask ) { - UINT32 RegEax; - UINT8 PhysicalAddressBits; - - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + UINT32 MaxExtendedFunction; + CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize; - if (RegEax >= 0x80000008) { - AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); - PhysicalAddressBits = (UINT8) RegEax; + AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL); - *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; - *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; + if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) { + AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL); } else { - *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK; - *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; + VirPhyAddressSize.Bits.PhysicalAddressBits = 36; } + + *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1; + *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; } @@ -1077,71 +806,34 @@ MtrrLibInitializeMtrrMask ( 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, + 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. + Section "MTRR Precedences". @param[in] MtrrType1 The first kind of Memory type @param[in] MtrrType2 The second kind of memory type **/ -UINT64 +MTRR_MEMORY_CACHE_TYPE MtrrLibPrecedence ( - IN UINT64 MtrrType1, - IN UINT64 MtrrType2 + IN MTRR_MEMORY_CACHE_TYPE MtrrType1, + IN MTRR_MEMORY_CACHE_TYPE 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 (MtrrType1 == MtrrType2) { + return MtrrType1; } - if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) { - MtrrType = MtrrType1; + ASSERT ( + MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) || + MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1) + ); + + if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) { + return MtrrType1; + } else { + return MtrrType2; } - return MtrrType; } /** @@ -1163,29 +855,27 @@ MtrrGetMemoryAttributeByAddressWorker ( 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; + MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType; + UINT64 FixedMtrr; + UINTN Index; + UINTN SubIndex; + MTRR_MEMORY_CACHE_TYPE MtrrType; + MTRR_MEMORY_RANGE VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)]; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINT32 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); + DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE); } else { - TempQword = MtrrSetting->MtrrDefType; + DefType.Uint64 = MtrrSetting->MtrrDefType; } - MtrrType = MTRR_CACHE_INVALID_TYPE; - if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + if (DefType.Bits.E == 0) { return CacheUncacheable; } @@ -1193,67 +883,68 @@ MtrrGetMemoryAttributeByAddressWorker ( // 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) { + if (DefType.Bits.FE != 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); - } + 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) { + FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + } else { + FixedMtrr = MtrrSetting->Fixed.Mtrr[Index]; + } + return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF); + } } } } - MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); - MtrrGetVariableMtrrWorker ( - MtrrSetting, - GetVariableMtrrCountWorker (), - &VariableSettings - ); + VariableMtrrCount = GetVariableMtrrCountWorker (); + ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr)); + MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings); - MtrrGetMemoryAttributeInVariableMtrrWorker ( - &VariableSettings, - GetFirmwareVariableMtrrCountWorker (), - MtrrValidBitsMask, - MtrrValidAddressMask, - VariableMtrr - ); + MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); + MtrrLibGetRawVariableRanges ( + &VariableSettings, + VariableMtrrCount, + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); // // Go through the variable MTRR // - VariableMtrrCount = GetVariableMtrrCountWorker (); - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); - + MtrrType = CacheInvalid; for (Index = 0; Index < VariableMtrrCount; Index++) { - if (VariableMtrr[Index].Valid) { + if (VariableMtrr[Index].Length != 0) { if (Address >= VariableMtrr[Index].BaseAddress && - Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { - TempMtrrType = VariableMtrr[Index].Type; - MtrrType = MtrrLibPrecedence (MtrrType, TempMtrrType); + Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) { + if (MtrrType == CacheInvalid) { + MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type; + } else { + MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type); + } } } } - CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType); - - return CacheType; -} - + + // + // If there is no MTRR which covers the Address, use the default MTRR type. + // + if (MtrrType == CacheInvalid) { + MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type; + } + + return MtrrType; +} + /** This function will get the memory cache type of the specific address. @@ -1279,562 +970,1532 @@ MtrrGetMemoryAttribute ( } /** - Worker function prints all MTRRs for debugging. - - If MtrrSetting is not NULL, print MTRR settings from input MTRR - settings buffer. - If MtrrSetting is NULL, print MTRR settings from MTRRs. - - @param MtrrSetting A buffer holding all MTRRs content. + Update the Ranges array to change the specified range identified by + BaseAddress and Length to Type. + + @param Ranges Array holding memory type settings for all memory regions. + @param Capacity The maximum count of memory ranges the array can hold. + @param Count Return the new memory range count in the array. + @param BaseAddress The base address of the memory range to change type. + @param Length The length of the memory range to change type. + @param Type The new type of the specified memory range. + + @retval RETURN_SUCCESS The type of the specified memory range is + changed successfully. + @retval RETURN_ALREADY_STARTED The type of the specified memory range equals + to the desired type. + @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory + range exceeds capacity. **/ -VOID -MtrrDebugPrintAllMtrrsWorker ( - IN MTRR_SETTINGS *MtrrSetting +RETURN_STATUS +MtrrLibSetMemoryType ( + IN MTRR_MEMORY_RANGE *Ranges, + IN UINTN Capacity, + IN OUT UINTN *Count, + IN UINT64 BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Type ) { - 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; + UINTN Index; + UINT64 Limit; + UINT64 LengthLeft; + UINT64 LengthRight; + UINTN StartIndex; + UINTN EndIndex; + UINTN DeltaCount; + + LengthRight = 0; + LengthLeft = 0; + Limit = BaseAddress + Length; + StartIndex = *Count; + EndIndex = *Count; + for (Index = 0; Index < *Count; Index++) { + if ((StartIndex == *Count) && + (Ranges[Index].BaseAddress <= BaseAddress) && + (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) { + StartIndex = Index; + LengthLeft = BaseAddress - Ranges[Index].BaseAddress; + } - if (!IsMtrrSupported ()) { - return; + if ((EndIndex == *Count) && + (Ranges[Index].BaseAddress < Limit) && + (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) { + EndIndex = Index; + LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit; + break; } + } - DEBUG((DEBUG_CACHE, "MTRR Settings\n")); - DEBUG((DEBUG_CACHE, "=============\n")); + ASSERT (StartIndex != *Count && EndIndex != *Count); + if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) { + return RETURN_ALREADY_STARTED; + } - if (MtrrSetting != NULL) { - Mtrrs = MtrrSetting; - } else { - MtrrGetAllMtrrs (&LocalMtrrs); - Mtrrs = &LocalMtrrs; + // + // The type change may cause merging with previous range or next range. + // Update the StartIndex, EndIndex, BaseAddress, Length so that following + // logic doesn't need to consider merging. + // + if (StartIndex != 0) { + if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) { + StartIndex--; + Length += Ranges[StartIndex].Length; + BaseAddress -= Ranges[StartIndex].Length; } + } + if (EndIndex != (*Count) - 1) { + if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) { + EndIndex++; + Length += Ranges[EndIndex].Length; + } + } - 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])); + // + // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4) + // |++++++++++++++++++| 0 3 1=3-0-2 3 + // |+++++++| 0 1 -1=1-0-2 5 + // |+| 0 0 -2=0-0-2 6 + // |+++| 0 0 -1=0-0-2+1 5 + // + // + DeltaCount = EndIndex - StartIndex - 2; + if (LengthLeft == 0) { + DeltaCount++; + } + if (LengthRight == 0) { + DeltaCount++; + } + if (*Count - DeltaCount > Capacity) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // Reserve (-DeltaCount) space + // + CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0])); + *Count -= DeltaCount; + + if (LengthLeft != 0) { + Ranges[StartIndex].Length = LengthLeft; + StartIndex++; + } + if (LengthRight != 0) { + Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length; + Ranges[EndIndex - DeltaCount].Length = LengthRight; + Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type; + } + Ranges[StartIndex].BaseAddress = BaseAddress; + Ranges[StartIndex].Length = Length; + Ranges[StartIndex].Type = Type; + return RETURN_SUCCESS; +} + +/** + Return the number of memory types in range [BaseAddress, BaseAddress + Length). + + @param Ranges Array holding memory type settings for all memory regions. + @param RangeCount The count of memory ranges the array holds. + @param BaseAddress Base address. + @param Length Length. + @param Types Return bit mask to indicate all memory types in the specified range. + + @retval Number of memory types. +**/ +UINT8 +MtrrLibGetNumberOfTypes ( + IN CONST MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount, + IN UINT64 BaseAddress, + IN UINT64 Length, + IN OUT UINT8 *Types OPTIONAL + ) +{ + UINTN Index; + UINT8 TypeCount; + UINT8 LocalTypes; + + TypeCount = 0; + LocalTypes = 0; + for (Index = 0; Index < RangeCount; Index++) { + if ((Ranges[Index].BaseAddress <= BaseAddress) && + (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) + ) { + if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) { + LocalTypes |= (UINT8)(1 << Ranges[Index].Type); + TypeCount++; + } + + if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) { + Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress; + BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length; + } else { + break; + } } + } - 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 - )); + if (Types != NULL) { + *Types = LocalTypes; + } + return TypeCount; +} + +/** + Calculate the least MTRR number from vector Start to Stop and update + the Previous of all vectors from Start to Stop is updated to reflect + how the memory range is covered by MTRR. + + @param VectorCount The count of vectors in the graph. + @param Vector Array holding all vectors. + @param Weight 2-dimention array holding weights between vectors. + @param Start Start vector. + @param Stop Stop vector. + @param IncludeOptional TRUE to count the optional weight. +**/ +VOID +MtrrLibCalculateLeastMtrrs ( + IN UINT16 VectorCount, + IN MTRR_LIB_ADDRESS *Vector, + IN OUT CONST UINT8 *Weight, + IN UINT16 Start, + IN UINT16 Stop, + IN BOOLEAN IncludeOptional + ) +{ + UINT16 Index; + UINT8 MinWeight; + UINT16 MinI; + UINT8 Mandatory; + UINT8 Optional; + + for (Index = Start; Index <= Stop; Index++) { + Vector[Index].Visited = FALSE; + Vector[Index].Previous = VectorCount; + Mandatory = Weight[M(Start,Index)]; + Vector[Index].Weight = Mandatory; + if (Mandatory != MAX_WEIGHT) { + Optional = IncludeOptional ? Weight[O(Start, Index)] : 0; + Vector[Index].Weight += Optional; + ASSERT (Vector[Index].Weight >= Optional); } - 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)); + MinI = Start; + MinWeight = 0; + while (!Vector[Stop].Visited) { + // + // Update the weight from the shortest vector to other unvisited vectors + // + for (Index = Start + 1; Index <= Stop; Index++) { + if (!Vector[Index].Visited) { + Mandatory = Weight[M(MinI, Index)]; + if (Mandatory != MAX_WEIGHT) { + Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0; + if (MinWeight + Mandatory + Optional <= Vector[Index].Weight) { + Vector[Index].Weight = MinWeight + Mandatory + Optional; + Vector[Index].Previous = MinI; // Previous is Start based. } - PreviousMemoryType = MemoryType; - DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); } - Base += mMtrrLibFixedMtrrTable[Index].Length; } } - DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); - VariableMtrrCount = GetVariableMtrrCount (); + // + // Find the shortest vector from Start + // + MinI = VectorCount; + MinWeight = MAX_WEIGHT; + for (Index = Start + 1; Index <= Stop; Index++) { + if (!Vector[Index].Visited && MinWeight > Vector[Index].Weight) { + MinI = Index; + MinWeight = Vector[Index].Weight; + } + } + + // + // Mark the shortest vector from Start as visited + // + Vector[MinI].Visited = TRUE; + } +} + +/** + Append the MTRR setting to MTRR setting array. + + @param Mtrrs Array holding all MTRR settings. + @param MtrrCapacity Capacity of the MTRR array. + @param MtrrCount The count of MTRR settings in array. + @param BaseAddress Base address. + @param Length Length. + @param Type Memory type. + + @retval RETURN_SUCCESS MTRR setting is appended to array. + @retval RETURN_OUT_OF_RESOURCES Array is full. +**/ +RETURN_STATUS +MtrrLibAppendVariableMtrr ( + IN OUT MTRR_MEMORY_RANGE *Mtrrs, + IN UINT32 MtrrCapacity, + IN OUT UINT32 *MtrrCount, + IN UINT64 BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Type + ) +{ + if (*MtrrCount == MtrrCapacity) { + return RETURN_OUT_OF_RESOURCES; + } + + Mtrrs[*MtrrCount].BaseAddress = BaseAddress; + Mtrrs[*MtrrCount].Length = Length; + Mtrrs[*MtrrCount].Type = Type; + (*MtrrCount)++; + return RETURN_SUCCESS; +} + +/** + Return the memory type that has the least precedence. + + @param TypeBits Bit mask of memory type. + + @retval Memory type that has the least precedence. +**/ +MTRR_MEMORY_CACHE_TYPE +MtrrLibLowestType ( + IN UINT8 TypeBits +) +{ + INT8 Type; + + ASSERT (TypeBits != 0); + for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1); + return (MTRR_MEMORY_CACHE_TYPE)Type; +} + +/** + Return TRUE when the Operand is exactly power of 2. + + @retval TRUE Operand is exactly power of 2. + @retval FALSE Operand is not power of 2. +**/ +BOOLEAN +MtrrLibIsPowerOfTwo ( + IN UINT64 Operand +) +{ + ASSERT (Operand != 0); + return (BOOLEAN) ((Operand & (Operand - 1)) == 0); +} + +/** + Calculate the subtractive path from vector Start to Stop. + + @param DefaultType Default memory type. + @param A0 Alignment to use when base address is 0. + @param Ranges Array holding memory type settings for all memory regions. + @param RangeCount The count of memory ranges the array holds. + @param VectorCount The count of vectors in the graph. + @param Vector Array holding all vectors. + @param Weight 2-dimention array holding weights between vectors. + @param Start Start vector. + @param Stop Stop vector. + @param Types Type bit mask of memory range from Start to Stop. + @param TypeCount Number of different memory types from Start to Stop. + @param Mtrrs Array holding all MTRR settings. + @param MtrrCapacity Capacity of the MTRR array. + @param MtrrCount The count of MTRR settings in array. + + @retval RETURN_SUCCESS The subtractive path is calculated successfully. + @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full. + +**/ +RETURN_STATUS +MtrrLibCalculateSubtractivePath ( + IN MTRR_MEMORY_CACHE_TYPE DefaultType, + IN UINT64 A0, + IN CONST MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount, + IN UINT16 VectorCount, + IN MTRR_LIB_ADDRESS *Vector, + IN OUT UINT8 *Weight, + IN UINT16 Start, + IN UINT16 Stop, + IN UINT8 Types, + IN UINT8 TypeCount, + IN OUT MTRR_MEMORY_RANGE *Mtrrs, OPTIONAL + IN UINT32 MtrrCapacity, OPTIONAL + IN OUT UINT32 *MtrrCount OPTIONAL + ) +{ + RETURN_STATUS Status; + UINT64 Base; + UINT64 Length; + UINT8 PrecedentTypes; + UINTN Index; + UINT64 HBase; + UINT64 HLength; + UINT64 SubLength; + UINT16 SubStart; + UINT16 SubStop; + UINT16 Cur; + UINT16 Pre; + MTRR_MEMORY_CACHE_TYPE LowestType; + MTRR_MEMORY_CACHE_TYPE LowestPrecedentType; + + Base = Vector[Start].Address; + Length = Vector[Stop].Address - Base; + + LowestType = MtrrLibLowestType (Types); + + // + // Clear the lowest type (highest bit) to get the precedent types + // + PrecedentTypes = ~(1 << LowestType) & Types; + LowestPrecedentType = MtrrLibLowestType (PrecedentTypes); + + if (Mtrrs == NULL) { + Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1); + Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0); + } - Limit = BIT36 - 1; - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000008) { - AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); - Limit = LShiftU64 (1, RegEax & 0xff) - 1; + // Add all high level ranges + HBase = MAX_UINT64; + HLength = 0; + for (Index = 0; Index < RangeCount; Index++) { + if (Length == 0) { + break; + } + if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) { + continue; } - 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)); + // + // Base is in the Range[Index] + // + if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) { + SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base; + } else { + SubLength = Length; + } + if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) { + // + // Meet a range whose types take precedence. + // Update the [HBase, HBase + HLength) to include the range, + // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence. + // + if (HBase == MAX_UINT64) { + HBase = Base; } + HLength += SubLength; + } - RangeBase = BASE_1MB; - NoRangeBase = BASE_1MB; - RangeLimit = Limit; - NoRangeLimit = Limit; + Base += SubLength; + Length -= SubLength; - 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 (HLength == 0) { + continue; + } - if (Base >= MtrrBase && Base < MtrrLimit) { - Found = TRUE; - } + if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end - if (Base >= MtrrBase && MtrrBase > RangeBase) { - RangeBase = MtrrBase; + // + // Add the MTRRs for each high priority type range + // the range[HBase, HBase + HLength) contains only two types. + // We might use positive or subtractive, depending on which way uses less MTRR + // + for (SubStart = Start; SubStart <= Stop; SubStart++) { + if (Vector[SubStart].Address == HBase) { + break; } - if (Base > MtrrLimit && MtrrLimit > RangeBase) { - RangeBase = MtrrLimit + 1; + } + + for (SubStop = SubStart; SubStop <= Stop; SubStop++) { + if (Vector[SubStop].Address == HBase + HLength) { + break; } - if (Base < MtrrBase && MtrrBase < RangeLimit) { - RangeLimit = MtrrBase - 1; + } + ASSERT (Vector[SubStart].Address == HBase); + ASSERT (Vector[SubStop].Address == HBase + HLength); + + if ((TypeCount == 2) || (SubStart == SubStop - 1)) { + // + // add subtractive MTRRs for [HBase, HBase + HLength) + // [HBase, HBase + HLength) contains only one type. + // while - loop is to split the range to MTRR - compliant aligned range. + // + if (Mtrrs == NULL) { + Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart); + } else { + while (SubStart != SubStop) { + Status = MtrrLibAppendVariableMtrr ( + Mtrrs, MtrrCapacity, MtrrCount, + Vector[SubStart].Address, Vector[SubStart].Length, (MTRR_MEMORY_CACHE_TYPE) Vector[SubStart].Type + ); + if (RETURN_ERROR (Status)) { + return Status; + } + SubStart++; + } } - if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { - RangeLimit = MtrrLimit; + } else { + ASSERT (TypeCount == 3); + MtrrLibCalculateLeastMtrrs (VectorCount, Vector, Weight, SubStart, SubStop, TRUE); + + if (Mtrrs == NULL) { + Weight[M (Start, Stop)] += Vector[SubStop].Weight; + } else { + // When we need to collect the optimal path from SubStart to SubStop + while (SubStop != SubStart) { + Cur = SubStop; + Pre = Vector[Cur].Previous; + SubStop = Pre; + + if (Weight[M (Pre, Cur)] != 0) { + Status = MtrrLibAppendVariableMtrr ( + Mtrrs, MtrrCapacity, MtrrCount, + Vector[Pre].Address, Vector[Cur].Address - Vector[Pre].Address, LowestPrecedentType + ); + if (RETURN_ERROR (Status)) { + return Status; + } + } + if (Pre != Cur - 1) { + Status = MtrrLibCalculateSubtractivePath ( + DefaultType, A0, + Ranges, RangeCount, + VectorCount, Vector, Weight, + Pre, Cur, PrecedentTypes, 2, + Mtrrs, MtrrCapacity, MtrrCount + ); + if (RETURN_ERROR (Status)) { + return Status; + } + } + } } - if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { - NoRangeBase = MtrrLimit + 1; + } + // + // Reset HBase, HLength + // + HBase = MAX_UINT64; + HLength = 0; + } + } + return RETURN_SUCCESS; +} + +/** + Calculate MTRR settings to cover the specified memory ranges. + + @param DefaultType Default memory type. + @param A0 Alignment to use when base address is 0. + @param Ranges Memory range array holding the memory type + settings for all memory address. + @param RangeCount Count of memory ranges. + @param Scratch A temporary scratch buffer that is used to perform the calculation. + This is an optional parameter that may be NULL. + @param ScratchSize Pointer to the size in bytes of the scratch buffer. + It may be updated to the actual required size when the calculation + needs more scratch buffer. + @param Mtrrs Array holding all MTRR settings. + @param MtrrCapacity Capacity of the MTRR array. + @param MtrrCount The count of MTRR settings in array. + + @retval RETURN_SUCCESS Variable MTRRs are allocated successfully. + @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity. + @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation. +**/ +RETURN_STATUS +MtrrLibCalculateMtrrs ( + IN MTRR_MEMORY_CACHE_TYPE DefaultType, + IN UINT64 A0, + IN CONST MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount, + IN VOID *Scratch, + IN OUT UINTN *ScratchSize, + IN OUT MTRR_MEMORY_RANGE *Mtrrs, + IN UINT32 MtrrCapacity, + IN OUT UINT32 *MtrrCount + ) +{ + UINT64 Base0; + UINT64 Base1; + UINTN Index; + UINT64 Base; + UINT64 Length; + UINT64 Alignment; + UINT64 SubLength; + MTRR_LIB_ADDRESS *Vector; + UINT8 *Weight; + UINT32 VectorIndex; + UINT32 VectorCount; + UINTN RequiredScratchSize; + UINT8 TypeCount; + UINT16 Start; + UINT16 Stop; + UINT8 Type; + RETURN_STATUS Status; + + Base0 = Ranges[0].BaseAddress; + Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length; + MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0); + + // + // Count the number of vectors. + // + Vector = (MTRR_LIB_ADDRESS*)Scratch; + for (VectorIndex = 0, Index = 0; Index < RangeCount; Index++) { + Base = Ranges[Index].BaseAddress; + Length = Ranges[Index].Length; + while (Length != 0) { + Alignment = MtrrLibBiggestAlignment (Base, A0); + SubLength = Alignment; + if (SubLength > Length) { + SubLength = GetPowerOfTwo64 (Length); + } + if (VectorIndex < *ScratchSize / sizeof (*Vector)) { + Vector[VectorIndex].Address = Base; + Vector[VectorIndex].Alignment = Alignment; + Vector[VectorIndex].Type = Ranges[Index].Type; + Vector[VectorIndex].Length = SubLength; + } + Base += SubLength; + Length -= SubLength; + VectorIndex++; + } + } + // + // Vector[VectorIndex] = Base1, so whole vector count is (VectorIndex + 1). + // + VectorCount = VectorIndex + 1; + DEBUG (( + DEBUG_CACHE, "VectorCount (%016lx - %016lx) = %d\n", + Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VectorCount + )); + ASSERT (VectorCount < MAX_UINT16); + + RequiredScratchSize = VectorCount * sizeof (*Vector) + VectorCount * VectorCount * sizeof (*Weight); + if (*ScratchSize < RequiredScratchSize) { + *ScratchSize = RequiredScratchSize; + return RETURN_BUFFER_TOO_SMALL; + } + Vector[VectorCount - 1].Address = Base1; + + Weight = (UINT8 *) &Vector[VectorCount]; + // + // Set mandatory weight between any vector to max + // Set optional weight and between any vector and self->self to 0 + // E.g.: + // 00 FF FF FF + // 00 00 FF FF + // 00 00 00 FF + // 00 00 00 00 + // + for (VectorIndex = 0; VectorIndex < VectorCount; VectorIndex++) { + SetMem (&Weight[M(VectorIndex, 0)], VectorIndex + 1, 0); + if (VectorIndex != VectorCount - 1) { + Weight[M (VectorIndex, VectorIndex + 1)] = (DefaultType == Vector[VectorIndex].Type) ? 0 : 1; + SetMem (&Weight[M (VectorIndex, VectorIndex + 2)], VectorCount - VectorIndex - 2, MAX_WEIGHT); + } + } + + for (TypeCount = 2; TypeCount <= 3; TypeCount++) { + for (Start = 0; Start < VectorCount; Start++) { + for (Stop = Start + 2; Stop < VectorCount; Stop++) { + ASSERT (Vector[Stop].Address > Vector[Start].Address); + Length = Vector[Stop].Address - Vector[Start].Address; + if (Length > Vector[Start].Alignment) { + // + // Pickup a new Start when [Start, Stop) cannot be described by one MTRR. + // + break; } - if (Base < MtrrBase && NoRangeLimit > MtrrBase) { - NoRangeLimit = MtrrBase - 1; + if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) { + if (MtrrLibGetNumberOfTypes ( + Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type + ) == TypeCount) { + // + // Update the Weight[Start, Stop] using subtractive path. + // + MtrrLibCalculateSubtractivePath ( + DefaultType, A0, + Ranges, RangeCount, + (UINT16)VectorCount, Vector, Weight, + Start, Stop, Type, TypeCount, + NULL, 0, NULL + ); + } else if (TypeCount == 2) { + // + // Pick up a new Start when we expect 2-type range, but 3-type range is met. + // Because no matter how Stop is increased, we always meet 3-type range. + // + break; + } } } + } + } - if (Found) { - Base = RangeLimit + 1; - } else { - Base = NoRangeLimit + 1; + Status = RETURN_SUCCESS; + MtrrLibCalculateLeastMtrrs ((UINT16) VectorCount, Vector, Weight, 0, (UINT16) VectorCount - 1, FALSE); + Stop = (UINT16) VectorCount - 1; + while (Stop != 0) { + Start = Vector[Stop].Previous; + TypeCount = MAX_UINT8; + Type = 0; + if (Weight[M(Start, Stop)] != 0) { + TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type); + Status = MtrrLibAppendVariableMtrr ( + Mtrrs, MtrrCapacity, MtrrCount, + Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, + MtrrLibLowestType (Type) + ); + if (RETURN_ERROR (Status)) { + break; } - } while (Base < Limit); - DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); - ); + } + + if (Start != Stop - 1) { + // + // substractive path + // + if (TypeCount == MAX_UINT8) { + TypeCount = MtrrLibGetNumberOfTypes ( + Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type + ); + } + Status = MtrrLibCalculateSubtractivePath ( + DefaultType, A0, + Ranges, RangeCount, + (UINT16) VectorCount, Vector, Weight, Start, Stop, + Type, TypeCount, + Mtrrs, MtrrCapacity, MtrrCount + ); + if (RETURN_ERROR (Status)) { + break; + } + } + Stop = Start; + } + return Status; } /** - This function prints all MTRRs for debugging. + Apply the fixed MTRR settings to memory range array. + + @param Fixed The fixed MTRR settings. + @param Ranges Return the memory range array holding memory type + settings for all memory address. + @param RangeCapacity The capacity of memory range array. + @param RangeCount Return the count of memory range. + + @retval RETURN_SUCCESS The memory range array is returned successfully. + @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity. **/ -VOID -EFIAPI -MtrrDebugPrintAllMtrrs ( - VOID +RETURN_STATUS +MtrrLibApplyFixedMtrrs ( + IN MTRR_FIXED_SETTINGS *Fixed, + IN OUT MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCapacity, + IN OUT UINTN *RangeCount ) { - MtrrDebugPrintAllMtrrsWorker (NULL); + RETURN_STATUS Status; + UINTN MsrIndex; + UINTN Index; + MTRR_MEMORY_CACHE_TYPE MemoryType; + UINT64 Base; + + Base = 0; + for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) { + ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress); + for (Index = 0; Index < sizeof (UINT64); Index++) { + MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index]; + Status = MtrrLibSetMemoryType ( + Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType + ); + if (Status == RETURN_OUT_OF_RESOURCES) { + return Status; + } + Base += mMtrrLibFixedMtrrTable[MsrIndex].Length; + } + } + ASSERT (Base == BASE_1MB); + return RETURN_SUCCESS; } - /** - 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. + Apply the variable MTRR settings to memory range array. - @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. + @param VariableMtrr The variable MTRR array. + @param VariableMtrrCount The count of variable MTRRs. + @param Ranges Return the memory range array with new MTRR settings applied. + @param RangeCapacity The capacity of memory range array. + @param RangeCount Return the count of memory range. + @retval RETURN_SUCCESS The memory range array is returned successfully. + @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity. **/ RETURN_STATUS -MtrrSetMemoryAttributeWorker ( - IN OUT MTRR_SETTINGS *MtrrSetting, - IN PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN MTRR_MEMORY_CACHE_TYPE Attribute +MtrrLibApplyVariableMtrrs ( + IN CONST MTRR_MEMORY_RANGE *VariableMtrr, + IN UINT32 VariableMtrrCount, + IN OUT MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCapacity, + IN OUT UINTN *RangeCount ) { - 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; + RETURN_STATUS Status; + UINTN Index; - MtrrContextValid = FALSE; - VariableMtrrCount = 0; - ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings)); - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - FixedSettingsValid[Index] = FALSE; - FixedSettingsModified[Index] = FALSE; + // + // WT > WB + // UC > * + // UC > * (except WB, UC) > WB + // + + // + // 1. Set WB + // + for (Index = 0; Index < VariableMtrrCount; Index++) { + if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) { + Status = MtrrLibSetMemoryType ( + Ranges, RangeCapacity, RangeCount, + VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type + ); + if (Status == RETURN_OUT_OF_RESOURCES) { + return Status; + } + } } - ProgramVariableSettings = FALSE; - if (!IsMtrrSupported ()) { - Status = RETURN_UNSUPPORTED; - goto Done; + // + // 2. Set other types than WB or UC + // + for (Index = 0; Index < VariableMtrrCount; Index++) { + if ((VariableMtrr[Index].Length != 0) && + (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) { + Status = MtrrLibSetMemoryType ( + Ranges, RangeCapacity, RangeCount, + VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type + ); + if (Status == RETURN_OUT_OF_RESOURCES) { + return Status; + } + } } - MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); + // + // 3. Set UC + // + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) { + Status = MtrrLibSetMemoryType ( + Ranges, RangeCapacity, RangeCount, + VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type + ); + if (Status == RETURN_OUT_OF_RESOURCES) { + return Status; + } + } + } + return RETURN_SUCCESS; +} + +/** + Return the memory type bit mask that's compatible to first type in the Ranges. + + @param Ranges Memory range array holding the memory type + settings for all memory address. + @param RangeCount Count of memory ranges. + + @return Compatible memory type bit mask. +**/ +UINT8 +MtrrLibGetCompatibleTypes ( + IN CONST MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount + ) +{ + ASSERT (RangeCount != 0); + + switch (Ranges[0].Type) { + case CacheWriteBack: + case CacheWriteThrough: + return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable); + break; - TempQword = 0; - MemoryType = (UINT64)Attribute; - OverwriteExistingMtrr = FALSE; + case CacheWriteCombining: + case CacheWriteProtected: + return (1 << Ranges[0].Type) | (1 << CacheUncacheable); + break; + + case CacheUncacheable: + if (RangeCount == 1) { + return (1 << CacheUncacheable); + } + return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1); + break; + + case CacheInvalid: + default: + ASSERT (FALSE); + break; + } + return 0; +} + +/** + Overwrite the destination MTRR settings with the source MTRR settings. + This routine is to make sure the modification to destination MTRR settings + is as small as possible. + + @param DstMtrrs Destination MTRR settings. + @param DstMtrrCount Count of destination MTRR settings. + @param SrcMtrrs Source MTRR settings. + @param SrcMtrrCount Count of source MTRR settings. + @param Modified Flag array to indicate which destination MTRR setting is modified. +**/ +VOID +MtrrLibMergeVariableMtrr ( + MTRR_MEMORY_RANGE *DstMtrrs, + UINT32 DstMtrrCount, + MTRR_MEMORY_RANGE *SrcMtrrs, + UINT32 SrcMtrrCount, + BOOLEAN *Modified + ) +{ + UINT32 DstIndex; + UINT32 SrcIndex; + + ASSERT (SrcMtrrCount <= DstMtrrCount); + + for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) { + Modified[DstIndex] = FALSE; + + if (DstMtrrs[DstIndex].Length == 0) { + continue; + } + for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) { + if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress && + DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length && + DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) { + break; + } + } + + if (SrcIndex == SrcMtrrCount) { + // + // Remove the one from DstMtrrs which is not in SrcMtrrs + // + DstMtrrs[DstIndex].Length = 0; + Modified[DstIndex] = TRUE; + } else { + // + // Remove the one from SrcMtrrs which is also in DstMtrrs + // + SrcMtrrs[SrcIndex].Length = 0; + } + } // - // Check for an invalid parameter + // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs. + // Merge MTRRs from SrcMtrrs to DstMtrrs // - if (Length == 0) { - Status = RETURN_INVALID_PARAMETER; - goto Done; - } + DstIndex = 0; + for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) { + if (SrcMtrrs[SrcIndex].Length != 0) { - if ( - (BaseAddress & ~MtrrValidAddressMask) != 0 || - (Length & ~MtrrValidAddressMask) != 0 - ) { - Status = RETURN_UNSUPPORTED; - goto Done; + // + // Find the empty slot in DstMtrrs + // + while (DstIndex < DstMtrrCount) { + if (DstMtrrs[DstIndex].Length == 0) { + break; + } + DstIndex++; + } + ASSERT (DstIndex < DstMtrrCount); + CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0])); + Modified[DstIndex] = TRUE; + } } +} + +/** + Calculate the variable MTRR settings for all memory ranges. + + @param DefaultType Default memory type. + @param A0 Alignment to use when base address is 0. + @param Ranges Memory range array holding the memory type + settings for all memory address. + @param RangeCount Count of memory ranges. + @param Scratch Scratch buffer to be used in MTRR calculation. + @param ScratchSize Pointer to the size of scratch buffer. + @param VariableMtrr Array holding all MTRR settings. + @param VariableMtrrCapacity Capacity of the MTRR array. + @param VariableMtrrCount The count of MTRR settings in array. + + @retval RETURN_SUCCESS Variable MTRRs are allocated successfully. + @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity. + @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation. + The required scratch buffer size is returned through ScratchSize. +**/ +RETURN_STATUS +MtrrLibSetMemoryRanges ( + IN MTRR_MEMORY_CACHE_TYPE DefaultType, + IN UINT64 A0, + IN MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount, + IN VOID *Scratch, + IN OUT UINTN *ScratchSize, + OUT MTRR_MEMORY_RANGE *VariableMtrr, + IN UINT32 VariableMtrrCapacity, + OUT UINT32 *VariableMtrrCount + ) +{ + RETURN_STATUS Status; + UINT32 Index; + UINT64 Base0; + UINT64 Base1; + UINT64 Alignment; + UINT8 CompatibleTypes; + UINT64 Length; + UINT32 End; + UINTN ActualScratchSize; + UINTN BiggestScratchSize; + *VariableMtrrCount = 0; + // - // Check if Fixed MTRR + // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs(). + // Each call needs different scratch buffer size. + // When the provided scratch buffer size is not sufficient in any call, + // set the GetActualScratchSize to TRUE, and following calls will only + // calculate the actual scratch size for the caller. // - Status = RETURN_SUCCESS; - if (BaseAddress < BASE_1MB) { - MsrNum = (UINT32)-1; - while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { - Status = MtrrLibProgramFixedMtrr (Attribute, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask); - if (RETURN_ERROR (Status)) { - goto Done; + BiggestScratchSize = 0; + + for (Index = 0; Index < RangeCount;) { + Base0 = Ranges[Index].BaseAddress; + + // + // Full step is optimal + // + while (Index < RangeCount) { + ASSERT (Ranges[Index].BaseAddress == Base0); + Alignment = MtrrLibBiggestAlignment (Base0, A0); + while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) { + if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) { + Status = MtrrLibAppendVariableMtrr ( + VariableMtrr, VariableMtrrCapacity, VariableMtrrCount, + Base0, Alignment, Ranges[Index].Type + ); + if (RETURN_ERROR (Status)) { + return Status; + } + } + Base0 += Alignment; + Alignment = MtrrLibBiggestAlignment (Base0, A0); } - if (MtrrSetting != NULL) { - MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask; - MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED; + + // + // Remove the above range from Ranges[Index] + // + Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress; + Ranges[Index].BaseAddress = Base0; + if (Ranges[Index].Length != 0) { + break; } 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; - } + Index++; + } + } + + if (Index == RangeCount) { + break; + } + + // + // Find continous ranges [Base0, Base1) which could be combined by MTRR. + // Per SDM, the compatible types between[B0, B1) are: + // UC, * + // WB, WT + // UC, WB, WT + // + CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index); + + End = Index; // End points to last one that matches the CompatibleTypes. + while (End + 1 < RangeCount) { + if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) { + break; } + End++; + } + Alignment = MtrrLibBiggestAlignment (Base0, A0); + Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0); + Base1 = Base0 + MIN (Alignment, Length); + + // + // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to. + // + End = Index; + while (End + 1 < RangeCount) { + if (Base1 <= Ranges[End + 1].BaseAddress) { + break; + } + End++; + } + + Length = Ranges[End].Length; + Ranges[End].Length = Base1 - Ranges[End].BaseAddress; + ActualScratchSize = *ScratchSize; + Status = MtrrLibCalculateMtrrs ( + DefaultType, A0, + &Ranges[Index], End + 1 - Index, + Scratch, &ActualScratchSize, + VariableMtrr, VariableMtrrCapacity, VariableMtrrCount + ); + if (Status == RETURN_BUFFER_TOO_SMALL) { + BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize); + // + // Ignore this error, because we need to calculate the biggest + // scratch buffer size. + // + Status = RETURN_SUCCESS; + } + if (RETURN_ERROR (Status)) { + return Status; + } + + if (Length != Ranges[End].Length) { + Ranges[End].BaseAddress = Base1; + Ranges[End].Length = Length - Ranges[End].Length; + Index = End; + } else { + Index = End + 1; } + } + + if (*ScratchSize < BiggestScratchSize) { + *ScratchSize = BiggestScratchSize; + return RETURN_BUFFER_TOO_SMALL; + } + return RETURN_SUCCESS; +} + +/** + Set the below-1MB memory attribute to fixed MTRR buffer. + Modified flag array indicates which fixed MTRR is modified. + + @param [in, out] FixedSettings Fixed MTRR buffer. + @param [out] Modified Flag array indicating which MTRR is modified. + @param [in] BaseAddress Base address. + @param [in] Length Length. + @param [in] Type Memory type. + + @retval RETURN_SUCCESS The memory attribute is set successfully. + @retval RETURN_UNSUPPORTED The requested range or cache type was invalid + for the fixed MTRRs. +**/ +RETURN_STATUS +MtrrLibSetBelow1MBMemoryAttribute ( + IN OUT MTRR_FIXED_SETTINGS *FixedSettings, + OUT BOOLEAN *Modified, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Type + ) +{ + RETURN_STATUS Status; + UINT32 MsrIndex; + UINT64 ClearMask; + UINT64 OrMask; + UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)]; + UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)]; + BOOLEAN LocalModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)]; + + ASSERT (BaseAddress < BASE_1MB); + + SetMem (LocalModified, sizeof (LocalModified), FALSE); + + // + // (Value & ~0 | 0) still equals to (Value) + // + SetMem (ClearMasks, sizeof (ClearMasks), 0); + SetMem (OrMasks, sizeof (OrMasks), 0); + + MsrIndex = (UINT32)-1; + while ((BaseAddress < BASE_1MB) && (Length != 0)) { + Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask); + if (RETURN_ERROR (Status)) { + return Status; + } + ClearMasks[MsrIndex] = ClearMask; + OrMasks[MsrIndex] = OrMask; + Modified[MsrIndex] = TRUE; + LocalModified[MsrIndex] = TRUE; + } + + for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) { + if (LocalModified[MsrIndex]) { + FixedSettings->Mtrr[MsrIndex] = (FixedSettings->Mtrr[MsrIndex] & ~ClearMasks[MsrIndex]) | OrMasks[MsrIndex]; + } + } + return RETURN_SUCCESS; +} + +/** + This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges. + + @param[in, out] MtrrSetting MTRR setting buffer to be set. + @param[in] Scratch A temporary scratch buffer that is used to perform the calculation. + @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer. + It may be updated to the actual required size when the calculation + needs more scratch buffer. + @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE. + When range overlap happens, the last one takes higher priority. + When the function returns, either all the attributes are set successfully, + or none of them is set. + @param[in] RangeCount Count of MTRR_MEMORY_RANGE. + + @retval RETURN_SUCCESS The attributes were set for all the memory ranges. + @retval RETURN_INVALID_PARAMETER Length in any range is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the + memory resource range specified by BaseAddress and Length in any range. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length in any range. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource ranges. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation. +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttributesInMtrrSettings ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN VOID *Scratch, + IN OUT UINTN *ScratchSize, + IN CONST MTRR_MEMORY_RANGE *Ranges, + IN UINTN RangeCount + ) +{ + RETURN_STATUS Status; + UINT32 Index; + UINT64 BaseAddress; + UINT64 Length; + BOOLEAN Above1MbExist; + + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + MTRR_MEMORY_CACHE_TYPE DefaultType; + MTRR_VARIABLE_SETTINGS VariableSettings; + MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2]; + UINTN WorkingRangeCount; + BOOLEAN Modified; + MTRR_VARIABLE_SETTING VariableSetting; + UINT32 OriginalVariableMtrrCount; + UINT32 FirmwareVariableMtrrCount; + UINT32 WorkingVariableMtrrCount; + MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)]; + MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)]; + BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)]; - 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; - } - } + BOOLEAN FixedSettingsModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)]; + MTRR_FIXED_SETTINGS WorkingFixedSettings; + + MTRR_CONTEXT MtrrContext; + BOOLEAN MtrrContextValid; + + MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); // - // Since memory ranges below 1MB will be overridden by the fixed MTRRs, - // we can set the base to 0 to save variable MTRRs. + // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr. // - if (BaseAddress == BASE_1MB) { - BaseAddress = 0; - Length += SIZE_1MB; - } + SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE); + // + // TRUE indicating the accordingly Fixed setting needs modification in WorkingFixedSettings. + // + SetMem (FixedSettingsModified, ARRAY_SIZE (FixedSettingsModified), FALSE); // - // Read all variable MTRRs + // TRUE indicating the caller requests to set 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; - } + Above1MbExist = FALSE; + OriginalVariableMtrrCount = 0; // - // Check for overlap + // 1. Validate the parameters. // - 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; + for (Index = 0; Index < RangeCount; Index++) { + if (Ranges[Index].Length == 0) { + return RETURN_INVALID_PARAMETER; } - - if (Length == 0) { - // - // Combined successfully, invalidate the now-unused MTRRs - // - InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); - Status = RETURN_SUCCESS; - goto Done; + if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) || + ((Ranges[Index].Length & ~MtrrValidAddressMask) != 0) + ) { + return RETURN_UNSUPPORTED; + } + if ((Ranges[Index].Type != CacheUncacheable) && + (Ranges[Index].Type != CacheWriteCombining) && + (Ranges[Index].Type != CacheWriteThrough) && + (Ranges[Index].Type != CacheWriteProtected) && + (Ranges[Index].Type != CacheWriteBack)) { + return RETURN_INVALID_PARAMETER; + } + if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) { + Above1MbExist = TRUE; } } // - // The memory type is the same with the type specified by - // MTRR_LIB_IA32_MTRR_DEF_TYPE. + // 2. Apply the above-1MB memory attribute settings. // - if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) { + if (Above1MbExist) { // - // Invalidate the now-unused MTRRs + // 2.1. Read all variable MTRRs and convert to Ranges. // - InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); - goto Done; - } + OriginalVariableMtrrCount = GetVariableMtrrCountWorker (); + MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings); + MtrrLibGetRawVariableRanges ( + &VariableSettings, OriginalVariableMtrrCount, + MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr + ); - Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber); + DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting); + WorkingRangeCount = 1; + WorkingRanges[0].BaseAddress = 0; + WorkingRanges[0].Length = MtrrValidBitsMask + 1; + WorkingRanges[0].Type = DefaultType; - if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { - Status = RETURN_OUT_OF_RESOURCES; - goto Done; - } + Status = MtrrLibApplyVariableMtrrs ( + OriginalVariableMtrr, OriginalVariableMtrrCount, + WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount); + ASSERT_RETURN_ERROR (Status); - // - // Invalidate the now-unused MTRRs - // - InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); + ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs)); + FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs); + ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1); - // - // Find first unused MTRR - // - for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) { - if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { - break; + // + // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm. + // + Status = MtrrLibSetMemoryType ( + WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount, + 0, SIZE_1MB, CacheUncacheable + ); + ASSERT (Status != RETURN_OUT_OF_RESOURCES); + + // + // 2.3. Apply the new memory attribute settings to Ranges. + // + Modified = FALSE; + for (Index = 0; Index < RangeCount; Index++) { + BaseAddress = Ranges[Index].BaseAddress; + Length = Ranges[Index].Length; + if (BaseAddress < BASE_1MB) { + if (Length <= BASE_1MB - BaseAddress) { + continue; + } + Length -= BASE_1MB - BaseAddress; + BaseAddress = BASE_1MB; + } + Status = MtrrLibSetMemoryType ( + WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount, + BaseAddress, Length, Ranges[Index].Type + ); + if (Status == RETURN_ALREADY_STARTED) { + Status = RETURN_SUCCESS; + } else if (Status == RETURN_OUT_OF_RESOURCES) { + return Status; + } else { + ASSERT_RETURN_ERROR (Status); + Modified = TRUE; + } } - } - if (BaseAddress != 0) { - do { + if (Modified) { // - // Calculate the alignment of the base address. + // 2.4. Calculate the Variable MTRR settings based on the Ranges. + // Buffer Too Small may be returned if the scratch buffer size is insufficient. // - Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); - - if (Alignment > Length) { - break; + Status = MtrrLibSetMemoryRanges ( + DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount, + Scratch, ScratchSize, + WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount + ); + if (RETURN_ERROR (Status)) { + return Status; } // - // Find unused MTRR + // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range) // - for (; MsrNum < VariableMtrrCount; MsrNum++) { - if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + for (Index = 0; Index < WorkingVariableMtrrCount; Index++) { + if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) { + ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable); + WorkingVariableMtrrCount--; + CopyMem ( + &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1], + (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[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; + if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) { + return RETURN_OUT_OF_RESOURCES; } - } - ProgramVariableMtrr ( - VariableSettings, - MsrNum, - BaseAddress, - Length, - MemoryType, - MtrrValidAddressMask + // + // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr + // Make sure least modification is made to OriginalVariableMtrr. + // + MtrrLibMergeVariableMtrr ( + OriginalVariableMtrr, OriginalVariableMtrrCount, + WorkingVariableMtrr, WorkingVariableMtrrCount, + VariableSettingModified ); - 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; + // + // 3. Apply the below-1MB memory attribute settings. + // + ZeroMem (WorkingFixedSettings.Mtrr, sizeof (WorkingFixedSettings.Mtrr)); + for (Index = 0; Index < RangeCount; Index++) { + if (Ranges[Index].BaseAddress >= BASE_1MB) { + continue; } - ProgramVariableMtrr ( - VariableSettings, - MsrNum, - BaseAddress, - Length, - MemoryType, - MtrrValidAddressMask - ); - - if (Positive) { - BaseAddress += Length; + Status = MtrrLibSetBelow1MBMemoryAttribute ( + &WorkingFixedSettings, FixedSettingsModified, + Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type + ); + if (RETURN_ERROR (Status)) { + return Status; } - TempQword -= Length; - - } while (TempQword > 0); - -Done: + } + MtrrContextValid = FALSE; // - // Write fixed MTRRs that have been modified + // 4. Write fixed MTRRs that have been modified // - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + for (Index = 0; Index < ARRAY_SIZE (FixedSettingsModified); Index++) { if (FixedSettingsModified[Index]) { - if (!MtrrContextValid) { - MtrrLibPreMtrrChange (&MtrrContext); - MtrrContextValid = TRUE; - } - AsmWriteMsr64 ( - mMtrrLibFixedMtrrTable[Index].Msr, - WorkingFixedSettings.Mtrr[Index] + if (MtrrSetting != NULL) { + MtrrSetting->Fixed.Mtrr[Index] = WorkingFixedSettings.Mtrr[Index]; + } else { + if (!MtrrContextValid) { + MtrrLibPreMtrrChange (&MtrrContext); + MtrrContextValid = TRUE; + } + AsmWriteMsr64 ( + mMtrrLibFixedMtrrTable[Index].Msr, + WorkingFixedSettings.Mtrr[Index] ); + } } } // - // Write variable MTRRs + // 5. Write variable MTRRs that have been modified // - 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 ) { + for (Index = 0; Index < OriginalVariableMtrrCount; Index++) { + if (VariableSettingModified[Index]) { + if (OriginalVariableMtrr[Index].Length != 0) { + VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) + | (UINT8)OriginalVariableMtrr[Index].Type; + VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11; + } else { + VariableSetting.Base = 0; + VariableSetting.Mask = 0; + } + if (MtrrSetting != NULL) { + CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting)); + } else { if (!MtrrContextValid) { MtrrLibPreMtrrChange (&MtrrContext); MtrrContextValid = TRUE; } AsmWriteMsr64 ( - MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1), - WorkingVariableSettings.Mtrr[Index].Base - ); + MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), + VariableSetting.Base + ); AsmWriteMsr64 ( - MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1, - WorkingVariableSettings.Mtrr[Index].Mask - ); + MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), + VariableSetting.Mask + ); } } } - if (MtrrContextValid) { - MtrrLibPostMtrrChange (&MtrrContext); + + if (MtrrSetting != NULL) { + ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1; + ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1; + } else { + if (MtrrContextValid) { + MtrrLibPostMtrrChange (&MtrrContext); + } + } + + return RETURN_SUCCESS; +} + +/** + 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 range. + @param[in] Length The size in bytes of the memory range. + @param[in] Attribute The bit mask of attributes to set for the + memory range. + + @retval RETURN_SUCCESS The attributes were set for the memory range. + @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. + @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation. +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttributeInMtrrSettings ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + RETURN_STATUS Status; + UINT8 Scratch[SCRATCH_BUFFER_SIZE]; + UINTN ScratchSize; + MTRR_MEMORY_RANGE Range; + + if (!IsMtrrSupported ()) { + return RETURN_UNSUPPORTED; } - DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); + Range.BaseAddress = BaseAddress; + Range.Length = Length; + Range.Type = Attribute; + ScratchSize = sizeof (Scratch); + Status = MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1); + DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute(MtrrSettings = %p) %a: [%016lx, %016lx) - %r\n", + MtrrSetting, + mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status)); + if (!RETURN_ERROR (Status)) { - if (MtrrSetting != NULL) { - MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED; - } MtrrDebugPrintAllMtrrsWorker (MtrrSetting); } - return Status; } @@ -1842,13 +2503,13 @@ Done: 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. + address of a memory range. + @param[in] Length The size in bytes of the memory range. @param[in] Attributes The bit mask of attributes to set for the - memory region. + memory range. @retval RETURN_SUCCESS The attributes were set for the memory - region. + range. @retval RETURN_INVALID_PARAMETER Length is zero. @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory resource range @@ -1862,7 +2523,7 @@ Done: @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of the memory resource range. - + @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation. **/ RETURN_STATUS EFIAPI @@ -1872,53 +2533,7 @@ MtrrSetMemoryAttribute ( 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 - ); + return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute); } /** @@ -1936,17 +2551,17 @@ MtrrSetVariableMtrrWorker ( UINT32 VariableMtrrCount; VariableMtrrCount = GetVariableMtrrCountWorker (); - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->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 - ); + // + // Mask MSR is always updated since caller might need to invalidate the MSR pair. + // Base MSR is skipped when Mask.V is not set. + // + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSettings->Mtrr[Index].Mask); + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) { + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSettings->Mtrr[Index].Base); + } } } @@ -2065,7 +2680,7 @@ MtrrGetAllMtrrs ( // // Get MTRR_DEF_TYPE value // - MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE); return MtrrSetting; } @@ -2106,7 +2721,7 @@ MtrrSetAllMtrrs ( // // Set MTRR_DEF_TYPE value // - AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); + AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); MtrrLibPostMtrrChangeEnableCache (&MtrrContext); @@ -2149,3 +2764,112 @@ IsMtrrSupported ( } return TRUE; } + + +/** + Worker function prints all MTRRs for debugging. + + If MtrrSetting is not NULL, print MTRR settings 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 RangeCount; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINT32 VariableMtrrCount; + MTRR_MEMORY_RANGE Ranges[ + ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1 + ]; + MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)]; + + if (!IsMtrrSupported ()) { + return; + } + + VariableMtrrCount = GetVariableMtrrCountWorker (); + + if (MtrrSetting != NULL) { + Mtrrs = MtrrSetting; + } else { + MtrrGetAllMtrrs (&LocalMtrrs); + Mtrrs = &LocalMtrrs; + } + + // + // Dump RAW MTRR contents + // + DEBUG((DEBUG_CACHE, "MTRR Settings\n")); + DEBUG((DEBUG_CACHE, "=============\n")); + DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType)); + for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) { + DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index])); + } + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 0) { + // + // If mask is not valid, then do not display range + // + continue; + } + 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")); + + // + // Dump MTRR setting in ranges + // + DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); + DEBUG((DEBUG_CACHE, "====================================\n")); + MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); + Ranges[0].BaseAddress = 0; + Ranges[0].Length = MtrrValidBitsMask + 1; + Ranges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs); + RangeCount = 1; + + MtrrLibGetRawVariableRanges ( + &Mtrrs->Variables, VariableMtrrCount, + MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges + ); + MtrrLibApplyVariableMtrrs ( + RawVariableRanges, VariableMtrrCount, + Ranges, ARRAY_SIZE (Ranges), &RangeCount + ); + + MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount); + + for (Index = 0; Index < RangeCount; Index++) { + DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n", + mMtrrMemoryCacheTypeShortName[Ranges[Index].Type], + Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1 + )); + } + ); +} + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ) +{ + MtrrDebugPrintAllMtrrsWorker (NULL); +}