4 Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
5 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
26 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
28 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
33 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
38 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
43 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
48 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
53 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
58 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
63 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
68 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
73 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
78 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
85 // Lookup table used to print MTRRs
87 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
88 "UC", // CacheUncacheable
89 "WC", // CacheWriteCombining
92 "WT", // CacheWriteThrough
93 "WP", // CacheWriteProtected
94 "WB", // CacheWriteBack
99 Returns the variable MTRR count for the CPU.
101 @return Variable MTRR count
106 GetVariableMtrrCount (
110 UINT32 VariableMtrrCount
;
112 if (!IsMtrrSupported ()) {
116 VariableMtrrCount
= (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
117 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
119 return VariableMtrrCount
;
123 Returns the firmware usable variable MTRR count for the CPU.
125 @return Firmware usable variable MTRR count
130 GetFirmwareVariableMtrrCount (
134 UINT32 VariableMtrrCount
;
136 VariableMtrrCount
= GetVariableMtrrCount ();
137 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
141 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
145 Returns the default MTRR cache type for the system.
147 @return MTRR default type
151 GetMtrrDefaultMemoryType (
155 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
160 Preparation before programming MTRR.
162 This function will do some preparation for programming MTRRs:
163 disable cache, invalid cache and disable MTRR caching functionality
165 @return CR4 value before changing.
176 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
181 // Save original CR4 value and clear PGE flag (Bit 7)
183 Value
= AsmReadCr4 ();
184 AsmWriteCr4 (Value
& (~BIT7
));
194 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
197 // Return original CR4 value
204 Cleaning up after programming MTRRs.
206 This function will do some clean up after programming MTRRs:
207 enable MTRR caching functionality, and enable cache
209 @param Cr4 CR4 value to restore
220 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
228 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
233 // Restore original CR4 value
240 Programs fixed MTRRs registers.
242 @param MemoryCacheType The memory type to set.
243 @param Base The base address of memory range.
244 @param Length The length of memory range.
246 @retval RETURN_SUCCESS The cache type was updated successfully
247 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
253 IN UINT64 MemoryCacheType
,
255 IN OUT UINT64
*Length
268 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
269 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
272 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
273 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
281 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
282 return RETURN_UNSUPPORTED
;
286 // We found the fixed MTRR to be programmed
288 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
291 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
292 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
299 if (ByteShift
== 8) {
300 return RETURN_UNSUPPORTED
;
305 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
308 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
309 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
310 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
311 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
314 if (ByteShift
< 8 && (*Length
!= 0)) {
315 return RETURN_UNSUPPORTED
;
319 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
320 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
321 return RETURN_SUCCESS
;
326 Get the attribute of variable MTRRs.
328 This function shadows the content of variable MTRRs into an
329 internal array: VariableMtrr.
331 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
332 @param MtrrValidAddressMask The valid address mask for MTRR
333 @param VariableMtrr The array to shadow variable MTRRs content
335 @return The return value of this paramter indicates the
336 number of MTRRs which has been used.
341 MtrrGetMemoryAttributeInVariableMtrr (
342 IN UINT64 MtrrValidBitsMask
,
343 IN UINT64 MtrrValidAddressMask
,
344 OUT VARIABLE_MTRR
*VariableMtrr
350 UINT32 FirmwareVariableMtrrCount
;
351 UINT32 VariableMtrrEnd
;
353 if (!IsMtrrSupported ()) {
357 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
358 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
360 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
363 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
365 (MsrNum
< VariableMtrrEnd
) &&
366 (Index
< FirmwareVariableMtrrCount
)
370 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
371 VariableMtrr
[Index
].Msr
= MsrNum
;
372 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
373 MtrrValidAddressMask
);
374 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
375 MtrrValidAddressMask
)
379 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
380 VariableMtrr
[Index
].Valid
= TRUE
;
381 VariableMtrr
[Index
].Used
= TRUE
;
382 UsedMtrr
= UsedMtrr
+ 1;
391 Checks overlap between given memory range and MTRRs.
393 @param Start The start address of memory range.
394 @param End The end address of memory range.
395 @param VariableMtrr The array to shadow variable MTRRs content
397 @retval TRUE Overlap exists.
398 @retval FALSE No overlap.
402 CheckMemoryAttributeOverlap (
403 IN PHYSICAL_ADDRESS Start
,
404 IN PHYSICAL_ADDRESS End
,
405 IN VARIABLE_MTRR
*VariableMtrr
410 for (Index
= 0; Index
< 6; Index
++) {
412 VariableMtrr
[Index
].Valid
&&
414 (Start
> (VariableMtrr
[Index
].BaseAddress
+
415 VariableMtrr
[Index
].Length
- 1)
417 (End
< VariableMtrr
[Index
].BaseAddress
)
429 Marks a variable MTRR as non-valid.
431 @param Index The index of the array VariableMtrr to be invalidated
432 @param VariableMtrr The array to shadow variable MTRRs content
433 @param UsedMtrr The number of MTRRs which has already been used
437 InvalidateShadowMtrr (
439 IN VARIABLE_MTRR
*VariableMtrr
,
443 VariableMtrr
[Index
].Valid
= FALSE
;
444 *UsedMtrr
= *UsedMtrr
- 1;
449 Combine memory attributes.
451 If overlap exists between given memory range and MTRRs, try to combine them.
453 @param Attributes The memory type to set.
454 @param Base The base address of memory range.
455 @param Length The length of memory range.
456 @param VariableMtrr The array to shadow variable MTRRs content
457 @param UsedMtrr The number of MTRRs which has already been used
458 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
460 @retval EFI_SUCCESS Memory region successfully combined.
461 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
465 CombineMemoryAttribute (
466 IN UINT64 Attributes
,
468 IN OUT UINT64
*Length
,
469 IN VARIABLE_MTRR
*VariableMtrr
,
470 IN OUT UINT32
*UsedMtrr
,
471 OUT BOOLEAN
*OverwriteExistingMtrr
479 UINT32 FirmwareVariableMtrrCount
;
480 BOOLEAN CoveredByExistingMtrr
;
482 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
484 *OverwriteExistingMtrr
= FALSE
;
485 CoveredByExistingMtrr
= FALSE
;
486 EndAddress
= *Base
+*Length
- 1;
488 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
490 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
492 !VariableMtrr
[Index
].Valid
||
495 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
502 // Combine same attribute MTRR range
504 if (Attributes
== VariableMtrr
[Index
].Type
) {
506 // if the Mtrr range contain the request range, set a flag, then continue to
507 // invalidate any MTRR of the same request range with higher priority cache type.
509 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
510 CoveredByExistingMtrr
= TRUE
;
514 // invalid this MTRR, and program the combine range
517 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
519 VariableMtrr
[Index
].BaseAddress
;
520 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
523 // Record the MTRR usage status in VariableMtrr array.
525 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
526 *Base
= CombineStart
;
527 *Length
= CombineEnd
- CombineStart
+ 1;
528 EndAddress
= CombineEnd
;
529 *OverwriteExistingMtrr
= TRUE
;
533 // The cache type is different, but the range is convered by one MTRR
535 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
536 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
542 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
543 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
544 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
545 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
546 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
547 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
549 *OverwriteExistingMtrr
= TRUE
;
553 // Other type memory overlap is invalid
555 return RETURN_ACCESS_DENIED
;
558 if (CoveredByExistingMtrr
) {
562 return RETURN_SUCCESS
;
567 Calculate the maximum value which is a power of 2, but less the MemoryLength.
569 @param MemoryLength The number to pass in.
570 @return The maximum value which is align to power of 2 and less the MemoryLength
575 IN UINT64 MemoryLength
580 if (RShiftU64 (MemoryLength
, 32) != 0) {
582 (UINT64
) GetPowerOfTwo32 (
583 (UINT32
) RShiftU64 (MemoryLength
, 32)
588 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
596 Determine the MTRR numbers used to program a memory range.
598 This function first checks the alignment of the base address. If the alignment of the base address <= Length,
599 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
600 Repeat the step until alignment > Length.
602 Then this function determines which direction of programming the variable MTRRs for the remaining length
603 will use fewer MTRRs.
605 @param BaseAddress Length of Memory to program MTRR
606 @param Length Length of Memory to program MTRR
607 @param MtrrNumber Pointer to the number of necessary MTRRs
609 @retval TRUE Positive direction is better.
610 FALSE Negtive direction is better.
614 GetMtrrNumberAndDirection (
615 IN UINT64 BaseAddress
,
627 if (BaseAddress
!= 0) {
630 // Calculate the alignment of the base address.
632 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
634 if (Alignment
> Length
) {
639 BaseAddress
+= Alignment
;
653 TempQword
-= Power2MaxMemory (TempQword
);
655 } while (TempQword
!= 0);
657 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
660 TempQword
-= Power2MaxMemory (TempQword
);
662 } while (TempQword
!= 0);
664 if (Positive
<= Subtractive
) {
665 *MtrrNumber
+= Positive
;
668 *MtrrNumber
+= Subtractive
;
674 Invalid variable MTRRs according to the value in the shadow array.
676 This function programs MTRRs according to the values specified
679 @param VariableMtrr The array to shadow variable MTRRs content
684 IN VARIABLE_MTRR
*VariableMtrr
689 UINTN VariableMtrrCount
;
691 Cr4
= PreMtrrChange ();
693 VariableMtrrCount
= GetVariableMtrrCount ();
694 while (Index
< VariableMtrrCount
) {
695 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
696 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
697 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
698 VariableMtrr
[Index
].Used
= FALSE
;
702 PostMtrrChange (Cr4
);
707 Programs variable MTRRs
709 This function programs variable MTRRs
711 @param MtrrNumber Index of MTRR to program.
712 @param BaseAddress Base address of memory region.
713 @param Length Length of memory region.
714 @param MemoryCacheType Memory type to set.
715 @param MtrrValidAddressMask The valid address mask for MTRR
719 ProgramVariableMtrr (
721 IN PHYSICAL_ADDRESS BaseAddress
,
723 IN UINT64 MemoryCacheType
,
724 IN UINT64 MtrrValidAddressMask
730 Cr4
= PreMtrrChange ();
733 // MTRR Physical Base
735 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
736 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
739 // MTRR Physical Mask
741 TempQword
= ~(Length
- 1);
743 (UINT32
) (MtrrNumber
+ 1),
744 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
747 PostMtrrChange (Cr4
);
752 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
754 @param MtrrType MTRR memory type
756 @return The enum item in MTRR_MEMORY_CACHE_TYPE
759 MTRR_MEMORY_CACHE_TYPE
760 GetMemoryCacheTypeFromMtrrType (
765 case MTRR_CACHE_UNCACHEABLE
:
766 return CacheUncacheable
;
767 case MTRR_CACHE_WRITE_COMBINING
:
768 return CacheWriteCombining
;
769 case MTRR_CACHE_WRITE_THROUGH
:
770 return CacheWriteThrough
;
771 case MTRR_CACHE_WRITE_PROTECTED
:
772 return CacheWriteProtected
;
773 case MTRR_CACHE_WRITE_BACK
:
774 return CacheWriteBack
;
777 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
778 // no mtrr covers the range
780 return CacheUncacheable
;
785 Initializes the valid bits mask and valid address mask for MTRRs.
787 This function initializes the valid bits mask and valid address mask for MTRRs.
789 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
790 @param MtrrValidAddressMask The valid address mask for the MTRR
794 MtrrLibInitializeMtrrMask (
795 OUT UINT64
*MtrrValidBitsMask
,
796 OUT UINT64
*MtrrValidAddressMask
800 UINT8 PhysicalAddressBits
;
802 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
804 if (RegEax
>= 0x80000008) {
805 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
807 PhysicalAddressBits
= (UINT8
) RegEax
;
809 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
810 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
812 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
813 *MtrrValidAddressMask
= 0xFFFFFFFF;
819 Determing the real attribute of a memory range.
821 This function is to arbitrate the real attribute of the memory when
822 there are 2 MTRR covers the same memory range. For further details,
823 please refer the IA32 Software Developer's Manual, Volume 3,
826 @param MtrrType1 the first kind of Memory type
827 @param MtrrType2 the second kind of memory type
838 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
840 case MTRR_CACHE_UNCACHEABLE
:
841 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
843 case MTRR_CACHE_WRITE_COMBINING
:
845 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
846 MtrrType2
==MTRR_CACHE_UNCACHEABLE
848 MtrrType
= MtrrType2
;
851 case MTRR_CACHE_WRITE_THROUGH
:
853 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
854 MtrrType2
==MTRR_CACHE_WRITE_BACK
856 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
857 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
858 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
861 case MTRR_CACHE_WRITE_PROTECTED
:
862 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
863 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
864 MtrrType
= MtrrType2
;
867 case MTRR_CACHE_WRITE_BACK
:
869 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
870 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
871 MtrrType2
== MTRR_CACHE_WRITE_BACK
873 MtrrType
= MtrrType2
;
876 case MTRR_CACHE_INVALID_TYPE
:
877 MtrrType
= MtrrType2
;
883 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
884 MtrrType
= MtrrType1
;
891 This function attempts to set the attributes for a memory range.
893 @param BaseAddress The physical address that is the start
894 address of a memory region.
895 @param Length The size in bytes of the memory region.
896 @param Attributes The bit mask of attributes to set for the
899 @retval RETURN_SUCCESS The attributes were set for the memory
901 @retval RETURN_INVALID_PARAMETER Length is zero.
902 @retval RETURN_UNSUPPORTED The processor does not support one or
903 more bytes of the memory resource range
904 specified by BaseAddress and Length.
905 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
906 for the memory resource range specified
907 by BaseAddress and Length.
908 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
909 range specified by BaseAddress and Length
911 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
912 modify the attributes of the memory
918 MtrrSetMemoryAttribute (
919 IN PHYSICAL_ADDRESS BaseAddress
,
921 IN MTRR_MEMORY_CACHE_TYPE Attribute
925 RETURN_STATUS Status
;
932 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
934 UINT64 MtrrValidBitsMask
;
935 UINT64 MtrrValidAddressMask
;
937 BOOLEAN OverwriteExistingMtrr
;
938 UINT32 FirmwareVariableMtrrCount
;
939 UINT32 VariableMtrrEnd
;
941 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
943 if (!IsMtrrSupported ()) {
944 Status
= RETURN_UNSUPPORTED
;
948 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
949 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
951 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
954 MemoryType
= (UINT64
)Attribute
;
955 OverwriteExistingMtrr
= FALSE
;
958 // Check for an invalid parameter
961 Status
= RETURN_INVALID_PARAMETER
;
966 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
967 (Length
& ~MtrrValidAddressMask
) != 0
969 Status
= RETURN_UNSUPPORTED
;
974 // Check if Fixed MTRR
976 Status
= RETURN_SUCCESS
;
977 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
978 Cr4
= PreMtrrChange ();
979 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
980 PostMtrrChange (Cr4
);
981 if (RETURN_ERROR (Status
)) {
988 // A Length of 0 can only make sense for fixed MTTR ranges.
989 // Since we just handled the fixed MTRRs, we can skip the
990 // variable MTRR section.
996 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
997 // we can set the base to 0 to save variable MTRRs.
999 if (BaseAddress
== BASE_1MB
) {
1005 // Check for overlap
1007 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1008 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1010 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1011 if (RETURN_ERROR (Status
)) {
1017 // Combined successfully, invalidate the now-unused MTRRs
1019 InvalidateMtrr(VariableMtrr
);
1020 Status
= RETURN_SUCCESS
;
1026 // Program Variable MTRRs
1028 // Avoid hardcode here and read data dynamically
1030 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
1031 Status
= RETURN_OUT_OF_RESOURCES
;
1036 // The memory type is the same with the type specified by
1037 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1039 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
1041 // Invalidate the now-unused MTRRs
1043 InvalidateMtrr(VariableMtrr
);
1047 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1049 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1050 Status
= RETURN_OUT_OF_RESOURCES
;
1055 // Invalidate the now-unused MTRRs
1057 InvalidateMtrr(VariableMtrr
);
1060 // Find first unused MTRR
1062 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1063 MsrNum
< VariableMtrrEnd
;
1066 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1071 if (BaseAddress
!= 0) {
1074 // Calculate the alignment of the base address.
1076 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1078 if (Alignment
> Length
) {
1085 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1086 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1091 ProgramVariableMtrr (
1096 MtrrValidAddressMask
1098 BaseAddress
+= Alignment
;
1099 Length
-= Alignment
;
1110 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1115 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1116 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1121 ProgramVariableMtrr (
1126 MtrrValidAddressMask
1128 BaseAddress
+= Length
;
1129 TempQword
= Length
- TempQword
;
1130 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1137 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1138 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1143 Length
= Power2MaxMemory (TempQword
);
1145 BaseAddress
-= Length
;
1148 ProgramVariableMtrr (
1153 MtrrValidAddressMask
1157 BaseAddress
+= Length
;
1159 TempQword
-= Length
;
1161 } while (TempQword
> 0);
1164 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1165 if (!RETURN_ERROR (Status
)) {
1166 MtrrDebugPrintAllMtrrs ();
1174 This function will get the memory cache type of the specific address.
1176 This function is mainly for debug purpose.
1178 @param Address The specific address
1180 @return Memory cache type of the sepcific address
1183 MTRR_MEMORY_CACHE_TYPE
1185 MtrrGetMemoryAttribute (
1186 IN PHYSICAL_ADDRESS Address
1193 UINT64 TempMtrrType
;
1194 MTRR_MEMORY_CACHE_TYPE CacheType
;
1195 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1196 UINT64 MtrrValidBitsMask
;
1197 UINT64 MtrrValidAddressMask
;
1198 UINTN VariableMtrrCount
;
1200 if (!IsMtrrSupported ()) {
1201 return CacheUncacheable
;
1205 // Check if MTRR is enabled, if not, return UC as attribute
1207 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1208 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1210 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1211 return CacheUncacheable
;
1215 // If address is less than 1M, then try to go through the fixed MTRR
1217 if (Address
< BASE_1MB
) {
1218 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1220 // Go through the fixed MTRR
1222 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1223 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1225 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1226 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1230 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1231 mMtrrLibFixedMtrrTable
[Index
].Length
;
1232 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1233 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1234 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1239 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1240 MtrrGetMemoryAttributeInVariableMtrr(
1242 MtrrValidAddressMask
,
1247 // Go through the variable MTRR
1249 VariableMtrrCount
= GetVariableMtrrCount ();
1250 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1252 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1253 if (VariableMtrr
[Index
].Valid
) {
1254 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1255 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1256 TempMtrrType
= VariableMtrr
[Index
].Type
;
1257 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1261 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1268 This function will get the raw value in variable MTRRs
1270 @param VariableSettings A buffer to hold variable MTRRs content.
1272 @return The VariableSettings input pointer
1275 MTRR_VARIABLE_SETTINGS
*
1277 MtrrGetVariableMtrr (
1278 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1282 UINT32 VariableMtrrCount
;
1284 if (!IsMtrrSupported ()) {
1285 return VariableSettings
;
1288 VariableMtrrCount
= GetVariableMtrrCount ();
1289 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1291 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1292 VariableSettings
->Mtrr
[Index
].Base
=
1293 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1294 VariableSettings
->Mtrr
[Index
].Mask
=
1295 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1298 return VariableSettings
;
1303 Worker function setting variable MTRRs
1305 @param VariableSettings A buffer to hold variable MTRRs content.
1309 MtrrSetVariableMtrrWorker (
1310 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1314 UINT32 VariableMtrrCount
;
1316 VariableMtrrCount
= GetVariableMtrrCount ();
1317 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1319 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1321 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1322 VariableSettings
->Mtrr
[Index
].Base
1325 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1326 VariableSettings
->Mtrr
[Index
].Mask
1333 This function sets variable MTRRs
1335 @param VariableSettings A buffer to hold variable MTRRs content.
1337 @return The pointer of VariableSettings
1340 MTRR_VARIABLE_SETTINGS
*
1342 MtrrSetVariableMtrr (
1343 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1348 if (!IsMtrrSupported ()) {
1349 return VariableSettings
;
1352 Cr4
= PreMtrrChange ();
1353 MtrrSetVariableMtrrWorker (VariableSettings
);
1354 PostMtrrChange (Cr4
);
1355 return VariableSettings
;
1360 This function gets the content in fixed MTRRs
1362 @param FixedSettings A buffer to hold fixed Mtrrs content.
1364 @retval The pointer of FixedSettings
1367 MTRR_FIXED_SETTINGS
*
1370 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1375 if (!IsMtrrSupported ()) {
1376 return FixedSettings
;
1379 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1380 FixedSettings
->Mtrr
[Index
] =
1381 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1384 return FixedSettings
;
1388 Worker function setting fixed MTRRs
1390 @param FixedSettings A buffer to hold fixed Mtrrs content.
1394 MtrrSetFixedMtrrWorker (
1395 IN MTRR_FIXED_SETTINGS
*FixedSettings
1400 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1402 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1403 FixedSettings
->Mtrr
[Index
]
1410 This function sets fixed MTRRs
1412 @param FixedSettings A buffer to hold fixed Mtrrs content.
1414 @retval The pointer of FixedSettings
1417 MTRR_FIXED_SETTINGS
*
1420 IN MTRR_FIXED_SETTINGS
*FixedSettings
1425 if (!IsMtrrSupported ()) {
1426 return FixedSettings
;
1429 Cr4
= PreMtrrChange ();
1430 MtrrSetFixedMtrrWorker (FixedSettings
);
1431 PostMtrrChange (Cr4
);
1433 return FixedSettings
;
1438 This function gets the content in all MTRRs (variable and fixed)
1440 @param MtrrSetting A buffer to hold all Mtrrs content.
1442 @retval the pointer of MtrrSetting
1448 OUT MTRR_SETTINGS
*MtrrSetting
1451 if (!IsMtrrSupported ()) {
1458 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1461 // Get variable MTRRs
1463 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1466 // Get MTRR_DEF_TYPE value
1468 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1475 This function sets all MTRRs (variable and fixed)
1477 @param MtrrSetting A buffer holding all MTRRs content.
1479 @retval The pointer of MtrrSetting
1485 IN MTRR_SETTINGS
*MtrrSetting
1490 if (!IsMtrrSupported ()) {
1494 Cr4
= PreMtrrChange ();
1499 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1502 // Set variable MTRRs
1504 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1507 // Set MTRR_DEF_TYPE value
1509 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1511 PostMtrrChange (Cr4
);
1517 This function prints all MTRRs for debugging.
1521 MtrrDebugPrintAllMtrrs (
1526 MTRR_SETTINGS MtrrSettings
;
1529 UINTN VariableMtrrCount
;
1537 UINT64 NoRangeLimit
;
1540 UINTN PreviousMemoryType
;
1543 if (!IsMtrrSupported ()) {
1547 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1548 DEBUG((DEBUG_CACHE
, "=============\n"));
1550 MtrrGetAllMtrrs (&MtrrSettings
);
1551 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1552 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1553 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1556 VariableMtrrCount
= GetVariableMtrrCount ();
1557 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1558 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1560 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1561 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1564 DEBUG((DEBUG_CACHE
, "\n"));
1565 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1566 DEBUG((DEBUG_CACHE
, "====================================\n"));
1569 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1570 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1571 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1572 for (Index1
= 0; Index1
< 8; Index1
++) {
1573 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1574 if (MemoryType
> CacheWriteBack
) {
1575 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1577 if (MemoryType
!= PreviousMemoryType
) {
1578 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1579 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1581 PreviousMemoryType
= MemoryType
;
1582 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1584 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1587 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1589 VariableMtrrCount
= GetVariableMtrrCount ();
1592 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1594 MemoryType
= MtrrGetMemoryAttribute (Base
);
1595 if (MemoryType
> CacheWriteBack
) {
1596 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1599 if (MemoryType
!= PreviousMemoryType
) {
1600 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1601 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1603 PreviousMemoryType
= MemoryType
;
1604 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1607 RangeBase
= BASE_1MB
;
1608 NoRangeBase
= BASE_1MB
;
1610 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1611 if (RegEax
>= 0x80000008) {
1612 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1613 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1616 NoRangeLimit
= Limit
;
1618 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1619 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1621 // If mask is not valid, then do not display range
1625 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1626 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1628 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1632 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1633 RangeBase
= MtrrBase
;
1635 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1636 RangeBase
= MtrrLimit
+ 1;
1638 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1639 RangeLimit
= MtrrBase
- 1;
1641 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1642 RangeLimit
= MtrrLimit
;
1645 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1646 NoRangeBase
= MtrrLimit
+ 1;
1648 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1649 NoRangeLimit
= MtrrBase
- 1;
1654 Base
= RangeLimit
+ 1;
1656 Base
= NoRangeLimit
+ 1;
1659 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1664 Checks if MTRR is supported.
1666 @retval TRUE MTRR is supported.
1667 @retval FALSE MTRR is not supported.
1680 // Check CPUID(1).EDX[12] for MTRR capability
1682 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1683 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1688 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1689 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1690 // exist, return false.
1692 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1693 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {