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 The default MTRR cache type.
150 MTRR_MEMORY_CACHE_TYPE
152 MtrrGetDefaultMemoryType (
156 if (!IsMtrrSupported ()) {
157 return CacheUncacheable
;
160 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
164 Preparation before programming MTRR.
166 This function will do some preparation for programming MTRRs:
167 disable cache, invalid cache and disable MTRR caching functionality
169 @return CR4 value before changing.
180 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
185 // Save original CR4 value and clear PGE flag (Bit 7)
187 Value
= AsmReadCr4 ();
188 AsmWriteCr4 (Value
& (~BIT7
));
198 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
201 // Return original CR4 value
208 Cleaning up after programming MTRRs.
210 This function will do some clean up after programming MTRRs:
211 enable MTRR caching functionality, and enable cache
213 @param Cr4 CR4 value to restore
224 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
232 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
237 // Restore original CR4 value
244 Programs fixed MTRRs registers.
246 @param MemoryCacheType The memory type to set.
247 @param Base The base address of memory range.
248 @param Length The length of memory range.
250 @retval RETURN_SUCCESS The cache type was updated successfully
251 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
257 IN UINT64 MemoryCacheType
,
259 IN OUT UINT64
*Length
272 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
273 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
276 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
277 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
285 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
286 return RETURN_UNSUPPORTED
;
290 // We found the fixed MTRR to be programmed
292 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
295 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
296 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
303 if (ByteShift
== 8) {
304 return RETURN_UNSUPPORTED
;
309 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
312 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
313 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
314 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
315 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
318 if (ByteShift
< 8 && (*Length
!= 0)) {
319 return RETURN_UNSUPPORTED
;
323 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
324 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
325 return RETURN_SUCCESS
;
330 Get the attribute of variable MTRRs.
332 This function shadows the content of variable MTRRs into an
333 internal array: VariableMtrr.
335 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
336 @param MtrrValidAddressMask The valid address mask for MTRR
337 @param VariableMtrr The array to shadow variable MTRRs content
339 @return The return value of this paramter indicates the
340 number of MTRRs which has been used.
345 MtrrGetMemoryAttributeInVariableMtrr (
346 IN UINT64 MtrrValidBitsMask
,
347 IN UINT64 MtrrValidAddressMask
,
348 OUT VARIABLE_MTRR
*VariableMtrr
354 UINT32 FirmwareVariableMtrrCount
;
355 UINT32 VariableMtrrEnd
;
357 if (!IsMtrrSupported ()) {
361 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
362 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
364 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
367 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
369 (MsrNum
< VariableMtrrEnd
) &&
370 (Index
< FirmwareVariableMtrrCount
)
374 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
375 VariableMtrr
[Index
].Msr
= MsrNum
;
376 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
377 MtrrValidAddressMask
);
378 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
379 MtrrValidAddressMask
)
383 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
384 VariableMtrr
[Index
].Valid
= TRUE
;
385 VariableMtrr
[Index
].Used
= TRUE
;
386 UsedMtrr
= UsedMtrr
+ 1;
395 Checks overlap between given memory range and MTRRs.
397 @param Start The start address of memory range.
398 @param End The end address of memory range.
399 @param VariableMtrr The array to shadow variable MTRRs content
401 @retval TRUE Overlap exists.
402 @retval FALSE No overlap.
406 CheckMemoryAttributeOverlap (
407 IN PHYSICAL_ADDRESS Start
,
408 IN PHYSICAL_ADDRESS End
,
409 IN VARIABLE_MTRR
*VariableMtrr
414 for (Index
= 0; Index
< 6; Index
++) {
416 VariableMtrr
[Index
].Valid
&&
418 (Start
> (VariableMtrr
[Index
].BaseAddress
+
419 VariableMtrr
[Index
].Length
- 1)
421 (End
< VariableMtrr
[Index
].BaseAddress
)
433 Marks a variable MTRR as non-valid.
435 @param Index The index of the array VariableMtrr to be invalidated
436 @param VariableMtrr The array to shadow variable MTRRs content
437 @param UsedMtrr The number of MTRRs which has already been used
441 InvalidateShadowMtrr (
443 IN VARIABLE_MTRR
*VariableMtrr
,
447 VariableMtrr
[Index
].Valid
= FALSE
;
448 *UsedMtrr
= *UsedMtrr
- 1;
453 Combine memory attributes.
455 If overlap exists between given memory range and MTRRs, try to combine them.
457 @param Attributes The memory type to set.
458 @param Base The base address of memory range.
459 @param Length The length of memory range.
460 @param VariableMtrr The array to shadow variable MTRRs content
461 @param UsedMtrr The number of MTRRs which has already been used
462 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
464 @retval EFI_SUCCESS Memory region successfully combined.
465 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
469 CombineMemoryAttribute (
470 IN UINT64 Attributes
,
472 IN OUT UINT64
*Length
,
473 IN VARIABLE_MTRR
*VariableMtrr
,
474 IN OUT UINT32
*UsedMtrr
,
475 OUT BOOLEAN
*OverwriteExistingMtrr
483 UINT32 FirmwareVariableMtrrCount
;
484 BOOLEAN CoveredByExistingMtrr
;
486 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
488 *OverwriteExistingMtrr
= FALSE
;
489 CoveredByExistingMtrr
= FALSE
;
490 EndAddress
= *Base
+*Length
- 1;
492 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
494 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
496 !VariableMtrr
[Index
].Valid
||
499 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
506 // Combine same attribute MTRR range
508 if (Attributes
== VariableMtrr
[Index
].Type
) {
510 // if the Mtrr range contain the request range, set a flag, then continue to
511 // invalidate any MTRR of the same request range with higher priority cache type.
513 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
514 CoveredByExistingMtrr
= TRUE
;
518 // invalid this MTRR, and program the combine range
521 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
523 VariableMtrr
[Index
].BaseAddress
;
524 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
527 // Record the MTRR usage status in VariableMtrr array.
529 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
530 *Base
= CombineStart
;
531 *Length
= CombineEnd
- CombineStart
+ 1;
532 EndAddress
= CombineEnd
;
533 *OverwriteExistingMtrr
= TRUE
;
537 // The cache type is different, but the range is convered by one MTRR
539 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
540 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
546 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
547 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
548 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
549 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
550 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
551 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
553 *OverwriteExistingMtrr
= TRUE
;
557 // Other type memory overlap is invalid
559 return RETURN_ACCESS_DENIED
;
562 if (CoveredByExistingMtrr
) {
566 return RETURN_SUCCESS
;
571 Calculate the maximum value which is a power of 2, but less the MemoryLength.
573 @param MemoryLength The number to pass in.
574 @return The maximum value which is align to power of 2 and less the MemoryLength
579 IN UINT64 MemoryLength
584 if (RShiftU64 (MemoryLength
, 32) != 0) {
586 (UINT64
) GetPowerOfTwo32 (
587 (UINT32
) RShiftU64 (MemoryLength
, 32)
592 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
600 Determine the MTRR numbers used to program a memory range.
602 This function first checks the alignment of the base address. If the alignment of the base address <= Length,
603 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
604 Repeat the step until alignment > Length.
606 Then this function determines which direction of programming the variable MTRRs for the remaining length
607 will use fewer MTRRs.
609 @param BaseAddress Length of Memory to program MTRR
610 @param Length Length of Memory to program MTRR
611 @param MtrrNumber Pointer to the number of necessary MTRRs
613 @retval TRUE Positive direction is better.
614 FALSE Negtive direction is better.
618 GetMtrrNumberAndDirection (
619 IN UINT64 BaseAddress
,
631 if (BaseAddress
!= 0) {
634 // Calculate the alignment of the base address.
636 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
638 if (Alignment
> Length
) {
643 BaseAddress
+= Alignment
;
657 TempQword
-= Power2MaxMemory (TempQword
);
659 } while (TempQword
!= 0);
661 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
664 TempQword
-= Power2MaxMemory (TempQword
);
666 } while (TempQword
!= 0);
668 if (Positive
<= Subtractive
) {
669 *MtrrNumber
+= Positive
;
672 *MtrrNumber
+= Subtractive
;
678 Invalid variable MTRRs according to the value in the shadow array.
680 This function programs MTRRs according to the values specified
683 @param VariableMtrr The array to shadow variable MTRRs content
688 IN VARIABLE_MTRR
*VariableMtrr
693 UINTN VariableMtrrCount
;
695 Cr4
= PreMtrrChange ();
697 VariableMtrrCount
= GetVariableMtrrCount ();
698 while (Index
< VariableMtrrCount
) {
699 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
700 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
701 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
702 VariableMtrr
[Index
].Used
= FALSE
;
706 PostMtrrChange (Cr4
);
711 Programs variable MTRRs
713 This function programs variable MTRRs
715 @param MtrrNumber Index of MTRR to program.
716 @param BaseAddress Base address of memory region.
717 @param Length Length of memory region.
718 @param MemoryCacheType Memory type to set.
719 @param MtrrValidAddressMask The valid address mask for MTRR
723 ProgramVariableMtrr (
725 IN PHYSICAL_ADDRESS BaseAddress
,
727 IN UINT64 MemoryCacheType
,
728 IN UINT64 MtrrValidAddressMask
734 Cr4
= PreMtrrChange ();
737 // MTRR Physical Base
739 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
740 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
743 // MTRR Physical Mask
745 TempQword
= ~(Length
- 1);
747 (UINT32
) (MtrrNumber
+ 1),
748 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
751 PostMtrrChange (Cr4
);
756 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
758 @param MtrrType MTRR memory type
760 @return The enum item in MTRR_MEMORY_CACHE_TYPE
763 MTRR_MEMORY_CACHE_TYPE
764 GetMemoryCacheTypeFromMtrrType (
769 case MTRR_CACHE_UNCACHEABLE
:
770 return CacheUncacheable
;
771 case MTRR_CACHE_WRITE_COMBINING
:
772 return CacheWriteCombining
;
773 case MTRR_CACHE_WRITE_THROUGH
:
774 return CacheWriteThrough
;
775 case MTRR_CACHE_WRITE_PROTECTED
:
776 return CacheWriteProtected
;
777 case MTRR_CACHE_WRITE_BACK
:
778 return CacheWriteBack
;
781 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
782 // no mtrr covers the range
784 return CacheUncacheable
;
789 Initializes the valid bits mask and valid address mask for MTRRs.
791 This function initializes the valid bits mask and valid address mask for MTRRs.
793 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
794 @param MtrrValidAddressMask The valid address mask for the MTRR
798 MtrrLibInitializeMtrrMask (
799 OUT UINT64
*MtrrValidBitsMask
,
800 OUT UINT64
*MtrrValidAddressMask
804 UINT8 PhysicalAddressBits
;
806 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
808 if (RegEax
>= 0x80000008) {
809 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
811 PhysicalAddressBits
= (UINT8
) RegEax
;
813 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
814 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
816 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
817 *MtrrValidAddressMask
= 0xFFFFFFFF;
823 Determing the real attribute of a memory range.
825 This function is to arbitrate the real attribute of the memory when
826 there are 2 MTRR covers the same memory range. For further details,
827 please refer the IA32 Software Developer's Manual, Volume 3,
830 @param MtrrType1 the first kind of Memory type
831 @param MtrrType2 the second kind of memory type
842 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
844 case MTRR_CACHE_UNCACHEABLE
:
845 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
847 case MTRR_CACHE_WRITE_COMBINING
:
849 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
850 MtrrType2
==MTRR_CACHE_UNCACHEABLE
852 MtrrType
= MtrrType2
;
855 case MTRR_CACHE_WRITE_THROUGH
:
857 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
858 MtrrType2
==MTRR_CACHE_WRITE_BACK
860 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
861 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
862 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
865 case MTRR_CACHE_WRITE_PROTECTED
:
866 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
867 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
868 MtrrType
= MtrrType2
;
871 case MTRR_CACHE_WRITE_BACK
:
873 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
874 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
875 MtrrType2
== MTRR_CACHE_WRITE_BACK
877 MtrrType
= MtrrType2
;
880 case MTRR_CACHE_INVALID_TYPE
:
881 MtrrType
= MtrrType2
;
887 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
888 MtrrType
= MtrrType1
;
895 This function attempts to set the attributes for a memory range.
897 @param BaseAddress The physical address that is the start
898 address of a memory region.
899 @param Length The size in bytes of the memory region.
900 @param Attributes The bit mask of attributes to set for the
903 @retval RETURN_SUCCESS The attributes were set for the memory
905 @retval RETURN_INVALID_PARAMETER Length is zero.
906 @retval RETURN_UNSUPPORTED The processor does not support one or
907 more bytes of the memory resource range
908 specified by BaseAddress and Length.
909 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
910 for the memory resource range specified
911 by BaseAddress and Length.
912 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
913 range specified by BaseAddress and Length
915 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
916 modify the attributes of the memory
922 MtrrSetMemoryAttribute (
923 IN PHYSICAL_ADDRESS BaseAddress
,
925 IN MTRR_MEMORY_CACHE_TYPE Attribute
929 RETURN_STATUS Status
;
936 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
938 UINT64 MtrrValidBitsMask
;
939 UINT64 MtrrValidAddressMask
;
941 BOOLEAN OverwriteExistingMtrr
;
942 UINT32 FirmwareVariableMtrrCount
;
943 UINT32 VariableMtrrEnd
;
945 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
947 if (!IsMtrrSupported ()) {
948 Status
= RETURN_UNSUPPORTED
;
952 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
953 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
955 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
958 MemoryType
= (UINT64
)Attribute
;
959 OverwriteExistingMtrr
= FALSE
;
962 // Check for an invalid parameter
965 Status
= RETURN_INVALID_PARAMETER
;
970 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
971 (Length
& ~MtrrValidAddressMask
) != 0
973 Status
= RETURN_UNSUPPORTED
;
978 // Check if Fixed MTRR
980 Status
= RETURN_SUCCESS
;
981 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
982 Cr4
= PreMtrrChange ();
983 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
984 PostMtrrChange (Cr4
);
985 if (RETURN_ERROR (Status
)) {
992 // A Length of 0 can only make sense for fixed MTTR ranges.
993 // Since we just handled the fixed MTRRs, we can skip the
994 // variable MTRR section.
1000 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1001 // we can set the base to 0 to save variable MTRRs.
1003 if (BaseAddress
== BASE_1MB
) {
1009 // Check for overlap
1011 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1012 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1014 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1015 if (RETURN_ERROR (Status
)) {
1021 // Combined successfully, invalidate the now-unused MTRRs
1023 InvalidateMtrr(VariableMtrr
);
1024 Status
= RETURN_SUCCESS
;
1030 // The memory type is the same with the type specified by
1031 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1033 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryType ())) {
1035 // Invalidate the now-unused MTRRs
1037 InvalidateMtrr(VariableMtrr
);
1041 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1043 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1044 Status
= RETURN_OUT_OF_RESOURCES
;
1049 // Invalidate the now-unused MTRRs
1051 InvalidateMtrr(VariableMtrr
);
1054 // Find first unused MTRR
1056 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1057 MsrNum
< VariableMtrrEnd
;
1060 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1065 if (BaseAddress
!= 0) {
1068 // Calculate the alignment of the base address.
1070 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1072 if (Alignment
> Length
) {
1079 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1080 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1085 ProgramVariableMtrr (
1090 MtrrValidAddressMask
1092 BaseAddress
+= Alignment
;
1093 Length
-= Alignment
;
1104 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1109 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1110 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1115 ProgramVariableMtrr (
1120 MtrrValidAddressMask
1122 BaseAddress
+= Length
;
1123 TempQword
= Length
- TempQword
;
1124 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1131 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1132 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1137 Length
= Power2MaxMemory (TempQword
);
1139 BaseAddress
-= Length
;
1142 ProgramVariableMtrr (
1147 MtrrValidAddressMask
1151 BaseAddress
+= Length
;
1153 TempQword
-= Length
;
1155 } while (TempQword
> 0);
1158 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1159 if (!RETURN_ERROR (Status
)) {
1160 MtrrDebugPrintAllMtrrs ();
1168 This function will get the memory cache type of the specific address.
1170 This function is mainly for debug purpose.
1172 @param Address The specific address
1174 @return Memory cache type of the sepcific address
1177 MTRR_MEMORY_CACHE_TYPE
1179 MtrrGetMemoryAttribute (
1180 IN PHYSICAL_ADDRESS Address
1187 UINT64 TempMtrrType
;
1188 MTRR_MEMORY_CACHE_TYPE CacheType
;
1189 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1190 UINT64 MtrrValidBitsMask
;
1191 UINT64 MtrrValidAddressMask
;
1192 UINTN VariableMtrrCount
;
1194 if (!IsMtrrSupported ()) {
1195 return CacheUncacheable
;
1199 // Check if MTRR is enabled, if not, return UC as attribute
1201 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1202 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1204 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1205 return CacheUncacheable
;
1209 // If address is less than 1M, then try to go through the fixed MTRR
1211 if (Address
< BASE_1MB
) {
1212 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1214 // Go through the fixed MTRR
1216 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1217 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1219 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1220 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1224 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1225 mMtrrLibFixedMtrrTable
[Index
].Length
;
1226 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1227 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1228 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1233 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1234 MtrrGetMemoryAttributeInVariableMtrr(
1236 MtrrValidAddressMask
,
1241 // Go through the variable MTRR
1243 VariableMtrrCount
= GetVariableMtrrCount ();
1244 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1246 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1247 if (VariableMtrr
[Index
].Valid
) {
1248 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1249 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1250 TempMtrrType
= VariableMtrr
[Index
].Type
;
1251 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1255 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1262 This function will get the raw value in variable MTRRs
1264 @param VariableSettings A buffer to hold variable MTRRs content.
1266 @return The VariableSettings input pointer
1269 MTRR_VARIABLE_SETTINGS
*
1271 MtrrGetVariableMtrr (
1272 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1276 UINT32 VariableMtrrCount
;
1278 if (!IsMtrrSupported ()) {
1279 return VariableSettings
;
1282 VariableMtrrCount
= GetVariableMtrrCount ();
1283 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1285 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1286 VariableSettings
->Mtrr
[Index
].Base
=
1287 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1288 VariableSettings
->Mtrr
[Index
].Mask
=
1289 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1292 return VariableSettings
;
1297 Worker function setting variable MTRRs
1299 @param VariableSettings A buffer to hold variable MTRRs content.
1303 MtrrSetVariableMtrrWorker (
1304 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1308 UINT32 VariableMtrrCount
;
1310 VariableMtrrCount
= GetVariableMtrrCount ();
1311 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1313 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1315 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1316 VariableSettings
->Mtrr
[Index
].Base
1319 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1320 VariableSettings
->Mtrr
[Index
].Mask
1327 This function sets variable MTRRs
1329 @param VariableSettings A buffer to hold variable MTRRs content.
1331 @return The pointer of VariableSettings
1334 MTRR_VARIABLE_SETTINGS
*
1336 MtrrSetVariableMtrr (
1337 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1342 if (!IsMtrrSupported ()) {
1343 return VariableSettings
;
1346 Cr4
= PreMtrrChange ();
1347 MtrrSetVariableMtrrWorker (VariableSettings
);
1348 PostMtrrChange (Cr4
);
1349 return VariableSettings
;
1354 This function gets the content in fixed MTRRs
1356 @param FixedSettings A buffer to hold fixed Mtrrs content.
1358 @retval The pointer of FixedSettings
1361 MTRR_FIXED_SETTINGS
*
1364 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1369 if (!IsMtrrSupported ()) {
1370 return FixedSettings
;
1373 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1374 FixedSettings
->Mtrr
[Index
] =
1375 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1378 return FixedSettings
;
1382 Worker function setting fixed MTRRs
1384 @param FixedSettings A buffer to hold fixed Mtrrs content.
1388 MtrrSetFixedMtrrWorker (
1389 IN MTRR_FIXED_SETTINGS
*FixedSettings
1394 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1396 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1397 FixedSettings
->Mtrr
[Index
]
1404 This function sets fixed MTRRs
1406 @param FixedSettings A buffer to hold fixed Mtrrs content.
1408 @retval The pointer of FixedSettings
1411 MTRR_FIXED_SETTINGS
*
1414 IN MTRR_FIXED_SETTINGS
*FixedSettings
1419 if (!IsMtrrSupported ()) {
1420 return FixedSettings
;
1423 Cr4
= PreMtrrChange ();
1424 MtrrSetFixedMtrrWorker (FixedSettings
);
1425 PostMtrrChange (Cr4
);
1427 return FixedSettings
;
1432 This function gets the content in all MTRRs (variable and fixed)
1434 @param MtrrSetting A buffer to hold all Mtrrs content.
1436 @retval the pointer of MtrrSetting
1442 OUT MTRR_SETTINGS
*MtrrSetting
1445 if (!IsMtrrSupported ()) {
1452 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1455 // Get variable MTRRs
1457 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1460 // Get MTRR_DEF_TYPE value
1462 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1469 This function sets all MTRRs (variable and fixed)
1471 @param MtrrSetting A buffer holding all MTRRs content.
1473 @retval The pointer of MtrrSetting
1479 IN MTRR_SETTINGS
*MtrrSetting
1484 if (!IsMtrrSupported ()) {
1488 Cr4
= PreMtrrChange ();
1493 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1496 // Set variable MTRRs
1498 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1501 // Set MTRR_DEF_TYPE value
1503 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1505 PostMtrrChange (Cr4
);
1511 This function prints all MTRRs for debugging.
1515 MtrrDebugPrintAllMtrrs (
1520 MTRR_SETTINGS MtrrSettings
;
1523 UINTN VariableMtrrCount
;
1531 UINT64 NoRangeLimit
;
1534 UINTN PreviousMemoryType
;
1537 if (!IsMtrrSupported ()) {
1541 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1542 DEBUG((DEBUG_CACHE
, "=============\n"));
1544 MtrrGetAllMtrrs (&MtrrSettings
);
1545 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1546 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1547 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1550 VariableMtrrCount
= GetVariableMtrrCount ();
1551 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1552 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1554 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1555 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1558 DEBUG((DEBUG_CACHE
, "\n"));
1559 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1560 DEBUG((DEBUG_CACHE
, "====================================\n"));
1563 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1564 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1565 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1566 for (Index1
= 0; Index1
< 8; Index1
++) {
1567 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1568 if (MemoryType
> CacheWriteBack
) {
1569 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1571 if (MemoryType
!= PreviousMemoryType
) {
1572 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1573 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1575 PreviousMemoryType
= MemoryType
;
1576 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1578 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1581 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1583 VariableMtrrCount
= GetVariableMtrrCount ();
1586 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1588 MemoryType
= MtrrGetMemoryAttribute (Base
);
1589 if (MemoryType
> CacheWriteBack
) {
1590 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1593 if (MemoryType
!= PreviousMemoryType
) {
1594 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1595 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1597 PreviousMemoryType
= MemoryType
;
1598 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1601 RangeBase
= BASE_1MB
;
1602 NoRangeBase
= BASE_1MB
;
1604 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1605 if (RegEax
>= 0x80000008) {
1606 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1607 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1610 NoRangeLimit
= Limit
;
1612 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1613 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1615 // If mask is not valid, then do not display range
1619 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1620 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1622 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1626 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1627 RangeBase
= MtrrBase
;
1629 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1630 RangeBase
= MtrrLimit
+ 1;
1632 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1633 RangeLimit
= MtrrBase
- 1;
1635 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1636 RangeLimit
= MtrrLimit
;
1639 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1640 NoRangeBase
= MtrrLimit
+ 1;
1642 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1643 NoRangeLimit
= MtrrBase
- 1;
1648 Base
= RangeLimit
+ 1;
1650 Base
= NoRangeLimit
+ 1;
1653 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1658 Checks if MTRR is supported.
1660 @retval TRUE MTRR is supported.
1661 @retval FALSE MTRR is not supported.
1674 // Check CPUID(1).EDX[12] for MTRR capability
1676 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1677 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1682 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1683 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1684 // exist, return false.
1686 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1687 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {