4 Copyright (c) 2008 - 2012, 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
207 Cleaning up after programming MTRRs.
209 This function will do some clean up after programming MTRRs:
210 Flush all TLBs, re-enable caching, restore CR4.
212 @param Cr4 CR4 value to restore
216 PostMtrrChangeEnableCache (
226 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
231 // Restore original CR4 value
237 Cleaning up after programming MTRRs.
239 This function will do some clean up after programming MTRRs:
240 enable MTRR caching functionality, and enable cache
242 @param Cr4 CR4 value to restore
253 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
255 PostMtrrChangeEnableCache (Cr4
);
260 Programs fixed MTRRs registers.
262 @param MemoryCacheType The memory type to set.
263 @param Base The base address of memory range.
264 @param Length The length of memory range.
266 @retval RETURN_SUCCESS The cache type was updated successfully
267 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
273 IN UINT64 MemoryCacheType
,
275 IN OUT UINT64
*Length
288 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
289 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
292 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
293 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
301 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
302 return RETURN_UNSUPPORTED
;
306 // We found the fixed MTRR to be programmed
308 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
311 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
312 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
319 if (ByteShift
== 8) {
320 return RETURN_UNSUPPORTED
;
325 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
328 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
329 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
330 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
331 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
334 if (ByteShift
< 8 && (*Length
!= 0)) {
335 return RETURN_UNSUPPORTED
;
339 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
340 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
341 return RETURN_SUCCESS
;
346 Get the attribute of variable MTRRs.
348 This function shadows the content of variable MTRRs into an
349 internal array: VariableMtrr.
351 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
352 @param MtrrValidAddressMask The valid address mask for MTRR
353 @param VariableMtrr The array to shadow variable MTRRs content
355 @return The return value of this paramter indicates the
356 number of MTRRs which has been used.
361 MtrrGetMemoryAttributeInVariableMtrr (
362 IN UINT64 MtrrValidBitsMask
,
363 IN UINT64 MtrrValidAddressMask
,
364 OUT VARIABLE_MTRR
*VariableMtrr
370 UINT32 FirmwareVariableMtrrCount
;
371 UINT32 VariableMtrrEnd
;
373 if (!IsMtrrSupported ()) {
377 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
378 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
380 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
383 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
385 (MsrNum
< VariableMtrrEnd
) &&
386 (Index
< FirmwareVariableMtrrCount
)
390 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
391 VariableMtrr
[Index
].Msr
= MsrNum
;
392 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
393 MtrrValidAddressMask
);
394 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
395 MtrrValidAddressMask
)
399 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
400 VariableMtrr
[Index
].Valid
= TRUE
;
401 VariableMtrr
[Index
].Used
= TRUE
;
402 UsedMtrr
= UsedMtrr
+ 1;
411 Checks overlap between given memory range and MTRRs.
413 @param Start The start address of memory range.
414 @param End The end address of memory range.
415 @param VariableMtrr The array to shadow variable MTRRs content
417 @retval TRUE Overlap exists.
418 @retval FALSE No overlap.
422 CheckMemoryAttributeOverlap (
423 IN PHYSICAL_ADDRESS Start
,
424 IN PHYSICAL_ADDRESS End
,
425 IN VARIABLE_MTRR
*VariableMtrr
430 for (Index
= 0; Index
< 6; Index
++) {
432 VariableMtrr
[Index
].Valid
&&
434 (Start
> (VariableMtrr
[Index
].BaseAddress
+
435 VariableMtrr
[Index
].Length
- 1)
437 (End
< VariableMtrr
[Index
].BaseAddress
)
449 Marks a variable MTRR as non-valid.
451 @param Index The index of the array VariableMtrr to be invalidated
452 @param VariableMtrr The array to shadow variable MTRRs content
453 @param UsedMtrr The number of MTRRs which has already been used
457 InvalidateShadowMtrr (
459 IN VARIABLE_MTRR
*VariableMtrr
,
463 VariableMtrr
[Index
].Valid
= FALSE
;
464 *UsedMtrr
= *UsedMtrr
- 1;
469 Combine memory attributes.
471 If overlap exists between given memory range and MTRRs, try to combine them.
473 @param Attributes The memory type to set.
474 @param Base The base address of memory range.
475 @param Length The length of memory range.
476 @param VariableMtrr The array to shadow variable MTRRs content
477 @param UsedMtrr The number of MTRRs which has already been used
478 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
480 @retval EFI_SUCCESS Memory region successfully combined.
481 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
485 CombineMemoryAttribute (
486 IN UINT64 Attributes
,
488 IN OUT UINT64
*Length
,
489 IN VARIABLE_MTRR
*VariableMtrr
,
490 IN OUT UINT32
*UsedMtrr
,
491 OUT BOOLEAN
*OverwriteExistingMtrr
499 UINT32 FirmwareVariableMtrrCount
;
500 BOOLEAN CoveredByExistingMtrr
;
502 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
504 *OverwriteExistingMtrr
= FALSE
;
505 CoveredByExistingMtrr
= FALSE
;
506 EndAddress
= *Base
+*Length
- 1;
508 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
510 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
512 !VariableMtrr
[Index
].Valid
||
515 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
522 // Combine same attribute MTRR range
524 if (Attributes
== VariableMtrr
[Index
].Type
) {
526 // if the Mtrr range contain the request range, set a flag, then continue to
527 // invalidate any MTRR of the same request range with higher priority cache type.
529 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
530 CoveredByExistingMtrr
= TRUE
;
534 // invalid this MTRR, and program the combine range
537 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
539 VariableMtrr
[Index
].BaseAddress
;
540 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
543 // Record the MTRR usage status in VariableMtrr array.
545 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
546 *Base
= CombineStart
;
547 *Length
= CombineEnd
- CombineStart
+ 1;
548 EndAddress
= CombineEnd
;
549 *OverwriteExistingMtrr
= TRUE
;
553 // The cache type is different, but the range is convered by one MTRR
555 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
556 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
562 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
563 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
564 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
565 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
566 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
567 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
569 *OverwriteExistingMtrr
= TRUE
;
573 // Other type memory overlap is invalid
575 return RETURN_ACCESS_DENIED
;
578 if (CoveredByExistingMtrr
) {
582 return RETURN_SUCCESS
;
587 Calculate the maximum value which is a power of 2, but less the MemoryLength.
589 @param MemoryLength The number to pass in.
590 @return The maximum value which is align to power of 2 and less the MemoryLength
595 IN UINT64 MemoryLength
600 if (RShiftU64 (MemoryLength
, 32) != 0) {
602 (UINT64
) GetPowerOfTwo32 (
603 (UINT32
) RShiftU64 (MemoryLength
, 32)
608 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
616 Determine the MTRR numbers used to program a memory range.
618 This function first checks the alignment of the base address. If the alignment of the base address <= Length,
619 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
620 Repeat the step until alignment > Length.
622 Then this function determines which direction of programming the variable MTRRs for the remaining length
623 will use fewer MTRRs.
625 @param BaseAddress Length of Memory to program MTRR
626 @param Length Length of Memory to program MTRR
627 @param MtrrNumber Pointer to the number of necessary MTRRs
629 @retval TRUE Positive direction is better.
630 FALSE Negtive direction is better.
634 GetMtrrNumberAndDirection (
635 IN UINT64 BaseAddress
,
647 if (BaseAddress
!= 0) {
650 // Calculate the alignment of the base address.
652 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
654 if (Alignment
> Length
) {
659 BaseAddress
+= Alignment
;
673 TempQword
-= Power2MaxMemory (TempQword
);
675 } while (TempQword
!= 0);
677 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
680 TempQword
-= Power2MaxMemory (TempQword
);
682 } while (TempQword
!= 0);
684 if (Positive
<= Subtractive
) {
685 *MtrrNumber
+= Positive
;
688 *MtrrNumber
+= Subtractive
;
694 Invalid variable MTRRs according to the value in the shadow array.
696 This function programs MTRRs according to the values specified
699 @param VariableMtrr The array to shadow variable MTRRs content
704 IN VARIABLE_MTRR
*VariableMtrr
709 UINTN VariableMtrrCount
;
711 Cr4
= PreMtrrChange ();
713 VariableMtrrCount
= GetVariableMtrrCount ();
714 while (Index
< VariableMtrrCount
) {
715 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
716 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
717 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
718 VariableMtrr
[Index
].Used
= FALSE
;
722 PostMtrrChange (Cr4
);
727 Programs variable MTRRs
729 This function programs variable MTRRs
731 @param MtrrNumber Index of MTRR to program.
732 @param BaseAddress Base address of memory region.
733 @param Length Length of memory region.
734 @param MemoryCacheType Memory type to set.
735 @param MtrrValidAddressMask The valid address mask for MTRR
739 ProgramVariableMtrr (
741 IN PHYSICAL_ADDRESS BaseAddress
,
743 IN UINT64 MemoryCacheType
,
744 IN UINT64 MtrrValidAddressMask
750 Cr4
= PreMtrrChange ();
753 // MTRR Physical Base
755 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
756 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
759 // MTRR Physical Mask
761 TempQword
= ~(Length
- 1);
763 (UINT32
) (MtrrNumber
+ 1),
764 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
767 PostMtrrChange (Cr4
);
772 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
774 @param MtrrType MTRR memory type
776 @return The enum item in MTRR_MEMORY_CACHE_TYPE
779 MTRR_MEMORY_CACHE_TYPE
780 GetMemoryCacheTypeFromMtrrType (
785 case MTRR_CACHE_UNCACHEABLE
:
786 return CacheUncacheable
;
787 case MTRR_CACHE_WRITE_COMBINING
:
788 return CacheWriteCombining
;
789 case MTRR_CACHE_WRITE_THROUGH
:
790 return CacheWriteThrough
;
791 case MTRR_CACHE_WRITE_PROTECTED
:
792 return CacheWriteProtected
;
793 case MTRR_CACHE_WRITE_BACK
:
794 return CacheWriteBack
;
797 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
798 // no mtrr covers the range
800 return CacheUncacheable
;
805 Initializes the valid bits mask and valid address mask for MTRRs.
807 This function initializes the valid bits mask and valid address mask for MTRRs.
809 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
810 @param MtrrValidAddressMask The valid address mask for the MTRR
814 MtrrLibInitializeMtrrMask (
815 OUT UINT64
*MtrrValidBitsMask
,
816 OUT UINT64
*MtrrValidAddressMask
820 UINT8 PhysicalAddressBits
;
822 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
824 if (RegEax
>= 0x80000008) {
825 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
827 PhysicalAddressBits
= (UINT8
) RegEax
;
829 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
830 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
832 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
833 *MtrrValidAddressMask
= 0xFFFFFFFF;
839 Determing the real attribute of a memory range.
841 This function is to arbitrate the real attribute of the memory when
842 there are 2 MTRR covers the same memory range. For further details,
843 please refer the IA32 Software Developer's Manual, Volume 3,
846 @param MtrrType1 the first kind of Memory type
847 @param MtrrType2 the second kind of memory type
858 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
860 case MTRR_CACHE_UNCACHEABLE
:
861 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
863 case MTRR_CACHE_WRITE_COMBINING
:
865 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
866 MtrrType2
==MTRR_CACHE_UNCACHEABLE
868 MtrrType
= MtrrType2
;
871 case MTRR_CACHE_WRITE_THROUGH
:
873 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
874 MtrrType2
==MTRR_CACHE_WRITE_BACK
876 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
877 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
878 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
881 case MTRR_CACHE_WRITE_PROTECTED
:
882 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
883 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
884 MtrrType
= MtrrType2
;
887 case MTRR_CACHE_WRITE_BACK
:
889 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
890 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
891 MtrrType2
== MTRR_CACHE_WRITE_BACK
893 MtrrType
= MtrrType2
;
896 case MTRR_CACHE_INVALID_TYPE
:
897 MtrrType
= MtrrType2
;
903 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
904 MtrrType
= MtrrType1
;
911 This function attempts to set the attributes for a memory range.
913 @param BaseAddress The physical address that is the start
914 address of a memory region.
915 @param Length The size in bytes of the memory region.
916 @param Attributes The bit mask of attributes to set for the
919 @retval RETURN_SUCCESS The attributes were set for the memory
921 @retval RETURN_INVALID_PARAMETER Length is zero.
922 @retval RETURN_UNSUPPORTED The processor does not support one or
923 more bytes of the memory resource range
924 specified by BaseAddress and Length.
925 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
926 for the memory resource range specified
927 by BaseAddress and Length.
928 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
929 range specified by BaseAddress and Length
931 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
932 modify the attributes of the memory
938 MtrrSetMemoryAttribute (
939 IN PHYSICAL_ADDRESS BaseAddress
,
941 IN MTRR_MEMORY_CACHE_TYPE Attribute
945 RETURN_STATUS Status
;
952 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
954 UINT64 MtrrValidBitsMask
;
955 UINT64 MtrrValidAddressMask
;
957 BOOLEAN OverwriteExistingMtrr
;
958 UINT32 FirmwareVariableMtrrCount
;
959 UINT32 VariableMtrrEnd
;
961 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
963 if (!IsMtrrSupported ()) {
964 Status
= RETURN_UNSUPPORTED
;
968 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
969 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
971 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
974 MemoryType
= (UINT64
)Attribute
;
975 OverwriteExistingMtrr
= FALSE
;
978 // Check for an invalid parameter
981 Status
= RETURN_INVALID_PARAMETER
;
986 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
987 (Length
& ~MtrrValidAddressMask
) != 0
989 Status
= RETURN_UNSUPPORTED
;
994 // Check if Fixed MTRR
996 Status
= RETURN_SUCCESS
;
997 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
998 Cr4
= PreMtrrChange ();
999 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
1000 PostMtrrChange (Cr4
);
1001 if (RETURN_ERROR (Status
)) {
1008 // A Length of 0 can only make sense for fixed MTTR ranges.
1009 // Since we just handled the fixed MTRRs, we can skip the
1010 // variable MTRR section.
1016 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1017 // we can set the base to 0 to save variable MTRRs.
1019 if (BaseAddress
== BASE_1MB
) {
1025 // Check for overlap
1027 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1028 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1030 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1031 if (RETURN_ERROR (Status
)) {
1037 // Combined successfully, invalidate the now-unused MTRRs
1039 InvalidateMtrr(VariableMtrr
);
1040 Status
= RETURN_SUCCESS
;
1046 // The memory type is the same with the type specified by
1047 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1049 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryType ())) {
1051 // Invalidate the now-unused MTRRs
1053 InvalidateMtrr(VariableMtrr
);
1057 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1059 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1060 Status
= RETURN_OUT_OF_RESOURCES
;
1065 // Invalidate the now-unused MTRRs
1067 InvalidateMtrr(VariableMtrr
);
1070 // Find first unused MTRR
1072 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1073 MsrNum
< VariableMtrrEnd
;
1076 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1081 if (BaseAddress
!= 0) {
1084 // Calculate the alignment of the base address.
1086 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1088 if (Alignment
> Length
) {
1095 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1096 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1101 ProgramVariableMtrr (
1106 MtrrValidAddressMask
1108 BaseAddress
+= Alignment
;
1109 Length
-= Alignment
;
1120 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1125 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1126 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1131 ProgramVariableMtrr (
1136 MtrrValidAddressMask
1138 BaseAddress
+= Length
;
1139 TempQword
= Length
- TempQword
;
1140 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1147 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1148 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1153 Length
= Power2MaxMemory (TempQword
);
1155 BaseAddress
-= Length
;
1158 ProgramVariableMtrr (
1163 MtrrValidAddressMask
1167 BaseAddress
+= Length
;
1169 TempQword
-= Length
;
1171 } while (TempQword
> 0);
1174 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1175 if (!RETURN_ERROR (Status
)) {
1176 MtrrDebugPrintAllMtrrs ();
1184 This function will get the memory cache type of the specific address.
1186 This function is mainly for debug purpose.
1188 @param Address The specific address
1190 @return Memory cache type of the sepcific address
1193 MTRR_MEMORY_CACHE_TYPE
1195 MtrrGetMemoryAttribute (
1196 IN PHYSICAL_ADDRESS Address
1203 UINT64 TempMtrrType
;
1204 MTRR_MEMORY_CACHE_TYPE CacheType
;
1205 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1206 UINT64 MtrrValidBitsMask
;
1207 UINT64 MtrrValidAddressMask
;
1208 UINTN VariableMtrrCount
;
1210 if (!IsMtrrSupported ()) {
1211 return CacheUncacheable
;
1215 // Check if MTRR is enabled, if not, return UC as attribute
1217 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1218 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1220 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1221 return CacheUncacheable
;
1225 // If address is less than 1M, then try to go through the fixed MTRR
1227 if (Address
< BASE_1MB
) {
1228 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1230 // Go through the fixed MTRR
1232 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1233 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1235 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1236 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1240 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1241 mMtrrLibFixedMtrrTable
[Index
].Length
;
1242 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1243 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1244 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1249 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1250 MtrrGetMemoryAttributeInVariableMtrr(
1252 MtrrValidAddressMask
,
1257 // Go through the variable MTRR
1259 VariableMtrrCount
= GetVariableMtrrCount ();
1260 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1262 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1263 if (VariableMtrr
[Index
].Valid
) {
1264 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1265 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1266 TempMtrrType
= VariableMtrr
[Index
].Type
;
1267 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1271 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1278 This function will get the raw value in variable MTRRs
1280 @param VariableSettings A buffer to hold variable MTRRs content.
1282 @return The VariableSettings input pointer
1285 MTRR_VARIABLE_SETTINGS
*
1287 MtrrGetVariableMtrr (
1288 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1292 UINT32 VariableMtrrCount
;
1294 if (!IsMtrrSupported ()) {
1295 return VariableSettings
;
1298 VariableMtrrCount
= GetVariableMtrrCount ();
1299 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1301 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1302 VariableSettings
->Mtrr
[Index
].Base
=
1303 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1304 VariableSettings
->Mtrr
[Index
].Mask
=
1305 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1308 return VariableSettings
;
1313 Worker function setting variable MTRRs
1315 @param VariableSettings A buffer to hold variable MTRRs content.
1319 MtrrSetVariableMtrrWorker (
1320 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1324 UINT32 VariableMtrrCount
;
1326 VariableMtrrCount
= GetVariableMtrrCount ();
1327 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1329 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1331 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1332 VariableSettings
->Mtrr
[Index
].Base
1335 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1336 VariableSettings
->Mtrr
[Index
].Mask
1343 This function sets variable MTRRs
1345 @param VariableSettings A buffer to hold variable MTRRs content.
1347 @return The pointer of VariableSettings
1350 MTRR_VARIABLE_SETTINGS
*
1352 MtrrSetVariableMtrr (
1353 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1358 if (!IsMtrrSupported ()) {
1359 return VariableSettings
;
1362 Cr4
= PreMtrrChange ();
1363 MtrrSetVariableMtrrWorker (VariableSettings
);
1364 PostMtrrChange (Cr4
);
1365 return VariableSettings
;
1370 This function gets the content in fixed MTRRs
1372 @param FixedSettings A buffer to hold fixed Mtrrs content.
1374 @retval The pointer of FixedSettings
1377 MTRR_FIXED_SETTINGS
*
1380 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1385 if (!IsMtrrSupported ()) {
1386 return FixedSettings
;
1389 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1390 FixedSettings
->Mtrr
[Index
] =
1391 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1394 return FixedSettings
;
1398 Worker function setting fixed MTRRs
1400 @param FixedSettings A buffer to hold fixed Mtrrs content.
1404 MtrrSetFixedMtrrWorker (
1405 IN MTRR_FIXED_SETTINGS
*FixedSettings
1410 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1412 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1413 FixedSettings
->Mtrr
[Index
]
1420 This function sets fixed MTRRs
1422 @param FixedSettings A buffer to hold fixed Mtrrs content.
1424 @retval The pointer of FixedSettings
1427 MTRR_FIXED_SETTINGS
*
1430 IN MTRR_FIXED_SETTINGS
*FixedSettings
1435 if (!IsMtrrSupported ()) {
1436 return FixedSettings
;
1439 Cr4
= PreMtrrChange ();
1440 MtrrSetFixedMtrrWorker (FixedSettings
);
1441 PostMtrrChange (Cr4
);
1443 return FixedSettings
;
1448 This function gets the content in all MTRRs (variable and fixed)
1450 @param MtrrSetting A buffer to hold all Mtrrs content.
1452 @retval the pointer of MtrrSetting
1458 OUT MTRR_SETTINGS
*MtrrSetting
1461 if (!IsMtrrSupported ()) {
1468 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1471 // Get variable MTRRs
1473 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1476 // Get MTRR_DEF_TYPE value
1478 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1485 This function sets all MTRRs (variable and fixed)
1487 @param MtrrSetting A buffer holding all MTRRs content.
1489 @retval The pointer of MtrrSetting
1495 IN MTRR_SETTINGS
*MtrrSetting
1500 if (!IsMtrrSupported ()) {
1504 Cr4
= PreMtrrChange ();
1509 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1512 // Set variable MTRRs
1514 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1517 // Set MTRR_DEF_TYPE value
1519 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1521 PostMtrrChangeEnableCache (Cr4
);
1527 This function prints all MTRRs for debugging.
1531 MtrrDebugPrintAllMtrrs (
1536 MTRR_SETTINGS MtrrSettings
;
1539 UINTN VariableMtrrCount
;
1547 UINT64 NoRangeLimit
;
1550 UINTN PreviousMemoryType
;
1553 if (!IsMtrrSupported ()) {
1557 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1558 DEBUG((DEBUG_CACHE
, "=============\n"));
1560 MtrrGetAllMtrrs (&MtrrSettings
);
1561 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1562 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1563 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1566 VariableMtrrCount
= GetVariableMtrrCount ();
1567 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1568 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1570 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1571 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1574 DEBUG((DEBUG_CACHE
, "\n"));
1575 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1576 DEBUG((DEBUG_CACHE
, "====================================\n"));
1579 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1580 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1581 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1582 for (Index1
= 0; Index1
< 8; Index1
++) {
1583 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1584 if (MemoryType
> CacheWriteBack
) {
1585 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1587 if (MemoryType
!= PreviousMemoryType
) {
1588 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1589 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1591 PreviousMemoryType
= MemoryType
;
1592 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1594 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1597 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1599 VariableMtrrCount
= GetVariableMtrrCount ();
1602 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1604 MemoryType
= MtrrGetMemoryAttribute (Base
);
1605 if (MemoryType
> CacheWriteBack
) {
1606 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1609 if (MemoryType
!= PreviousMemoryType
) {
1610 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1611 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1613 PreviousMemoryType
= MemoryType
;
1614 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1617 RangeBase
= BASE_1MB
;
1618 NoRangeBase
= BASE_1MB
;
1620 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1621 if (RegEax
>= 0x80000008) {
1622 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1623 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1626 NoRangeLimit
= Limit
;
1628 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1629 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1631 // If mask is not valid, then do not display range
1635 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1636 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1638 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1642 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1643 RangeBase
= MtrrBase
;
1645 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1646 RangeBase
= MtrrLimit
+ 1;
1648 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1649 RangeLimit
= MtrrBase
- 1;
1651 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1652 RangeLimit
= MtrrLimit
;
1655 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1656 NoRangeBase
= MtrrLimit
+ 1;
1658 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1659 NoRangeLimit
= MtrrBase
- 1;
1664 Base
= RangeLimit
+ 1;
1666 Base
= NoRangeLimit
+ 1;
1669 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1674 Checks if MTRR is supported.
1676 @retval TRUE MTRR is supported.
1677 @retval FALSE MTRR is not supported.
1690 // Check CPUID(1).EDX[12] for MTRR capability
1692 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1693 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1698 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1699 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1700 // exist, return false.
1702 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1703 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {