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
93 GetVariableMtrrCount (
97 if (!IsMtrrSupported ()) {
101 return (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
105 Returns the firmware usable variable MTRR count for the CPU.
107 @return Firmware usable variable MTRR count
112 GetFirmwareVariableMtrrCount (
116 UINT32 VariableMtrrCount
;
118 VariableMtrrCount
= GetVariableMtrrCount ();
119 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
123 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
127 Returns the default MTRR cache type for the system.
129 @return MTRR default type
133 GetMtrrDefaultMemoryType (
137 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
142 Preparation before programming MTRR.
144 This function will do some preparation for programming MTRRs:
145 disable cache, invalid cache and disable MTRR caching functionality
147 @return CR4 value before changing.
158 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
163 // Save original CR4 value and clear PGE flag (Bit 7)
165 Value
= AsmReadCr4 ();
166 AsmWriteCr4 (Value
& (~BIT7
));
176 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
179 // Return original CR4 value
186 Cleaning up after programming MTRRs.
188 This function will do some clean up after programming MTRRs:
189 enable MTRR caching functionality, and enable cache
191 @param Cr4 CR4 value to restore
202 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
210 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
215 // Restore original CR4 value
222 Programs fixed MTRRs registers.
224 @param MemoryCacheType The memory type to set.
225 @param Base The base address of memory range.
226 @param Length The length of memory range.
228 @retval RETURN_SUCCESS The cache type was updated successfully
229 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
235 IN UINT64 MemoryCacheType
,
237 IN OUT UINT64
*Length
250 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
251 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
254 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
255 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
263 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
264 return RETURN_UNSUPPORTED
;
268 // We found the fixed MTRR to be programmed
270 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
273 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
274 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
281 if (ByteShift
== 8) {
282 return RETURN_UNSUPPORTED
;
287 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
290 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
291 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
292 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
293 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
296 if (ByteShift
< 8 && (*Length
!= 0)) {
297 return RETURN_UNSUPPORTED
;
301 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
302 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
303 return RETURN_SUCCESS
;
308 Get the attribute of variable MTRRs.
310 This function shadows the content of variable MTRRs into an
311 internal array: VariableMtrr.
313 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
314 @param MtrrValidAddressMask The valid address mask for MTRR
315 @param VariableMtrr The array to shadow variable MTRRs content
317 @return The return value of this paramter indicates the
318 number of MTRRs which has been used.
323 MtrrGetMemoryAttributeInVariableMtrr (
324 IN UINT64 MtrrValidBitsMask
,
325 IN UINT64 MtrrValidAddressMask
,
326 OUT VARIABLE_MTRR
*VariableMtrr
332 UINT32 FirmwareVariableMtrrCount
;
333 UINT32 VariableMtrrEnd
;
335 if (!IsMtrrSupported ()) {
339 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
340 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
342 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
345 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
347 (MsrNum
< VariableMtrrEnd
) &&
348 (Index
< FirmwareVariableMtrrCount
)
352 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
353 VariableMtrr
[Index
].Msr
= MsrNum
;
354 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
355 MtrrValidAddressMask
);
356 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
357 MtrrValidAddressMask
)
361 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
362 VariableMtrr
[Index
].Valid
= TRUE
;
363 VariableMtrr
[Index
].Used
= TRUE
;
364 UsedMtrr
= UsedMtrr
+ 1;
373 Checks overlap between given memory range and MTRRs.
375 @param Start The start address of memory range.
376 @param End The end address of memory range.
377 @param VariableMtrr The array to shadow variable MTRRs content
379 @retval TRUE Overlap exists.
380 @retval FALSE No overlap.
384 CheckMemoryAttributeOverlap (
385 IN PHYSICAL_ADDRESS Start
,
386 IN PHYSICAL_ADDRESS End
,
387 IN VARIABLE_MTRR
*VariableMtrr
392 for (Index
= 0; Index
< 6; Index
++) {
394 VariableMtrr
[Index
].Valid
&&
396 (Start
> (VariableMtrr
[Index
].BaseAddress
+
397 VariableMtrr
[Index
].Length
- 1)
399 (End
< VariableMtrr
[Index
].BaseAddress
)
411 Marks a variable MTRR as non-valid.
413 @param Index The index of the array VariableMtrr to be invalidated
414 @param VariableMtrr The array to shadow variable MTRRs content
415 @param UsedMtrr The number of MTRRs which has already been used
419 InvalidateShadowMtrr (
421 IN VARIABLE_MTRR
*VariableMtrr
,
425 VariableMtrr
[Index
].Valid
= FALSE
;
426 *UsedMtrr
= *UsedMtrr
- 1;
431 Combine memory attributes.
433 If overlap exists between given memory range and MTRRs, try to combine them.
435 @param Attributes The memory type to set.
436 @param Base The base address of memory range.
437 @param Length The length of memory range.
438 @param VariableMtrr The array to shadow variable MTRRs content
439 @param UsedMtrr The number of MTRRs which has already been used
440 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
442 @retval EFI_SUCCESS Memory region successfully combined.
443 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
447 CombineMemoryAttribute (
448 IN UINT64 Attributes
,
450 IN OUT UINT64
*Length
,
451 IN VARIABLE_MTRR
*VariableMtrr
,
452 IN OUT UINT32
*UsedMtrr
,
453 OUT BOOLEAN
*OverwriteExistingMtrr
461 UINT32 FirmwareVariableMtrrCount
;
463 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
465 *OverwriteExistingMtrr
= FALSE
;
466 EndAddress
= *Base
+*Length
- 1;
468 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
470 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
472 !VariableMtrr
[Index
].Valid
||
475 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
482 // Combine same attribute MTRR range
484 if (Attributes
== VariableMtrr
[Index
].Type
) {
486 // if the Mtrr range contain the request range, return RETURN_SUCCESS
488 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
490 return RETURN_SUCCESS
;
493 // invalid this MTRR, and program the combine range
496 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
498 VariableMtrr
[Index
].BaseAddress
;
499 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
502 // Record the MTRR usage status in VariableMtrr array.
504 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
505 *Base
= CombineStart
;
506 *Length
= CombineEnd
- CombineStart
+ 1;
507 EndAddress
= CombineEnd
;
508 *OverwriteExistingMtrr
= TRUE
;
512 // The cache type is different, but the range is convered by one MTRR
514 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
515 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
521 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
522 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
523 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
524 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
525 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
526 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
528 *OverwriteExistingMtrr
= TRUE
;
532 // Other type memory overlap is invalid
534 return RETURN_ACCESS_DENIED
;
537 return RETURN_SUCCESS
;
542 Calculate the maximum value which is a power of 2, but less the MemoryLength.
544 @param MemoryLength The number to pass in.
545 @return The maximum value which is align to power of 2 and less the MemoryLength
550 IN UINT64 MemoryLength
555 if (RShiftU64 (MemoryLength
, 32)) {
557 (UINT64
) GetPowerOfTwo32 (
558 (UINT32
) RShiftU64 (MemoryLength
, 32)
563 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
571 Check the direction to program variable MTRRs.
573 This function determines which direction of programming the variable
574 MTRRs will use fewer MTRRs.
576 @param Input Length of Memory to program MTRR
577 @param MtrrNumber Pointer to the number of necessary MTRRs
579 @retval TRUE Positive direction is better.
580 FALSE Negtive direction is better.
598 TempQword
-= Power2MaxMemory (TempQword
);
600 } while (TempQword
!= 0);
602 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
605 TempQword
-= Power2MaxMemory (TempQword
);
607 } while (TempQword
!= 0);
609 if (Positive
<= Subtractive
) {
610 *MtrrNumber
= Positive
;
613 *MtrrNumber
= Subtractive
;
619 Invalid variable MTRRs according to the value in the shadow array.
621 This function programs MTRRs according to the values specified
624 @param VariableMtrr The array to shadow variable MTRRs content
630 IN VARIABLE_MTRR
*VariableMtrr
635 UINTN VariableMtrrCount
;
637 Cr4
= PreMtrrChange ();
639 VariableMtrrCount
= GetVariableMtrrCount ();
640 while (Index
< VariableMtrrCount
) {
641 if (VariableMtrr
[Index
].Valid
== FALSE
&& VariableMtrr
[Index
].Used
== TRUE
) {
642 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
643 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
644 VariableMtrr
[Index
].Used
= FALSE
;
648 PostMtrrChange (Cr4
);
653 Programs variable MTRRs
655 This function programs variable MTRRs
657 @param MtrrNumber Index of MTRR to program.
658 @param BaseAddress Base address of memory region.
659 @param Length Length of memory region.
660 @param MemoryCacheType Memory type to set.
661 @param MtrrValidAddressMask The valid address mask for MTRR
666 ProgramVariableMtrr (
668 IN PHYSICAL_ADDRESS BaseAddress
,
670 IN UINT64 MemoryCacheType
,
671 IN UINT64 MtrrValidAddressMask
677 Cr4
= PreMtrrChange ();
680 // MTRR Physical Base
682 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
683 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
686 // MTRR Physical Mask
688 TempQword
= ~(Length
- 1);
690 (UINT32
) (MtrrNumber
+ 1),
691 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
694 PostMtrrChange (Cr4
);
699 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
701 @param MtrrType MTRR memory type
703 @return The enum item in MTRR_MEMORY_CACHE_TYPE
707 MTRR_MEMORY_CACHE_TYPE
708 GetMemoryCacheTypeFromMtrrType (
713 case MTRR_CACHE_UNCACHEABLE
:
714 return CacheUncacheable
;
715 case MTRR_CACHE_WRITE_COMBINING
:
716 return CacheWriteCombining
;
717 case MTRR_CACHE_WRITE_THROUGH
:
718 return CacheWriteThrough
;
719 case MTRR_CACHE_WRITE_PROTECTED
:
720 return CacheWriteProtected
;
721 case MTRR_CACHE_WRITE_BACK
:
722 return CacheWriteBack
;
725 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
726 // no mtrr covers the range
728 return CacheUncacheable
;
733 Initializes the valid bits mask and valid address mask for MTRRs.
735 This function initializes the valid bits mask and valid address mask for MTRRs.
737 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
738 @param MtrrValidAddressMask The valid address mask for the MTRR
743 MtrrLibInitializeMtrrMask (
744 OUT UINT64
*MtrrValidBitsMask
,
745 OUT UINT64
*MtrrValidAddressMask
749 UINT8 PhysicalAddressBits
;
751 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
753 if (RegEax
>= 0x80000008) {
754 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
756 PhysicalAddressBits
= (UINT8
) RegEax
;
758 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
759 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
761 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
762 *MtrrValidAddressMask
= 0xFFFFFFFF;
768 Determing the real attribute of a memory range.
770 This function is to arbitrate the real attribute of the memory when
771 there are 2 MTRR covers the same memory range. For further details,
772 please refer the IA32 Software Developer's Manual, Volume 3,
775 @param MtrrType1 the first kind of Memory type
776 @param MtrrType2 the second kind of memory type
787 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
789 case MTRR_CACHE_UNCACHEABLE
:
790 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
792 case MTRR_CACHE_WRITE_COMBINING
:
794 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
795 MtrrType2
==MTRR_CACHE_UNCACHEABLE
797 MtrrType
= MtrrType2
;
800 case MTRR_CACHE_WRITE_THROUGH
:
802 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
803 MtrrType2
==MTRR_CACHE_WRITE_BACK
805 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
806 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
807 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
810 case MTRR_CACHE_WRITE_PROTECTED
:
811 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
812 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
813 MtrrType
= MtrrType2
;
816 case MTRR_CACHE_WRITE_BACK
:
818 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
819 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
820 MtrrType2
== MTRR_CACHE_WRITE_BACK
822 MtrrType
= MtrrType2
;
825 case MTRR_CACHE_INVALID_TYPE
:
826 MtrrType
= MtrrType2
;
832 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
833 MtrrType
= MtrrType1
;
840 This function attempts to set the attributes for a memory range.
842 @param BaseAddress The physical address that is the start
843 address of a memory region.
844 @param Length The size in bytes of the memory region.
845 @param Attributes The bit mask of attributes to set for the
848 @retval RETURN_SUCCESS The attributes were set for the memory
850 @retval RETURN_INVALID_PARAMETER Length is zero.
851 @retval RETURN_UNSUPPORTED The processor does not support one or
852 more bytes of the memory resource range
853 specified by BaseAddress and Length.
854 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
855 for the memory resource range specified
856 by BaseAddress and Length.
857 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
858 range specified by BaseAddress and Length
860 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
861 modify the attributes of the memory
867 MtrrSetMemoryAttribute (
868 IN PHYSICAL_ADDRESS BaseAddress
,
870 IN MTRR_MEMORY_CACHE_TYPE Attribute
874 RETURN_STATUS Status
;
881 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
883 UINT64 MtrrValidBitsMask
;
884 UINT64 MtrrValidAddressMask
;
886 BOOLEAN OverwriteExistingMtrr
;
887 UINT32 FirmwareVariableMtrrCount
;
888 UINT32 VariableMtrrEnd
;
890 if (!IsMtrrSupported ()) {
891 return RETURN_UNSUPPORTED
;
894 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
895 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
897 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
900 MemoryType
= (UINT64
)Attribute
;
901 OverwriteExistingMtrr
= FALSE
;
904 // Check for an invalid parameter
907 return RETURN_INVALID_PARAMETER
;
911 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
912 (Length
&~MtrrValidAddressMask
) != 0
914 return RETURN_UNSUPPORTED
;
918 // Check if Fixed MTRR
920 Status
= RETURN_SUCCESS
;
921 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
922 Cr4
= PreMtrrChange ();
923 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
924 PostMtrrChange (Cr4
);
925 if (RETURN_ERROR (Status
)) {
932 // A Length of 0 can only make sense for fixed MTTR ranges.
933 // Since we just handled the fixed MTRRs, we can skip the
934 // variable MTRR section.
940 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
941 // we can set the bade to 0 to save variable MTRRs.
943 if (BaseAddress
== BASE_1MB
) {
949 // Check memory base address alignment
951 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
952 if (Remainder
!= 0) {
953 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
954 if (Remainder
!= 0) {
955 Status
= RETURN_UNSUPPORTED
;
963 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
964 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
966 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
967 if (RETURN_ERROR (Status
)) {
973 // Combined successfully
975 Status
= RETURN_SUCCESS
;
981 // Program Variable MTRRs
983 // Avoid hardcode here and read data dynamically
985 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
986 Status
= RETURN_OUT_OF_RESOURCES
;
991 // The memory type is the same with the type specified by
992 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
994 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
996 // Invalidate the now-unused MTRRs
998 InvalidateMtrr(VariableMtrr
);
1005 if (TempQword
== Power2MaxMemory (TempQword
)) {
1007 // Invalidate the now-unused MTRRs
1009 InvalidateMtrr(VariableMtrr
);
1012 // Find first unused MTRR
1014 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1015 MsrNum
< VariableMtrrEnd
;
1018 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1023 ProgramVariableMtrr (
1028 MtrrValidAddressMask
1032 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1034 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1035 Status
= RETURN_OUT_OF_RESOURCES
;
1040 // Invalidate the now-unused MTRRs
1042 InvalidateMtrr(VariableMtrr
);
1045 // Find first unused MTRR
1047 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1048 MsrNum
< VariableMtrrEnd
;
1051 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1057 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1058 ProgramVariableMtrr (
1063 MtrrValidAddressMask
1065 BaseAddress
+= Length
;
1066 TempQword
= Length
- TempQword
;
1067 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1074 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1075 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1080 Length
= Power2MaxMemory (TempQword
);
1082 BaseAddress
-= Length
;
1085 ProgramVariableMtrr (
1090 MtrrValidAddressMask
1094 BaseAddress
+= Length
;
1096 TempQword
-= Length
;
1098 } while (TempQword
> 0);
1108 This function will get the memory cache type of the specific address.
1110 This function is mainly for debug purpose.
1112 @param Address The specific address
1114 @return Memory cache type of the sepcific address
1117 MTRR_MEMORY_CACHE_TYPE
1119 MtrrGetMemoryAttribute (
1120 IN PHYSICAL_ADDRESS Address
1127 UINT64 TempMtrrType
;
1128 MTRR_MEMORY_CACHE_TYPE CacheType
;
1129 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1130 UINT64 MtrrValidBitsMask
;
1131 UINT64 MtrrValidAddressMask
;
1132 UINTN VariableMtrrCount
;
1134 if (!IsMtrrSupported ()) {
1135 return CacheUncacheable
;
1139 // Check if MTRR is enabled, if not, return UC as attribute
1141 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1142 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1144 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1145 return CacheUncacheable
;
1149 // If address is less than 1M, then try to go through the fixed MTRR
1151 if (Address
< BASE_1MB
) {
1152 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1154 // Go through the fixed MTRR
1156 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1157 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1159 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1160 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1164 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1165 MtrrLibFixedMtrrTable
[Index
].Length
;
1166 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1167 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1168 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1173 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1174 MtrrGetMemoryAttributeInVariableMtrr(
1176 MtrrValidAddressMask
,
1181 // Go through the variable MTRR
1183 VariableMtrrCount
= GetVariableMtrrCount ();
1184 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1186 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1187 if (VariableMtrr
[Index
].Valid
) {
1188 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1189 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1190 TempMtrrType
= VariableMtrr
[Index
].Type
;
1191 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1195 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1202 This function will get the raw value in variable MTRRs
1204 @param VariableSettings A buffer to hold variable MTRRs content.
1206 @return The VariableSettings input pointer
1209 MTRR_VARIABLE_SETTINGS
*
1211 MtrrGetVariableMtrr (
1212 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1216 UINT32 VariableMtrrCount
;
1218 if (!IsMtrrSupported ()) {
1219 return VariableSettings
;
1222 VariableMtrrCount
= GetVariableMtrrCount ();
1223 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1225 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1226 VariableSettings
->Mtrr
[Index
].Base
=
1227 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1228 VariableSettings
->Mtrr
[Index
].Mask
=
1229 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1232 return VariableSettings
;
1237 Worker function setting variable MTRRs
1239 @param VariableSettings A buffer to hold variable MTRRs content.
1243 MtrrSetVariableMtrrWorker (
1244 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1248 UINT32 VariableMtrrCount
;
1250 VariableMtrrCount
= GetVariableMtrrCount ();
1251 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1253 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1255 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1256 VariableSettings
->Mtrr
[Index
].Base
1259 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1260 VariableSettings
->Mtrr
[Index
].Mask
1267 This function sets variable MTRRs
1269 @param VariableSettings A buffer to hold variable MTRRs content.
1271 @return The pointer of VariableSettings
1274 MTRR_VARIABLE_SETTINGS
*
1276 MtrrSetVariableMtrr (
1277 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1282 if (!IsMtrrSupported ()) {
1283 return VariableSettings
;
1286 Cr4
= PreMtrrChange ();
1287 MtrrSetVariableMtrrWorker (VariableSettings
);
1288 PostMtrrChange (Cr4
);
1289 return VariableSettings
;
1294 This function gets the content in fixed MTRRs
1296 @param FixedSettings A buffer to hold fixed Mtrrs content.
1298 @retval The pointer of FixedSettings
1301 MTRR_FIXED_SETTINGS
*
1304 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1309 if (!IsMtrrSupported ()) {
1310 return FixedSettings
;
1313 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1314 FixedSettings
->Mtrr
[Index
] =
1315 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1318 return FixedSettings
;
1322 Worker function setting fixed MTRRs
1324 @param FixedSettings A buffer to hold fixed Mtrrs content.
1328 MtrrSetFixedMtrrWorker (
1329 IN MTRR_FIXED_SETTINGS
*FixedSettings
1334 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1336 MtrrLibFixedMtrrTable
[Index
].Msr
,
1337 FixedSettings
->Mtrr
[Index
]
1344 This function sets fixed MTRRs
1346 @param FixedSettings A buffer to hold fixed Mtrrs content.
1348 @retval The pointer of FixedSettings
1351 MTRR_FIXED_SETTINGS
*
1354 IN MTRR_FIXED_SETTINGS
*FixedSettings
1359 if (!IsMtrrSupported ()) {
1360 return FixedSettings
;
1363 Cr4
= PreMtrrChange ();
1364 MtrrSetFixedMtrrWorker (FixedSettings
);
1365 PostMtrrChange (Cr4
);
1367 return FixedSettings
;
1372 This function gets the content in all MTRRs (variable and fixed)
1374 @param MtrrSetting A buffer to hold all Mtrrs content.
1376 @retval the pointer of MtrrSetting
1382 OUT MTRR_SETTINGS
*MtrrSetting
1385 if (!IsMtrrSupported ()) {
1392 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1395 // Get variable MTRRs
1397 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1400 // Get MTRR_DEF_TYPE value
1402 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1409 This function sets all MTRRs (variable and fixed)
1411 @param MtrrSetting A buffer holding all MTRRs content.
1413 @retval The pointer of MtrrSetting
1419 IN MTRR_SETTINGS
*MtrrSetting
1424 if (!IsMtrrSupported ()) {
1428 Cr4
= PreMtrrChange ();
1433 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1436 // Set variable MTRRs
1438 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1441 // Set MTRR_DEF_TYPE value
1443 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1445 PostMtrrChange (Cr4
);
1452 This function prints all MTRRs for debugging.
1455 MtrrDebugPrintAllMtrrs (
1460 MTRR_SETTINGS MtrrSettings
;
1462 UINTN VariableMtrrCount
;
1464 if (!IsMtrrSupported ()) {
1468 MtrrGetAllMtrrs (&MtrrSettings
);
1469 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1470 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1472 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1474 MtrrSettings
.Fixed
.Mtrr
[Index
]
1478 VariableMtrrCount
= GetVariableMtrrCount ();
1479 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1481 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1483 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1484 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1492 Checks if MTRR is supported.
1494 @retval TRUE MTRR is supported.
1495 @retval FALSE MTRR is not supported.
1508 // Check CPUID(1).EDX[12] for MTRR capability
1510 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1511 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1516 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1517 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1518 // exist, return false.
1520 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1521 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {