4 Copyright (c) 2008 - 2010, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
24 // This table defines the offset, base and length of the fixed MTRRs
27 FIXED_MTRR MtrrLibFixedMtrrTable
[] = {
29 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
34 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
39 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
44 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
49 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
54 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
59 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
64 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
69 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
74 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
79 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
86 Returns the variable MTRR count for the CPU.
88 @return Variable MTRR count
92 GetVariableMtrrCount (
96 if (!IsMtrrSupported ()) {
100 return (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
104 Returns the firmware usable variable MTRR count for the CPU.
106 @return Firmware usable variable MTRR count
110 GetFirmwareVariableMtrrCount (
114 UINT32 VariableMtrrCount
;
116 VariableMtrrCount
= GetVariableMtrrCount ();
117 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
121 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
125 Returns the default MTRR cache type for the system.
127 @return MTRR default type
131 GetMtrrDefaultMemoryType (
135 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
140 Preparation before programming MTRR.
142 This function will do some preparation for programming MTRRs:
143 disable cache, invalid cache and disable MTRR caching functionality
145 @return CR4 value before changing.
156 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
161 // Save original CR4 value and clear PGE flag (Bit 7)
163 Value
= AsmReadCr4 ();
164 AsmWriteCr4 (Value
& (~BIT7
));
174 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
177 // Return original CR4 value
184 Cleaning up after programming MTRRs.
186 This function will do some clean up after programming MTRRs:
187 enable MTRR caching functionality, and enable cache
189 @param Cr4 CR4 value to restore
200 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
208 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
213 // Restore original CR4 value
220 Programs fixed MTRRs registers.
222 @param MemoryCacheType The memory type to set.
223 @param Base The base address of memory range.
224 @param Length The length of memory range.
226 @retval RETURN_SUCCESS The cache type was updated successfully
227 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
233 IN UINT64 MemoryCacheType
,
235 IN OUT UINT64
*Length
248 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
249 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
252 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
253 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
261 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
262 return RETURN_UNSUPPORTED
;
266 // We found the fixed MTRR to be programmed
268 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
271 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
272 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
279 if (ByteShift
== 8) {
280 return RETURN_UNSUPPORTED
;
285 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
288 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
289 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
290 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
291 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
294 if (ByteShift
< 8 && (*Length
!= 0)) {
295 return RETURN_UNSUPPORTED
;
299 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
300 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
301 return RETURN_SUCCESS
;
306 Get the attribute of variable MTRRs.
308 This function shadows the content of variable MTRRs into an
309 internal array: VariableMtrr.
311 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
312 @param MtrrValidAddressMask The valid address mask for MTRR
313 @param VariableMtrr The array to shadow variable MTRRs content
315 @return The return value of this paramter indicates the
316 number of MTRRs which has been used.
321 MtrrGetMemoryAttributeInVariableMtrr (
322 IN UINT64 MtrrValidBitsMask
,
323 IN UINT64 MtrrValidAddressMask
,
324 OUT VARIABLE_MTRR
*VariableMtrr
330 UINT32 FirmwareVariableMtrrCount
;
331 UINT32 VariableMtrrEnd
;
333 if (!IsMtrrSupported ()) {
337 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
338 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
340 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
343 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
345 (MsrNum
< VariableMtrrEnd
) &&
346 (Index
< FirmwareVariableMtrrCount
)
350 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
351 VariableMtrr
[Index
].Msr
= MsrNum
;
352 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
353 MtrrValidAddressMask
);
354 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
355 MtrrValidAddressMask
)
359 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
360 VariableMtrr
[Index
].Valid
= TRUE
;
361 VariableMtrr
[Index
].Used
= TRUE
;
362 UsedMtrr
= UsedMtrr
+ 1;
371 Checks overlap between given memory range and MTRRs.
373 @param Start The start address of memory range.
374 @param End The end address of memory range.
375 @param VariableMtrr The array to shadow variable MTRRs content
377 @retval TRUE Overlap exists.
378 @retval FALSE No overlap.
382 CheckMemoryAttributeOverlap (
383 IN PHYSICAL_ADDRESS Start
,
384 IN PHYSICAL_ADDRESS End
,
385 IN VARIABLE_MTRR
*VariableMtrr
390 for (Index
= 0; Index
< 6; Index
++) {
392 VariableMtrr
[Index
].Valid
&&
394 (Start
> (VariableMtrr
[Index
].BaseAddress
+
395 VariableMtrr
[Index
].Length
- 1)
397 (End
< VariableMtrr
[Index
].BaseAddress
)
409 Marks a variable MTRR as non-valid.
411 @param Index The index of the array VariableMtrr to be invalidated
412 @param VariableMtrr The array to shadow variable MTRRs content
413 @param UsedMtrr The number of MTRRs which has already been used
417 InvalidateShadowMtrr (
419 IN VARIABLE_MTRR
*VariableMtrr
,
423 VariableMtrr
[Index
].Valid
= FALSE
;
424 *UsedMtrr
= *UsedMtrr
- 1;
429 Combine memory attributes.
431 If overlap exists between given memory range and MTRRs, try to combine them.
433 @param Attributes The memory type to set.
434 @param Base The base address of memory range.
435 @param Length The length of memory range.
436 @param VariableMtrr The array to shadow variable MTRRs content
437 @param UsedMtrr The number of MTRRs which has already been used
438 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
440 @retval EFI_SUCCESS Memory region successfully combined.
441 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
445 CombineMemoryAttribute (
446 IN UINT64 Attributes
,
448 IN OUT UINT64
*Length
,
449 IN VARIABLE_MTRR
*VariableMtrr
,
450 IN OUT UINT32
*UsedMtrr
,
451 OUT BOOLEAN
*OverwriteExistingMtrr
459 UINT32 FirmwareVariableMtrrCount
;
461 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
463 *OverwriteExistingMtrr
= FALSE
;
464 EndAddress
= *Base
+*Length
- 1;
466 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
468 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
470 !VariableMtrr
[Index
].Valid
||
473 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
480 // Combine same attribute MTRR range
482 if (Attributes
== VariableMtrr
[Index
].Type
) {
484 // if the Mtrr range contain the request range, return RETURN_SUCCESS
486 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
488 return RETURN_SUCCESS
;
491 // invalid this MTRR, and program the combine range
494 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
496 VariableMtrr
[Index
].BaseAddress
;
497 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
500 // Record the MTRR usage status in VariableMtrr array.
502 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
503 *Base
= CombineStart
;
504 *Length
= CombineEnd
- CombineStart
+ 1;
505 EndAddress
= CombineEnd
;
506 *OverwriteExistingMtrr
= TRUE
;
510 // The cache type is different, but the range is convered by one MTRR
512 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
513 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
519 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
520 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
521 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
522 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
523 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
524 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
526 *OverwriteExistingMtrr
= TRUE
;
530 // Other type memory overlap is invalid
532 return RETURN_ACCESS_DENIED
;
535 return RETURN_SUCCESS
;
540 Calculate the maximum value which is a power of 2, but less the MemoryLength.
542 @param MemoryLength The number to pass in.
543 @return The maximum value which is align to power of 2 and less the MemoryLength
548 IN UINT64 MemoryLength
553 if (RShiftU64 (MemoryLength
, 32)) {
555 (UINT64
) GetPowerOfTwo32 (
556 (UINT32
) RShiftU64 (MemoryLength
, 32)
561 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
569 Check the direction to program variable MTRRs.
571 This function determines which direction of programming the variable
572 MTRRs will use fewer MTRRs.
574 @param Input Length of Memory to program MTRR
575 @param MtrrNumber Pointer to the number of necessary MTRRs
577 @retval TRUE Positive direction is better.
578 FALSE Negtive direction is better.
596 TempQword
-= Power2MaxMemory (TempQword
);
598 } while (TempQword
!= 0);
600 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
603 TempQword
-= Power2MaxMemory (TempQword
);
605 } while (TempQword
!= 0);
607 if (Positive
<= Subtractive
) {
608 *MtrrNumber
= Positive
;
611 *MtrrNumber
= Subtractive
;
617 Invalid variable MTRRs according to the value in the shadow array.
619 This function programs MTRRs according to the values specified
622 @param VariableMtrr The array to shadow variable MTRRs content
628 IN VARIABLE_MTRR
*VariableMtrr
633 UINTN VariableMtrrCount
;
635 Cr4
= PreMtrrChange ();
637 VariableMtrrCount
= GetVariableMtrrCount ();
638 while (Index
< VariableMtrrCount
) {
639 if (VariableMtrr
[Index
].Valid
== FALSE
&& VariableMtrr
[Index
].Used
== TRUE
) {
640 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
641 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
642 VariableMtrr
[Index
].Used
= FALSE
;
646 PostMtrrChange (Cr4
);
651 Programs variable MTRRs
653 This function programs variable MTRRs
655 @param MtrrNumber Index of MTRR to program.
656 @param BaseAddress Base address of memory region.
657 @param Length Length of memory region.
658 @param MemoryCacheType Memory type to set.
659 @param MtrrValidAddressMask The valid address mask for MTRR
664 ProgramVariableMtrr (
666 IN PHYSICAL_ADDRESS BaseAddress
,
668 IN UINT64 MemoryCacheType
,
669 IN UINT64 MtrrValidAddressMask
675 Cr4
= PreMtrrChange ();
678 // MTRR Physical Base
680 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
681 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
684 // MTRR Physical Mask
686 TempQword
= ~(Length
- 1);
688 (UINT32
) (MtrrNumber
+ 1),
689 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
692 PostMtrrChange (Cr4
);
697 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
699 @param MtrrType MTRR memory type
701 @return The enum item in MTRR_MEMORY_CACHE_TYPE
705 MTRR_MEMORY_CACHE_TYPE
706 GetMemoryCacheTypeFromMtrrType (
711 case MTRR_CACHE_UNCACHEABLE
:
712 return CacheUncacheable
;
713 case MTRR_CACHE_WRITE_COMBINING
:
714 return CacheWriteCombining
;
715 case MTRR_CACHE_WRITE_THROUGH
:
716 return CacheWriteThrough
;
717 case MTRR_CACHE_WRITE_PROTECTED
:
718 return CacheWriteProtected
;
719 case MTRR_CACHE_WRITE_BACK
:
720 return CacheWriteBack
;
723 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
724 // no mtrr covers the range
726 return CacheUncacheable
;
731 Initializes the valid bits mask and valid address mask for MTRRs.
733 This function initializes the valid bits mask and valid address mask for MTRRs.
735 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
736 @param MtrrValidAddressMask The valid address mask for the MTRR
741 MtrrLibInitializeMtrrMask (
742 OUT UINT64
*MtrrValidBitsMask
,
743 OUT UINT64
*MtrrValidAddressMask
747 UINT8 PhysicalAddressBits
;
749 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
751 if (RegEax
>= 0x80000008) {
752 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
754 PhysicalAddressBits
= (UINT8
) RegEax
;
756 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
757 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
759 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
760 *MtrrValidAddressMask
= 0xFFFFFFFF;
766 Determing the real attribute of a memory range.
768 This function is to arbitrate the real attribute of the memory when
769 there are 2 MTRR covers the same memory range. For further details,
770 please refer the IA32 Software Developer's Manual, Volume 3,
773 @param MtrrType1 the first kind of Memory type
774 @param MtrrType2 the second kind of memory type
785 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
787 case MTRR_CACHE_UNCACHEABLE
:
788 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
790 case MTRR_CACHE_WRITE_COMBINING
:
792 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
793 MtrrType2
==MTRR_CACHE_UNCACHEABLE
795 MtrrType
= MtrrType2
;
798 case MTRR_CACHE_WRITE_THROUGH
:
800 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
801 MtrrType2
==MTRR_CACHE_WRITE_BACK
803 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
804 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
805 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
808 case MTRR_CACHE_WRITE_PROTECTED
:
809 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
810 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
811 MtrrType
= MtrrType2
;
814 case MTRR_CACHE_WRITE_BACK
:
816 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
817 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
818 MtrrType2
== MTRR_CACHE_WRITE_BACK
820 MtrrType
= MtrrType2
;
823 case MTRR_CACHE_INVALID_TYPE
:
824 MtrrType
= MtrrType2
;
830 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
831 MtrrType
= MtrrType1
;
838 This function attempts to set the attributes for a memory range.
840 @param BaseAddress The physical address that is the start
841 address of a memory region.
842 @param Length The size in bytes of the memory region.
843 @param Attributes The bit mask of attributes to set for the
846 @retval RETURN_SUCCESS The attributes were set for the memory
848 @retval RETURN_INVALID_PARAMETER Length is zero.
849 @retval RETURN_UNSUPPORTED The processor does not support one or
850 more bytes of the memory resource range
851 specified by BaseAddress and Length.
852 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
853 for the memory resource range specified
854 by BaseAddress and Length.
855 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
856 range specified by BaseAddress and Length
858 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
859 modify the attributes of the memory
865 MtrrSetMemoryAttribute (
866 IN PHYSICAL_ADDRESS BaseAddress
,
868 IN MTRR_MEMORY_CACHE_TYPE Attribute
872 RETURN_STATUS Status
;
879 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
881 UINT64 MtrrValidBitsMask
;
882 UINT64 MtrrValidAddressMask
;
884 BOOLEAN OverwriteExistingMtrr
;
885 UINT32 FirmwareVariableMtrrCount
;
886 UINT32 VariableMtrrEnd
;
888 if (!IsMtrrSupported ()) {
889 return RETURN_UNSUPPORTED
;
892 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
893 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
895 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
898 MemoryType
= (UINT64
)Attribute
;
899 OverwriteExistingMtrr
= FALSE
;
902 // Check for an invalid parameter
905 return RETURN_INVALID_PARAMETER
;
909 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
910 (Length
&~MtrrValidAddressMask
) != 0
912 return RETURN_UNSUPPORTED
;
916 // Check if Fixed MTRR
918 Status
= RETURN_SUCCESS
;
919 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
920 Cr4
= PreMtrrChange ();
921 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
922 PostMtrrChange (Cr4
);
923 if (RETURN_ERROR (Status
)) {
930 // A Length of 0 can only make sense for fixed MTTR ranges.
931 // Since we just handled the fixed MTRRs, we can skip the
932 // variable MTRR section.
938 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
939 // we can set the bade to 0 to save variable MTRRs.
941 if (BaseAddress
== BASE_1MB
) {
947 // Check memory base address alignment
949 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
950 if (Remainder
!= 0) {
951 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
952 if (Remainder
!= 0) {
953 Status
= RETURN_UNSUPPORTED
;
961 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
962 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
964 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
965 if (RETURN_ERROR (Status
)) {
971 // Combined successfully
973 Status
= RETURN_SUCCESS
;
979 // Program Variable MTRRs
981 // Avoid hardcode here and read data dynamically
983 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
984 Status
= RETURN_OUT_OF_RESOURCES
;
989 // The memory type is the same with the type specified by
990 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
992 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
994 // Invalidate the now-unused MTRRs
996 InvalidateMtrr(VariableMtrr
);
1003 if (TempQword
== Power2MaxMemory (TempQword
)) {
1005 // Invalidate the now-unused MTRRs
1007 InvalidateMtrr(VariableMtrr
);
1010 // Find first unused MTRR
1012 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1013 MsrNum
< VariableMtrrEnd
;
1016 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1021 ProgramVariableMtrr (
1026 MtrrValidAddressMask
1030 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1032 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1033 Status
= RETURN_OUT_OF_RESOURCES
;
1038 // Invalidate the now-unused MTRRs
1040 InvalidateMtrr(VariableMtrr
);
1043 // Find first unused MTRR
1045 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1046 MsrNum
< VariableMtrrEnd
;
1049 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1055 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1056 ProgramVariableMtrr (
1061 MtrrValidAddressMask
1063 BaseAddress
+= Length
;
1064 TempQword
= Length
- TempQword
;
1065 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1072 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1073 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1078 Length
= Power2MaxMemory (TempQword
);
1080 BaseAddress
-= Length
;
1083 ProgramVariableMtrr (
1088 MtrrValidAddressMask
1092 BaseAddress
+= Length
;
1094 TempQword
-= Length
;
1096 } while (TempQword
> 0);
1106 This function will get the memory cache type of the specific address.
1108 This function is mainly for debug purpose.
1110 @param Address The specific address
1112 @return Memory cache type of the sepcific address
1115 MTRR_MEMORY_CACHE_TYPE
1117 MtrrGetMemoryAttribute (
1118 IN PHYSICAL_ADDRESS Address
1125 UINT64 TempMtrrType
;
1126 MTRR_MEMORY_CACHE_TYPE CacheType
;
1127 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1128 UINT64 MtrrValidBitsMask
;
1129 UINT64 MtrrValidAddressMask
;
1130 UINTN VariableMtrrCount
;
1132 if (!IsMtrrSupported ()) {
1133 return CacheUncacheable
;
1137 // Check if MTRR is enabled, if not, return UC as attribute
1139 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1140 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1142 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1143 return CacheUncacheable
;
1147 // If address is less than 1M, then try to go through the fixed MTRR
1149 if (Address
< BASE_1MB
) {
1150 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1152 // Go through the fixed MTRR
1154 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1155 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1157 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1158 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1162 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1163 MtrrLibFixedMtrrTable
[Index
].Length
;
1164 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1165 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1166 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1171 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1172 MtrrGetMemoryAttributeInVariableMtrr(
1174 MtrrValidAddressMask
,
1179 // Go through the variable MTRR
1181 VariableMtrrCount
= GetVariableMtrrCount ();
1182 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1184 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1185 if (VariableMtrr
[Index
].Valid
) {
1186 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1187 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1188 TempMtrrType
= VariableMtrr
[Index
].Type
;
1189 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1193 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1200 This function will get the raw value in variable MTRRs
1202 @param VariableSettings A buffer to hold variable MTRRs content.
1204 @return The VariableSettings input pointer
1207 MTRR_VARIABLE_SETTINGS
*
1209 MtrrGetVariableMtrr (
1210 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1214 UINT32 VariableMtrrCount
;
1216 if (!IsMtrrSupported ()) {
1217 return VariableSettings
;
1220 VariableMtrrCount
= GetVariableMtrrCount ();
1221 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1223 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1224 VariableSettings
->Mtrr
[Index
].Base
=
1225 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1226 VariableSettings
->Mtrr
[Index
].Mask
=
1227 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1230 return VariableSettings
;
1235 Worker function setting variable MTRRs
1237 @param VariableSettings A buffer to hold variable MTRRs content.
1241 MtrrSetVariableMtrrWorker (
1242 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1246 UINT32 VariableMtrrCount
;
1248 VariableMtrrCount
= GetVariableMtrrCount ();
1249 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1251 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1253 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1254 VariableSettings
->Mtrr
[Index
].Base
1257 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1258 VariableSettings
->Mtrr
[Index
].Mask
1265 This function sets variable MTRRs
1267 @param VariableSettings A buffer to hold variable MTRRs content.
1269 @return The pointer of VariableSettings
1272 MTRR_VARIABLE_SETTINGS
*
1274 MtrrSetVariableMtrr (
1275 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1280 if (!IsMtrrSupported ()) {
1281 return VariableSettings
;
1284 Cr4
= PreMtrrChange ();
1285 MtrrSetVariableMtrrWorker (VariableSettings
);
1286 PostMtrrChange (Cr4
);
1287 return VariableSettings
;
1292 This function gets the content in fixed MTRRs
1294 @param FixedSettings A buffer to hold fixed Mtrrs content.
1296 @retval The pointer of FixedSettings
1299 MTRR_FIXED_SETTINGS
*
1302 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1307 if (!IsMtrrSupported ()) {
1308 return FixedSettings
;
1311 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1312 FixedSettings
->Mtrr
[Index
] =
1313 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1316 return FixedSettings
;
1320 Worker function setting fixed MTRRs
1322 @param FixedSettings A buffer to hold fixed Mtrrs content.
1326 MtrrSetFixedMtrrWorker (
1327 IN MTRR_FIXED_SETTINGS
*FixedSettings
1332 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1334 MtrrLibFixedMtrrTable
[Index
].Msr
,
1335 FixedSettings
->Mtrr
[Index
]
1342 This function sets fixed MTRRs
1344 @param FixedSettings A buffer to hold fixed Mtrrs content.
1346 @retval The pointer of FixedSettings
1349 MTRR_FIXED_SETTINGS
*
1352 IN MTRR_FIXED_SETTINGS
*FixedSettings
1357 if (!IsMtrrSupported ()) {
1358 return FixedSettings
;
1361 Cr4
= PreMtrrChange ();
1362 MtrrSetFixedMtrrWorker (FixedSettings
);
1363 PostMtrrChange (Cr4
);
1365 return FixedSettings
;
1370 This function gets the content in all MTRRs (variable and fixed)
1372 @param MtrrSetting A buffer to hold all Mtrrs content.
1374 @retval the pointer of MtrrSetting
1380 OUT MTRR_SETTINGS
*MtrrSetting
1383 if (!IsMtrrSupported ()) {
1390 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1393 // Get variable MTRRs
1395 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1398 // Get MTRR_DEF_TYPE value
1400 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1407 This function sets all MTRRs (variable and fixed)
1409 @param MtrrSetting A buffer holding all MTRRs content.
1411 @retval The pointer of MtrrSetting
1417 IN MTRR_SETTINGS
*MtrrSetting
1422 if (!IsMtrrSupported ()) {
1426 Cr4
= PreMtrrChange ();
1431 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1434 // Set variable MTRRs
1436 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1439 // Set MTRR_DEF_TYPE value
1441 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1443 PostMtrrChange (Cr4
);
1450 This function prints all MTRRs for debugging.
1453 MtrrDebugPrintAllMtrrs (
1458 MTRR_SETTINGS MtrrSettings
;
1460 UINTN VariableMtrrCount
;
1462 if (!IsMtrrSupported ()) {
1466 MtrrGetAllMtrrs (&MtrrSettings
);
1467 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1468 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1470 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1472 MtrrSettings
.Fixed
.Mtrr
[Index
]
1476 VariableMtrrCount
= GetVariableMtrrCount ();
1477 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1479 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1481 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1482 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1490 Checks if MTRR is supported.
1492 @retval TRUE MTRR is supported.
1493 @retval FALSE MTRR is not supported.
1506 // Check CPUID(1).EDX[12] for MTRR capability
1508 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1509 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1514 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1515 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1516 // exist, return false.
1518 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1519 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {