3 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/BaseLib.h>
10 #include <Library/CacheLib.h>
11 #include <Library/CacheAsRamLib.h>
12 #include "CacheLibInternal.h"
15 Search the memory cache type for specific memory from MTRR.
17 @param[in] MemoryAddress the address of target memory
18 @param[in] MemoryLength the length of target memory
19 @param[in] ValidMtrrAddressMask the MTRR address mask
20 @param[out] UsedMsrNum the used MSR number
21 @param[out] UsedMemoryCacheType the cache type for the target memory
23 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
24 @retval EFI_NOT_FOUND The memory is not found in MTRR
29 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
30 IN UINT64 MemoryLength
,
31 IN UINT64 ValidMtrrAddressMask
,
32 OUT UINT32
*UsedMsrNum
,
33 OUT EFI_MEMORY_CACHE_TYPE
*MemoryCacheType
37 Check if CacheType match current default setting.
39 @param[in] MemoryCacheType input cache type to be checked.
41 @retval TRUE MemoryCacheType is default MTRR setting.
42 @retval FALSE MemoryCacheType is NOT default MTRR setting.
46 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
50 Return MTRR alignment requirement for base address and size.
52 @param[in] BaseAddress Base address.
56 @retval Non-Zero Not aligned.
61 IN UINT64 BaseAddress
,
71 EFI_FIXED_MTRR mFixedMtrrTable
[] = {
72 { EFI_MSR_IA32_MTRR_FIX64K_00000
, 0, 0x10000 },
73 { EFI_MSR_IA32_MTRR_FIX16K_80000
, 0x80000, 0x4000 },
74 { EFI_MSR_IA32_MTRR_FIX16K_A0000
, 0xA0000, 0x4000 },
75 { EFI_MSR_IA32_MTRR_FIX4K_C0000
, 0xC0000, 0x1000 },
76 { EFI_MSR_IA32_MTRR_FIX4K_C8000
, 0xC8000, 0x1000 },
77 { EFI_MSR_IA32_MTRR_FIX4K_D0000
, 0xD0000, 0x1000 },
78 { EFI_MSR_IA32_MTRR_FIX4K_D8000
, 0xD8000, 0x1000 },
79 { EFI_MSR_IA32_MTRR_FIX4K_E0000
, 0xE0000, 0x1000 },
80 { EFI_MSR_IA32_MTRR_FIX4K_E8000
, 0xE8000, 0x1000 },
81 { EFI_MSR_IA32_MTRR_FIX4K_F0000
, 0xF0000, 0x1000 },
82 { EFI_MSR_IA32_MTRR_FIX4K_F8000
, 0xF8000, 0x1000 }
86 Given the input, check if the number of MTRR is lesser.
87 if positive or subtractive.
89 @param[in] Input Length of Memory to program MTRR.
91 @retval Zero do positive.
92 @retval Non-Zero do subtractive.
104 Disable cache and its mtrr.
106 @param[out] OldMtrr To return the Old MTRR value
110 EfiDisableCacheMtrr (
117 // Disable Cache MTRR
119 *OldMtrr
= AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
);
120 TempQword
= (*OldMtrr
) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE
& ~B_EFI_MSR_FIXED_MTRR_ENABLE
;
121 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, TempQword
);
128 @param[in] EnableMtrr Whether to enable the MTRR
129 @param[in] OldMtrr The saved old MTRR value to restore when not to enable the MTRR
133 EfiRecoverCacheMtrr (
134 IN BOOLEAN EnableMtrr
,
144 TempQword
= AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
);
145 TempQword
|= (UINT64
)(B_EFI_MSR_GLOBAL_MTRR_ENABLE
| B_EFI_MSR_FIXED_MTRR_ENABLE
);
150 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, TempQword
);
156 Programming MTRR according to Memory address, length, and type.
158 @param[in] MtrrNumber the variable MTRR index number
159 @param[in] MemoryAddress the address of target memory
160 @param[in] MemoryLength the length of target memory
161 @param[in] MemoryCacheType the cache type of target memory
162 @param[in] ValidMtrrAddressMask the MTRR address mask
167 IN UINT32 MtrrNumber
,
168 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
169 IN UINT64 MemoryLength
,
170 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
,
171 IN UINT64 ValidMtrrAddressMask
177 if (MemoryLength
== 0) {
181 EfiDisableCacheMtrr (&OldMtrr
);
184 // MTRR Physical Base
186 TempQword
= (MemoryAddress
& ValidMtrrAddressMask
) | MemoryCacheType
;
187 AsmWriteMsr64 (MtrrNumber
, TempQword
);
190 // MTRR Physical Mask
192 TempQword
= ~(MemoryLength
- 1);
193 AsmWriteMsr64 (MtrrNumber
+ 1, (TempQword
& ValidMtrrAddressMask
) | B_EFI_MSR_CACHE_MTRR_VALID
);
195 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
199 Calculate the maximum value which is a power of 2, but less the MemoryLength.
201 @param[in] MemoryAddress Memory address.
202 @param[in] MemoryLength The number to pass in.
204 @return The maximum value which is align to power of 2 and less the MemoryLength
209 IN UINT64 MemoryAddress
,
210 IN UINT64 MemoryLength
215 if (MemoryLength
== 0) {
216 return EFI_INVALID_PARAMETER
;
220 // Compute initial power of 2 size to return
222 Result
= GetPowerOfTwo64 (MemoryLength
);
225 // Special case base of 0 as all ranges are valid
227 if (MemoryAddress
== 0) {
232 // Loop till a value that can be mapped to this base address is found
234 while (CheckMtrrAlignment (MemoryAddress
, Result
) != 0) {
236 // Need to try the next smaller power of 2
238 Result
= RShiftU64 (Result
, 1);
245 Return MTRR alignment requirement for base address and size.
247 @param[in] BaseAddress Base address.
248 @param[in] Size Size.
250 @retval Zero Aligned.
251 @retval Non-Zero Not aligned.
256 IN UINT64 BaseAddress
,
264 // Shift base and size right 12 bits to allow for larger memory sizes. The
265 // MTRRs do not use the first 12 bits so this is safe for now. Only supports
266 // up to 52 bits of physical address space.
268 ShiftedBase
= (UINT32
)RShiftU64 (BaseAddress
, 12);
269 ShiftedSize
= (UINT32
)RShiftU64 (Size
, 12);
272 // Return the results to the caller of the MOD
274 return ShiftedBase
% ShiftedSize
;
278 Programs fixed MTRRs registers.
280 @param[in] MemoryCacheType The memory type to set.
281 @param[in] Base The base address of memory range.
282 @param[in] Length The length of memory range.
284 @retval RETURN_SUCCESS The cache type was updated successfully
285 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
291 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
,
306 for (MsrNum
= 0; MsrNum
< V_EFI_FIXED_MTRR_NUMBER
; MsrNum
++) {
307 if ((*Base
>= mFixedMtrrTable
[MsrNum
].BaseAddress
) &&
308 (*Base
< (mFixedMtrrTable
[MsrNum
].BaseAddress
+ 8 * mFixedMtrrTable
[MsrNum
].Length
)))
314 if (MsrNum
== V_EFI_FIXED_MTRR_NUMBER
) {
315 return EFI_DEVICE_ERROR
;
319 // We found the fixed MTRR to be programmed
321 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
322 if ( *Base
== (mFixedMtrrTable
[MsrNum
].BaseAddress
+ ByteShift
* mFixedMtrrTable
[MsrNum
].Length
)) {
327 if (ByteShift
== 8 ) {
328 return EFI_DEVICE_ERROR
;
331 for ( ; ((ByteShift
< 8) && (*Len
>= mFixedMtrrTable
[MsrNum
].Length
)); ByteShift
++) {
332 OrMask
|= LShiftU64 ((UINT64
)MemoryCacheType
, (UINT32
)(ByteShift
* 8));
333 ClearMask
|= LShiftU64 ((UINT64
)0xFF, (UINT32
)(ByteShift
* 8));
334 *Len
-= mFixedMtrrTable
[MsrNum
].Length
;
335 *Base
+= mFixedMtrrTable
[MsrNum
].Length
;
338 TempQword
= (AsmReadMsr64 (mFixedMtrrTable
[MsrNum
].Msr
) & (~ClearMask
)) | OrMask
;
339 AsmWriteMsr64 (mFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
345 Check if there is a valid variable MTRR that overlaps the given range.
347 @param[in] Start Base Address of the range to check.
348 @param[in] End End address of the range to check.
350 @retval TRUE Mtrr overlap.
351 @retval FALSE Mtrr not overlap.
355 IN EFI_PHYSICAL_ADDRESS Start
,
356 IN EFI_PHYSICAL_ADDRESS End
363 Given the memory range and cache type, programs the MTRRs.
365 @param[in] MemoryAddress Base Address of Memory to program MTRR.
366 @param[in] MemoryLength Length of Memory to program MTRR.
367 @param[in] MemoryCacheType Cache Type.
369 @retval EFI_SUCCESS Mtrr are set successfully.
370 @retval EFI_LOAD_ERROR No empty MTRRs to use.
371 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
372 @retval others An error occurs when setting MTTR.
378 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
379 IN UINT64 MemoryLength
,
380 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
384 UINT32 MsrNum
, MsrNumEnd
;
386 UINT32 LastVariableMtrrForBios
;
389 EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType
;
390 UINT64 ValidMtrrAddressMask
;
393 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &Cpuid_RegEax
, NULL
, NULL
, NULL
);
394 if (Cpuid_RegEax
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
395 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &Cpuid_RegEax
, NULL
, NULL
, NULL
);
396 ValidMtrrAddressMask
= (LShiftU64 ((UINT64
)1, (Cpuid_RegEax
& 0xFF)) - 1) & (~(UINT64
)0x0FFF);
398 ValidMtrrAddressMask
= (LShiftU64 ((UINT64
)1, 36) - 1) & (~(UINT64
)0x0FFF);
402 // Check for invalid parameter
404 if (((MemoryAddress
& ~ValidMtrrAddressMask
) != 0) || ((MemoryLength
& ~ValidMtrrAddressMask
) != 0)) {
405 return EFI_INVALID_PARAMETER
;
408 if (MemoryLength
== 0) {
409 return EFI_INVALID_PARAMETER
;
412 switch (MemoryCacheType
) {
413 case EFI_CACHE_UNCACHEABLE
:
414 case EFI_CACHE_WRITECOMBINING
:
415 case EFI_CACHE_WRITETHROUGH
:
416 case EFI_CACHE_WRITEPROTECTED
:
417 case EFI_CACHE_WRITEBACK
:
421 return EFI_INVALID_PARAMETER
;
425 // Check if Fixed MTRR
427 if ((MemoryAddress
+ MemoryLength
) <= (1 << 20)) {
428 Status
= EFI_SUCCESS
;
429 EfiDisableCacheMtrr (&OldMtrr
);
430 while ((MemoryLength
> 0) && (Status
== EFI_SUCCESS
)) {
431 Status
= ProgramFixedMtrr (MemoryCacheType
, &MemoryAddress
, &MemoryLength
);
434 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
439 // Search if the range attribute has been set before
441 Status
= SearchForExactMtrr (
444 ValidMtrrAddressMask
,
449 if (!EFI_ERROR (Status
)) {
451 // Compare if it has the same type as current setting
453 if (UsedMemoryCacheType
== MemoryCacheType
) {
461 // Check if the set type is the same as Default Type
463 if (IsDefaultType (MemoryCacheType
)) {
467 AsmWriteMsr64 (UsedMsrNum
, 0);
468 AsmWriteMsr64 (UsedMsrNum
+ 1, 0);
473 // Modify the MTRR type
489 // @bug - Need to create memory map so that when checking for overlap we
490 // can determine if an overlap exists based on all caching requests.
492 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
494 if (MemoryCacheType
== (AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
)) {
495 if (!CheckMtrrOverlap (MemoryAddress
, MemoryAddress
+MemoryLength
-1)) {
503 // Find first unused MTRR
505 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
506 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+= 2) {
507 if ((AsmReadMsr64 (MsrNum
+1) & B_EFI_MSR_CACHE_MTRR_VALID
) == 0 ) {
513 // Reserve 1 MTRR pair for OS.
515 LastVariableMtrrForBios
= MsrNumEnd
- 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS
* 2);
516 if (MsrNum
> LastVariableMtrrForBios
) {
517 return EFI_LOAD_ERROR
;
521 // Special case for 1 MB base address
523 if (MemoryAddress
== BASE_1MB
) {
530 TempQword
= MemoryLength
;
532 if (TempQword
== Power2MaxMemory (MemoryAddress
, TempQword
)) {
542 // Fill in MTRRs with values. Direction can not be checked for this method
543 // as we are using WB as the default cache type and only setting areas to UC.
547 // Do boundary check so we don't go past last MTRR register
548 // for BIOS use. Leave one MTRR pair for OS use.
550 if (MsrNum
> LastVariableMtrrForBios
) {
551 return EFI_LOAD_ERROR
;
555 // Set next power of 2 region
557 MemoryLength
= Power2MaxMemory (MemoryAddress
, TempQword
);
565 MemoryAddress
+= MemoryLength
;
566 TempQword
-= MemoryLength
;
568 } while (TempQword
!= 0);
575 Reset all the MTRRs to a known state.
577 @retval EFI_SUCCESS All MTRRs have been reset successfully.
582 ResetCacheAttributes (
586 UINT32 MsrNum
, MsrNumEnd
;
596 // Determine default cache type
598 CacheType
= EFI_CACHE_UNCACHEABLE
;
601 // Set default cache type
603 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, CacheType
);
608 DisableCacheAsRam (DisableCar
);
610 EfiDisableCacheMtrr (&OldMtrr
);
615 for (Index
= 0; Index
< V_EFI_FIXED_MTRR_NUMBER
; Index
++) {
616 AsmWriteMsr64 (mFixedMtrrTable
[Index
].Msr
, 0);
620 // Reset Variable MTRRs
622 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
623 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
++) {
624 AsmWriteMsr64 (MsrNum
, 0);
628 // Enable Fixed and Variable MTRRs
630 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
636 Search the memory cache type for specific memory from MTRR.
638 @param[in] MemoryAddress the address of target memory
639 @param[in] MemoryLength the length of target memory
640 @param[in] ValidMtrrAddressMask the MTRR address mask
641 @param[out] UsedMsrNum the used MSR number
642 @param[out] UsedMemoryCacheType the cache type for the target memory
644 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
645 @retval EFI_NOT_FOUND The memory is not found in MTRR
650 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
651 IN UINT64 MemoryLength
,
652 IN UINT64 ValidMtrrAddressMask
,
653 OUT UINT32
*UsedMsrNum
,
654 OUT EFI_MEMORY_CACHE_TYPE
*UsedMemoryCacheType
657 UINT32 MsrNum
, MsrNumEnd
;
660 if (MemoryLength
== 0) {
661 return EFI_INVALID_PARAMETER
;
664 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
665 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+= 2) {
666 TempQword
= AsmReadMsr64 (MsrNum
+1);
667 if ((TempQword
& B_EFI_MSR_CACHE_MTRR_VALID
) == 0) {
671 if ((TempQword
& ValidMtrrAddressMask
) != ((~(MemoryLength
- 1)) & ValidMtrrAddressMask
)) {
675 TempQword
= AsmReadMsr64 (MsrNum
);
676 if ((TempQword
& ValidMtrrAddressMask
) != (MemoryAddress
& ValidMtrrAddressMask
)) {
680 *UsedMemoryCacheType
= (EFI_MEMORY_CACHE_TYPE
)(TempQword
& B_EFI_MSR_CACHE_MEMORY_TYPE
);
681 *UsedMsrNum
= MsrNum
;
686 return EFI_NOT_FOUND
;
690 Check if CacheType match current default setting.
692 @param[in] MemoryCacheType input cache type to be checked.
694 @retval TRUE MemoryCacheType is default MTRR setting.
695 @retval TRUE MemoryCacheType is NOT default MTRR setting.
699 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
702 if ((AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
) != MemoryCacheType
) {