3 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php.
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/BaseLib.h>
16 #include <Library/CacheLib.h>
17 #include <Library/CacheAsRamLib.h>
18 #include "CacheLibInternal.h"
21 Search the memory cache type for specific memory from MTRR.
23 @param[in] MemoryAddress the address of target memory
24 @param[in] MemoryLength the length of target memory
25 @param[in] ValidMtrrAddressMask the MTRR address mask
26 @param[out] UsedMsrNum the used MSR number
27 @param[out] UsedMemoryCacheType the cache type for the target memory
29 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
30 @retval EFI_NOT_FOUND The memory is not found in MTRR
35 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
36 IN UINT64 MemoryLength
,
37 IN UINT64 ValidMtrrAddressMask
,
38 OUT UINT32
*UsedMsrNum
,
39 OUT EFI_MEMORY_CACHE_TYPE
*MemoryCacheType
43 Check if CacheType match current default setting.
45 @param[in] MemoryCacheType input cache type to be checked.
47 @retval TRUE MemoryCacheType is default MTRR setting.
48 @retval FALSE MemoryCacheType is NOT default MTRR setting.
52 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
56 Return MTRR alignment requirement for base address and size.
58 @param[in] BaseAddress Base address.
61 @retval Zero Alligned.
62 @retval Non-Zero Not alligned.
67 IN UINT64 BaseAddress
,
77 EFI_FIXED_MTRR mFixedMtrrTable
[] = {
78 { EFI_MSR_IA32_MTRR_FIX64K_00000
, 0, 0x10000},
79 { EFI_MSR_IA32_MTRR_FIX16K_80000
, 0x80000, 0x4000},
80 { EFI_MSR_IA32_MTRR_FIX16K_A0000
, 0xA0000, 0x4000},
81 { EFI_MSR_IA32_MTRR_FIX4K_C0000
, 0xC0000, 0x1000},
82 { EFI_MSR_IA32_MTRR_FIX4K_C8000
, 0xC8000, 0x1000},
83 { EFI_MSR_IA32_MTRR_FIX4K_D0000
, 0xD0000, 0x1000},
84 { EFI_MSR_IA32_MTRR_FIX4K_D8000
, 0xD8000, 0x1000},
85 { EFI_MSR_IA32_MTRR_FIX4K_E0000
, 0xE0000, 0x1000},
86 { EFI_MSR_IA32_MTRR_FIX4K_E8000
, 0xE8000, 0x1000},
87 { EFI_MSR_IA32_MTRR_FIX4K_F0000
, 0xF0000, 0x1000},
88 { EFI_MSR_IA32_MTRR_FIX4K_F8000
, 0xF8000, 0x1000}
92 Given the input, check if the number of MTRR is lesser.
93 if positive or subtractive.
95 @param[in] Input Length of Memory to program MTRR.
97 @retval Zero do positive.
98 @retval Non-Zero do subtractive.
110 Disable cache and its mtrr.
112 @param[out] OldMtrr To return the Old MTRR value
116 EfiDisableCacheMtrr (
123 // Disable Cache MTRR
125 *OldMtrr
= AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
);
126 TempQword
= (*OldMtrr
) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE
& ~B_EFI_MSR_FIXED_MTRR_ENABLE
;
127 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, TempQword
);
134 @param[in] EnableMtrr Whether to enable the MTRR
135 @param[in] OldMtrr The saved old MTRR value to restore when not to enable the MTRR
139 EfiRecoverCacheMtrr (
140 IN BOOLEAN EnableMtrr
,
150 TempQword
= AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
);
151 TempQword
|= (UINT64
)(B_EFI_MSR_GLOBAL_MTRR_ENABLE
| B_EFI_MSR_FIXED_MTRR_ENABLE
);
156 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, TempQword
);
162 Programming MTRR according to Memory address, length, and type.
164 @param[in] MtrrNumber the variable MTRR index number
165 @param[in] MemoryAddress the address of target memory
166 @param[in] MemoryLength the length of target memory
167 @param[in] MemoryCacheType the cache type of target memory
168 @param[in] ValidMtrrAddressMask the MTRR address mask
174 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
175 IN UINT64 MemoryLength
,
176 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
,
177 IN UINT64 ValidMtrrAddressMask
183 if (MemoryLength
== 0) {
187 EfiDisableCacheMtrr (&OldMtrr
);
190 // MTRR Physical Base
192 TempQword
= (MemoryAddress
& ValidMtrrAddressMask
) | MemoryCacheType
;
193 AsmWriteMsr64 (MtrrNumber
, TempQword
);
196 // MTRR Physical Mask
198 TempQword
= ~(MemoryLength
- 1);
199 AsmWriteMsr64 (MtrrNumber
+ 1, (TempQword
& ValidMtrrAddressMask
) | B_EFI_MSR_CACHE_MTRR_VALID
);
201 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
205 Calculate the maximum value which is a power of 2, but less the MemoryLength.
207 @param[in] MemoryAddress Memory address.
208 @param[in] MemoryLength The number to pass in.
210 @return The maximum value which is align to power of 2 and less the MemoryLength
215 IN UINT64 MemoryAddress
,
216 IN UINT64 MemoryLength
221 if (MemoryLength
== 0) {
222 return EFI_INVALID_PARAMETER
;
226 // Compute inital power of 2 size to return
228 Result
= GetPowerOfTwo64(MemoryLength
);
231 // Special case base of 0 as all ranges are valid
233 if (MemoryAddress
== 0) {
238 // Loop till a value that can be mapped to this base address is found
240 while (CheckMtrrAlignment (MemoryAddress
, Result
) != 0) {
242 // Need to try the next smaller power of 2
244 Result
= RShiftU64 (Result
, 1);
251 Return MTRR alignment requirement for base address and size.
253 @param[in] BaseAddress Base address.
254 @param[in] Size Size.
256 @retval Zero Alligned.
257 @retval Non-Zero Not alligned.
262 IN UINT64 BaseAddress
,
270 // Shift base and size right 12 bits to allow for larger memory sizes. The
271 // MTRRs do not use the first 12 bits so this is safe for now. Only supports
272 // up to 52 bits of physical address space.
274 ShiftedBase
= (UINT32
) RShiftU64 (BaseAddress
, 12);
275 ShiftedSize
= (UINT32
) RShiftU64 (Size
, 12);
278 // Return the results to the caller of the MOD
280 return ShiftedBase
% ShiftedSize
;
284 Programs fixed MTRRs registers.
286 @param[in] MemoryCacheType The memory type to set.
287 @param[in] Base The base address of memory range.
288 @param[in] Length The length of memory range.
290 @retval RETURN_SUCCESS The cache type was updated successfully
291 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
297 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
,
312 for (MsrNum
= 0; MsrNum
< V_EFI_FIXED_MTRR_NUMBER
; MsrNum
++) {
313 if ((*Base
>= mFixedMtrrTable
[MsrNum
].BaseAddress
) &&
314 (*Base
< (mFixedMtrrTable
[MsrNum
].BaseAddress
+ 8 * mFixedMtrrTable
[MsrNum
].Length
))) {
318 if (MsrNum
== V_EFI_FIXED_MTRR_NUMBER
) {
319 return EFI_DEVICE_ERROR
;
322 // We found the fixed MTRR to be programmed
324 for (ByteShift
=0; ByteShift
< 8; ByteShift
++) {
325 if ( *Base
== (mFixedMtrrTable
[MsrNum
].BaseAddress
+ ByteShift
* mFixedMtrrTable
[MsrNum
].Length
)) {
329 if (ByteShift
== 8 ) {
330 return EFI_DEVICE_ERROR
;
332 for (; ((ByteShift
<8) && (*Len
>= mFixedMtrrTable
[MsrNum
].Length
));ByteShift
++) {
333 OrMask
|= LShiftU64((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
334 ClearMask
|= LShiftU64((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
335 *Len
-= mFixedMtrrTable
[MsrNum
].Length
;
336 *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
);
433 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
438 // Search if the range attribute has been set before
440 Status
= SearchForExactMtrr(
443 ValidMtrrAddressMask
,
448 if (!EFI_ERROR(Status
)) {
450 // Compare if it has the same type as current setting
452 if (UsedMemoryCacheType
== MemoryCacheType
) {
460 // Check if the set type is the same as Default Type
462 if (IsDefaultType(MemoryCacheType
)) {
466 AsmWriteMsr64(UsedMsrNum
, 0);
467 AsmWriteMsr64(UsedMsrNum
+ 1, 0);
472 // Modify the MTRR type
474 EfiProgramMtrr(UsedMsrNum
,
487 // @bug - Need to create memory map so that when checking for overlap we
488 // can determine if an overlap exists based on all caching requests.
490 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
492 if (MemoryCacheType
== (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
)) {
493 if (!CheckMtrrOverlap (MemoryAddress
, MemoryAddress
+MemoryLength
-1)) {
500 // Find first unused MTRR
502 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
503 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+=2) {
504 if ((AsmReadMsr64(MsrNum
+1) & B_EFI_MSR_CACHE_MTRR_VALID
) == 0 ) {
510 // Reserve 1 MTRR pair for OS.
512 LastVariableMtrrForBios
= MsrNumEnd
- 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS
* 2);
513 if (MsrNum
> LastVariableMtrrForBios
) {
514 return EFI_LOAD_ERROR
;
518 // Special case for 1 MB base address
520 if (MemoryAddress
== BASE_1MB
) {
527 TempQword
= MemoryLength
;
529 if (TempQword
== Power2MaxMemory(MemoryAddress
, TempQword
)) {
530 EfiProgramMtrr(MsrNum
,
539 // Fill in MTRRs with values. Direction can not be checked for this method
540 // as we are using WB as the default cache type and only setting areas to UC.
544 // Do boundary check so we don't go past last MTRR register
545 // for BIOS use. Leave one MTRR pair for OS use.
547 if (MsrNum
> LastVariableMtrrForBios
) {
548 return EFI_LOAD_ERROR
;
552 // Set next power of 2 region
554 MemoryLength
= Power2MaxMemory(MemoryAddress
, TempQword
);
555 EfiProgramMtrr(MsrNum
,
561 MemoryAddress
+= MemoryLength
;
562 TempQword
-= MemoryLength
;
564 } while (TempQword
!= 0);
571 Reset all the MTRRs to a known state.
573 @retval EFI_SUCCESS All MTRRs have been reset successfully.
578 ResetCacheAttributes (
582 UINT32 MsrNum
, MsrNumEnd
;
591 // Determine default cache type
593 CacheType
= EFI_CACHE_UNCACHEABLE
;
596 // Set default cache type
598 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
, CacheType
);
603 DisableCacheAsRam (DisableCar
);
605 EfiDisableCacheMtrr (&OldMtrr
);
610 for (Index
= 0; Index
< V_EFI_FIXED_MTRR_NUMBER
; Index
++) {
611 AsmWriteMsr64 (mFixedMtrrTable
[Index
].Msr
, 0);
615 // Reset Variable MTRRs
617 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
618 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
++) {
619 AsmWriteMsr64 (MsrNum
, 0);
623 // Enable Fixed and Variable MTRRs
625 EfiRecoverCacheMtrr (TRUE
, OldMtrr
);
631 Search the memory cache type for specific memory from MTRR.
633 @param[in] MemoryAddress the address of target memory
634 @param[in] MemoryLength the length of target memory
635 @param[in] ValidMtrrAddressMask the MTRR address mask
636 @param[out] UsedMsrNum the used MSR number
637 @param[out] UsedMemoryCacheType the cache type for the target memory
639 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned
640 @retval EFI_NOT_FOUND The memory is not found in MTRR
645 IN EFI_PHYSICAL_ADDRESS MemoryAddress
,
646 IN UINT64 MemoryLength
,
647 IN UINT64 ValidMtrrAddressMask
,
648 OUT UINT32
*UsedMsrNum
,
649 OUT EFI_MEMORY_CACHE_TYPE
*UsedMemoryCacheType
652 UINT32 MsrNum
, MsrNumEnd
;
655 if (MemoryLength
== 0) {
656 return EFI_INVALID_PARAMETER
;
659 MsrNumEnd
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
+ (2 * (UINT32
)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP
) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT
));
660 for (MsrNum
= EFI_MSR_CACHE_VARIABLE_MTRR_BASE
; MsrNum
< MsrNumEnd
; MsrNum
+=2) {
661 TempQword
= AsmReadMsr64(MsrNum
+1);
662 if ((TempQword
& B_EFI_MSR_CACHE_MTRR_VALID
) == 0) {
666 if ((TempQword
& ValidMtrrAddressMask
) != ((~(MemoryLength
- 1)) & ValidMtrrAddressMask
)) {
670 TempQword
= AsmReadMsr64 (MsrNum
);
671 if ((TempQword
& ValidMtrrAddressMask
) != (MemoryAddress
& ValidMtrrAddressMask
)) {
675 *UsedMemoryCacheType
= (EFI_MEMORY_CACHE_TYPE
)(TempQword
& B_EFI_MSR_CACHE_MEMORY_TYPE
);
676 *UsedMsrNum
= MsrNum
;
681 return EFI_NOT_FOUND
;
685 Check if CacheType match current default setting.
687 @param[in] MemoryCacheType input cache type to be checked.
689 @retval TRUE MemoryCacheType is default MTRR setting.
690 @retval TRUE MemoryCacheType is NOT default MTRR setting.
694 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
697 if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE
) & B_EFI_MSR_CACHE_MEMORY_TYPE
) != MemoryCacheType
) {