3 Copyright (c) 2014 - 2019, 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
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
))) {
312 if (MsrNum
== V_EFI_FIXED_MTRR_NUMBER
) {
313 return EFI_DEVICE_ERROR
;
316 // We found the fixed MTRR to be programmed
318 for (ByteShift
=0; ByteShift
< 8; ByteShift
++) {
319 if ( *Base
== (mFixedMtrrTable
[MsrNum
].BaseAddress
+ ByteShift
* mFixedMtrrTable
[MsrNum
].Length
)) {
323 if (ByteShift
== 8 ) {
324 return EFI_DEVICE_ERROR
;
326 for (; ((ByteShift
<8) && (*Len
>= mFixedMtrrTable
[MsrNum
].Length
));ByteShift
++) {
327 OrMask
|= LShiftU64((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
328 ClearMask
|= LShiftU64((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
329 *Len
-= mFixedMtrrTable
[MsrNum
].Length
;
330 *Base
+= mFixedMtrrTable
[MsrNum
].Length
;
332 TempQword
= (AsmReadMsr64 (mFixedMtrrTable
[MsrNum
].Msr
) & (~ClearMask
)) | OrMask
;
333 AsmWriteMsr64 (mFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
339 Check if there is a valid variable MTRR that overlaps the given range.
341 @param[in] Start Base Address of the range to check.
342 @param[in] End End address of the range to check.
344 @retval TRUE Mtrr overlap.
345 @retval FALSE Mtrr not overlap.
349 IN EFI_PHYSICAL_ADDRESS Start
,
350 IN EFI_PHYSICAL_ADDRESS End
357 Given the memory range and cache type, programs the MTRRs.
359 @param[in] MemoryAddress Base Address of Memory to program MTRR.
360 @param[in] MemoryLength Length of Memory to program MTRR.
361 @param[in] MemoryCacheType Cache Type.
363 @retval EFI_SUCCESS Mtrr are set successfully.
364 @retval EFI_LOAD_ERROR No empty MTRRs to use.
365 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
366 @retval others An error occurs when setting MTTR.
372 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
373 IN UINT64 MemoryLength
,
374 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
378 UINT32 MsrNum
, MsrNumEnd
;
380 UINT32 LastVariableMtrrForBios
;
383 EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType
;
384 UINT64 ValidMtrrAddressMask
;
387 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &Cpuid_RegEax
, NULL
, NULL
, NULL
);
388 if (Cpuid_RegEax
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
389 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &Cpuid_RegEax
, NULL
, NULL
, NULL
);
390 ValidMtrrAddressMask
= (LShiftU64((UINT64
) 1, (Cpuid_RegEax
& 0xFF)) - 1) & (~(UINT64
)0x0FFF);
392 ValidMtrrAddressMask
= (LShiftU64((UINT64
) 1, 36) - 1) & (~(UINT64
)0x0FFF);
396 // Check for invalid parameter
398 if ((MemoryAddress
& ~ValidMtrrAddressMask
) != 0 || (MemoryLength
& ~ValidMtrrAddressMask
) != 0) {
399 return EFI_INVALID_PARAMETER
;
402 if (MemoryLength
== 0) {
403 return EFI_INVALID_PARAMETER
;
406 switch (MemoryCacheType
) {
407 case EFI_CACHE_UNCACHEABLE
:
408 case EFI_CACHE_WRITECOMBINING
:
409 case EFI_CACHE_WRITETHROUGH
:
410 case EFI_CACHE_WRITEPROTECTED
:
411 case EFI_CACHE_WRITEBACK
:
415 return EFI_INVALID_PARAMETER
;
419 // Check if Fixed MTRR
421 if ((MemoryAddress
+ MemoryLength
) <= (1 << 20)) {
422 Status
= EFI_SUCCESS
;
423 EfiDisableCacheMtrr (&OldMtrr
);
424 while ((MemoryLength
> 0) && (Status
== EFI_SUCCESS
)) {
425 Status
= ProgramFixedMtrr (MemoryCacheType
, &MemoryAddress
, &MemoryLength
);
427 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
432 // Search if the range attribute has been set before
434 Status
= SearchForExactMtrr(
437 ValidMtrrAddressMask
,
442 if (!EFI_ERROR(Status
)) {
444 // Compare if it has the same type as current setting
446 if (UsedMemoryCacheType
== MemoryCacheType
) {
454 // Check if the set type is the same as Default Type
456 if (IsDefaultType(MemoryCacheType
)) {
460 AsmWriteMsr64(UsedMsrNum
, 0);
461 AsmWriteMsr64(UsedMsrNum
+ 1, 0);
466 // Modify the MTRR type
468 EfiProgramMtrr(UsedMsrNum
,
481 // @bug - Need to create memory map so that when checking for overlap we
482 // can determine if an overlap exists based on all caching requests.
484 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
486 if (MemoryCacheType
== (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
)) {
487 if (!CheckMtrrOverlap (MemoryAddress
, MemoryAddress
+MemoryLength
-1)) {
494 // Find first unused MTRR
496 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
497 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+=2) {
498 if ((AsmReadMsr64(MsrNum
+1) & B_EFI_MSR_CACHE_MTRR_VALID
) == 0 ) {
504 // Reserve 1 MTRR pair for OS.
506 LastVariableMtrrForBios
= MsrNumEnd
- 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS
* 2);
507 if (MsrNum
> LastVariableMtrrForBios
) {
508 return EFI_LOAD_ERROR
;
512 // Special case for 1 MB base address
514 if (MemoryAddress
== BASE_1MB
) {
521 TempQword
= MemoryLength
;
523 if (TempQword
== Power2MaxMemory(MemoryAddress
, TempQword
)) {
524 EfiProgramMtrr(MsrNum
,
533 // Fill in MTRRs with values. Direction can not be checked for this method
534 // as we are using WB as the default cache type and only setting areas to UC.
538 // Do boundary check so we don't go past last MTRR register
539 // for BIOS use. Leave one MTRR pair for OS use.
541 if (MsrNum
> LastVariableMtrrForBios
) {
542 return EFI_LOAD_ERROR
;
546 // Set next power of 2 region
548 MemoryLength
= Power2MaxMemory(MemoryAddress
, TempQword
);
549 EfiProgramMtrr(MsrNum
,
555 MemoryAddress
+= MemoryLength
;
556 TempQword
-= MemoryLength
;
558 } while (TempQword
!= 0);
565 Reset all the MTRRs to a known state.
567 @retval EFI_SUCCESS All MTRRs have been reset successfully.
572 ResetCacheAttributes (
576 UINT32 MsrNum
, MsrNumEnd
;
585 // Determine default cache type
587 CacheType
= EFI_CACHE_UNCACHEABLE
;
590 // Set default cache type
592 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, CacheType
);
597 DisableCacheAsRam (DisableCar
);
599 EfiDisableCacheMtrr (&OldMtrr
);
604 for (Index
= 0; Index
< V_EFI_FIXED_MTRR_NUMBER
; Index
++) {
605 AsmWriteMsr64 (mFixedMtrrTable
[Index
].Msr
, 0);
609 // Reset Variable MTRRs
611 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
612 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
++) {
613 AsmWriteMsr64 (MsrNum
, 0);
617 // Enable Fixed and Variable MTRRs
619 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
625 Search the memory cache type for specific memory from MTRR.
627 @param[in] MemoryAddress the address of target memory
628 @param[in] MemoryLength the length of target memory
629 @param[in] ValidMtrrAddressMask the MTRR address mask
630 @param[out] UsedMsrNum the used MSR number
631 @param[out] UsedMemoryCacheType the cache type for the target memory
633 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
634 @retval EFI_NOT_FOUND The memory is not found in MTRR
639 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
640 IN UINT64 MemoryLength
,
641 IN UINT64 ValidMtrrAddressMask
,
642 OUT UINT32
*UsedMsrNum
,
643 OUT EFI_MEMORY_CACHE_TYPE
*UsedMemoryCacheType
646 UINT32 MsrNum
, MsrNumEnd
;
649 if (MemoryLength
== 0) {
650 return EFI_INVALID_PARAMETER
;
653 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
654 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+=2) {
655 TempQword
= AsmReadMsr64(MsrNum
+1);
656 if ((TempQword
& B_EFI_MSR_CACHE_MTRR_VALID
) == 0) {
660 if ((TempQword
& ValidMtrrAddressMask
) != ((~(MemoryLength
- 1)) & ValidMtrrAddressMask
)) {
664 TempQword
= AsmReadMsr64 (MsrNum
);
665 if ((TempQword
& ValidMtrrAddressMask
) != (MemoryAddress
& ValidMtrrAddressMask
)) {
669 *UsedMemoryCacheType
= (EFI_MEMORY_CACHE_TYPE
)(TempQword
& B_EFI_MSR_CACHE_MEMORY_TYPE
);
670 *UsedMsrNum
= MsrNum
;
675 return EFI_NOT_FOUND
;
679 Check if CacheType match current default setting.
681 @param[in] MemoryCacheType input cache type to be checked.
683 @retval TRUE MemoryCacheType is default MTRR setting.
684 @retval TRUE MemoryCacheType is NOT default MTRR setting.
688 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
691 if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
) != MemoryCacheType
) {