4 Copyright (c) 2008 - 2010, 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 FIXED_MTRR MtrrLibFixedMtrrTable
[] = {
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 Returns the variable MTRR count for the CPU.
87 @return Variable MTRR count
92 GetVariableMtrrCount (
96 if (!IsMtrrSupported ()) {
100 return (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
104 Returns the firmware usable variable MTRR count for the CPU.
106 @return Firmware usable variable MTRR count
111 GetFirmwareVariableMtrrCount (
115 UINT32 VariableMtrrCount
;
117 VariableMtrrCount
= GetVariableMtrrCount ();
118 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
122 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
126 Returns the default MTRR cache type for the system.
128 @return MTRR default type
132 GetMtrrDefaultMemoryType (
136 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
141 Preparation before programming MTRR.
143 This function will do some preparation for programming MTRRs:
144 disable cache, invalid cache and disable MTRR caching functionality
146 @return CR4 value before changing.
157 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
162 // Save original CR4 value and clear PGE flag (Bit 7)
164 Value
= AsmReadCr4 ();
165 AsmWriteCr4 (Value
& (~BIT7
));
175 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
178 // Return original CR4 value
185 Cleaning up after programming MTRRs.
187 This function will do some clean up after programming MTRRs:
188 enable MTRR caching functionality, and enable cache
190 @param Cr4 CR4 value to restore
201 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
209 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
214 // Restore original CR4 value
221 Programs fixed MTRRs registers.
223 @param MemoryCacheType The memory type to set.
224 @param Base The base address of memory range.
225 @param Length The length of memory range.
227 @retval RETURN_SUCCESS The cache type was updated successfully
228 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
234 IN UINT64 MemoryCacheType
,
236 IN OUT UINT64
*Length
249 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
250 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
253 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
254 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
262 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
263 return RETURN_UNSUPPORTED
;
267 // We found the fixed MTRR to be programmed
269 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
272 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
273 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
280 if (ByteShift
== 8) {
281 return RETURN_UNSUPPORTED
;
286 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
289 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
290 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
291 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
292 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
295 if (ByteShift
< 8 && (*Length
!= 0)) {
296 return RETURN_UNSUPPORTED
;
300 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
301 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
302 return RETURN_SUCCESS
;
307 Get the attribute of variable MTRRs.
309 This function shadows the content of variable MTRRs into an
310 internal array: VariableMtrr.
312 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
313 @param MtrrValidAddressMask The valid address mask for MTRR
314 @param VariableMtrr The array to shadow variable MTRRs content
316 @return The return value of this paramter indicates the
317 number of MTRRs which has been used.
322 MtrrGetMemoryAttributeInVariableMtrr (
323 IN UINT64 MtrrValidBitsMask
,
324 IN UINT64 MtrrValidAddressMask
,
325 OUT VARIABLE_MTRR
*VariableMtrr
331 UINT32 FirmwareVariableMtrrCount
;
332 UINT32 VariableMtrrEnd
;
334 if (!IsMtrrSupported ()) {
338 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
339 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
341 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
344 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
346 (MsrNum
< VariableMtrrEnd
) &&
347 (Index
< FirmwareVariableMtrrCount
)
351 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
352 VariableMtrr
[Index
].Msr
= MsrNum
;
353 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
354 MtrrValidAddressMask
);
355 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
356 MtrrValidAddressMask
)
360 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
361 VariableMtrr
[Index
].Valid
= TRUE
;
362 VariableMtrr
[Index
].Used
= TRUE
;
363 UsedMtrr
= UsedMtrr
+ 1;
372 Checks overlap between given memory range and MTRRs.
374 @param Start The start address of memory range.
375 @param End The end address of memory range.
376 @param VariableMtrr The array to shadow variable MTRRs content
378 @retval TRUE Overlap exists.
379 @retval FALSE No overlap.
383 CheckMemoryAttributeOverlap (
384 IN PHYSICAL_ADDRESS Start
,
385 IN PHYSICAL_ADDRESS End
,
386 IN VARIABLE_MTRR
*VariableMtrr
391 for (Index
= 0; Index
< 6; Index
++) {
393 VariableMtrr
[Index
].Valid
&&
395 (Start
> (VariableMtrr
[Index
].BaseAddress
+
396 VariableMtrr
[Index
].Length
- 1)
398 (End
< VariableMtrr
[Index
].BaseAddress
)
410 Marks a variable MTRR as non-valid.
412 @param Index The index of the array VariableMtrr to be invalidated
413 @param VariableMtrr The array to shadow variable MTRRs content
414 @param UsedMtrr The number of MTRRs which has already been used
418 InvalidateShadowMtrr (
420 IN VARIABLE_MTRR
*VariableMtrr
,
424 VariableMtrr
[Index
].Valid
= FALSE
;
425 *UsedMtrr
= *UsedMtrr
- 1;
430 Combine memory attributes.
432 If overlap exists between given memory range and MTRRs, try to combine them.
434 @param Attributes The memory type to set.
435 @param Base The base address of memory range.
436 @param Length The length of memory range.
437 @param VariableMtrr The array to shadow variable MTRRs content
438 @param UsedMtrr The number of MTRRs which has already been used
439 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
441 @retval EFI_SUCCESS Memory region successfully combined.
442 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
446 CombineMemoryAttribute (
447 IN UINT64 Attributes
,
449 IN OUT UINT64
*Length
,
450 IN VARIABLE_MTRR
*VariableMtrr
,
451 IN OUT UINT32
*UsedMtrr
,
452 OUT BOOLEAN
*OverwriteExistingMtrr
460 UINT32 FirmwareVariableMtrrCount
;
462 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
464 *OverwriteExistingMtrr
= FALSE
;
465 EndAddress
= *Base
+*Length
- 1;
467 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
469 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
471 !VariableMtrr
[Index
].Valid
||
474 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
481 // Combine same attribute MTRR range
483 if (Attributes
== VariableMtrr
[Index
].Type
) {
485 // if the Mtrr range contain the request range, return RETURN_SUCCESS
487 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
489 return RETURN_SUCCESS
;
492 // invalid this MTRR, and program the combine range
495 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
497 VariableMtrr
[Index
].BaseAddress
;
498 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
501 // Record the MTRR usage status in VariableMtrr array.
503 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
504 *Base
= CombineStart
;
505 *Length
= CombineEnd
- CombineStart
+ 1;
506 EndAddress
= CombineEnd
;
507 *OverwriteExistingMtrr
= TRUE
;
511 // The cache type is different, but the range is convered by one MTRR
513 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
514 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
520 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
521 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
522 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
523 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
524 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
525 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
527 *OverwriteExistingMtrr
= TRUE
;
531 // Other type memory overlap is invalid
533 return RETURN_ACCESS_DENIED
;
536 return RETURN_SUCCESS
;
541 Calculate the maximum value which is a power of 2, but less the MemoryLength.
543 @param MemoryLength The number to pass in.
544 @return The maximum value which is align to power of 2 and less the MemoryLength
549 IN UINT64 MemoryLength
554 if (RShiftU64 (MemoryLength
, 32) != 0) {
556 (UINT64
) GetPowerOfTwo32 (
557 (UINT32
) RShiftU64 (MemoryLength
, 32)
562 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
570 Check the direction to program variable MTRRs.
572 This function determines which direction of programming the variable
573 MTRRs will use fewer MTRRs.
575 @param Input Length of Memory to program MTRR
576 @param MtrrNumber Pointer to the number of necessary MTRRs
578 @retval TRUE Positive direction is better.
579 FALSE Negtive direction is better.
597 TempQword
-= Power2MaxMemory (TempQword
);
599 } while (TempQword
!= 0);
601 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
604 TempQword
-= Power2MaxMemory (TempQword
);
606 } while (TempQword
!= 0);
608 if (Positive
<= Subtractive
) {
609 *MtrrNumber
= Positive
;
612 *MtrrNumber
= Subtractive
;
618 Invalid variable MTRRs according to the value in the shadow array.
620 This function programs MTRRs according to the values specified
623 @param VariableMtrr The array to shadow variable MTRRs content
628 IN VARIABLE_MTRR
*VariableMtrr
633 UINTN VariableMtrrCount
;
635 Cr4
= PreMtrrChange ();
637 VariableMtrrCount
= GetVariableMtrrCount ();
638 while (Index
< VariableMtrrCount
) {
639 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
640 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
641 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
642 VariableMtrr
[Index
].Used
= FALSE
;
646 PostMtrrChange (Cr4
);
651 Programs variable MTRRs
653 This function programs variable MTRRs
655 @param MtrrNumber Index of MTRR to program.
656 @param BaseAddress Base address of memory region.
657 @param Length Length of memory region.
658 @param MemoryCacheType Memory type to set.
659 @param MtrrValidAddressMask The valid address mask for MTRR
663 ProgramVariableMtrr (
665 IN PHYSICAL_ADDRESS BaseAddress
,
667 IN UINT64 MemoryCacheType
,
668 IN UINT64 MtrrValidAddressMask
674 Cr4
= PreMtrrChange ();
677 // MTRR Physical Base
679 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
680 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
683 // MTRR Physical Mask
685 TempQword
= ~(Length
- 1);
687 (UINT32
) (MtrrNumber
+ 1),
688 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
691 PostMtrrChange (Cr4
);
696 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
698 @param MtrrType MTRR memory type
700 @return The enum item in MTRR_MEMORY_CACHE_TYPE
703 MTRR_MEMORY_CACHE_TYPE
704 GetMemoryCacheTypeFromMtrrType (
709 case MTRR_CACHE_UNCACHEABLE
:
710 return CacheUncacheable
;
711 case MTRR_CACHE_WRITE_COMBINING
:
712 return CacheWriteCombining
;
713 case MTRR_CACHE_WRITE_THROUGH
:
714 return CacheWriteThrough
;
715 case MTRR_CACHE_WRITE_PROTECTED
:
716 return CacheWriteProtected
;
717 case MTRR_CACHE_WRITE_BACK
:
718 return CacheWriteBack
;
721 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
722 // no mtrr covers the range
724 return CacheUncacheable
;
729 Initializes the valid bits mask and valid address mask for MTRRs.
731 This function initializes the valid bits mask and valid address mask for MTRRs.
733 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
734 @param MtrrValidAddressMask The valid address mask for the MTRR
738 MtrrLibInitializeMtrrMask (
739 OUT UINT64
*MtrrValidBitsMask
,
740 OUT UINT64
*MtrrValidAddressMask
744 UINT8 PhysicalAddressBits
;
746 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
748 if (RegEax
>= 0x80000008) {
749 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
751 PhysicalAddressBits
= (UINT8
) RegEax
;
753 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
754 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
756 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
757 *MtrrValidAddressMask
= 0xFFFFFFFF;
763 Determing the real attribute of a memory range.
765 This function is to arbitrate the real attribute of the memory when
766 there are 2 MTRR covers the same memory range. For further details,
767 please refer the IA32 Software Developer's Manual, Volume 3,
770 @param MtrrType1 the first kind of Memory type
771 @param MtrrType2 the second kind of memory type
782 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
784 case MTRR_CACHE_UNCACHEABLE
:
785 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
787 case MTRR_CACHE_WRITE_COMBINING
:
789 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
790 MtrrType2
==MTRR_CACHE_UNCACHEABLE
792 MtrrType
= MtrrType2
;
795 case MTRR_CACHE_WRITE_THROUGH
:
797 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
798 MtrrType2
==MTRR_CACHE_WRITE_BACK
800 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
801 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
802 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
805 case MTRR_CACHE_WRITE_PROTECTED
:
806 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
807 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
808 MtrrType
= MtrrType2
;
811 case MTRR_CACHE_WRITE_BACK
:
813 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
814 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
815 MtrrType2
== MTRR_CACHE_WRITE_BACK
817 MtrrType
= MtrrType2
;
820 case MTRR_CACHE_INVALID_TYPE
:
821 MtrrType
= MtrrType2
;
827 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
828 MtrrType
= MtrrType1
;
835 This function attempts to set the attributes for a memory range.
837 @param BaseAddress The physical address that is the start
838 address of a memory region.
839 @param Length The size in bytes of the memory region.
840 @param Attributes The bit mask of attributes to set for the
843 @retval RETURN_SUCCESS The attributes were set for the memory
845 @retval RETURN_INVALID_PARAMETER Length is zero.
846 @retval RETURN_UNSUPPORTED The processor does not support one or
847 more bytes of the memory resource range
848 specified by BaseAddress and Length.
849 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
850 for the memory resource range specified
851 by BaseAddress and Length.
852 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
853 range specified by BaseAddress and Length
855 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
856 modify the attributes of the memory
862 MtrrSetMemoryAttribute (
863 IN PHYSICAL_ADDRESS BaseAddress
,
865 IN MTRR_MEMORY_CACHE_TYPE Attribute
869 RETURN_STATUS Status
;
876 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
878 UINT64 MtrrValidBitsMask
;
879 UINT64 MtrrValidAddressMask
;
881 BOOLEAN OverwriteExistingMtrr
;
882 UINT32 FirmwareVariableMtrrCount
;
883 UINT32 VariableMtrrEnd
;
885 if (!IsMtrrSupported ()) {
886 return RETURN_UNSUPPORTED
;
889 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
890 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
892 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
895 MemoryType
= (UINT64
)Attribute
;
896 OverwriteExistingMtrr
= FALSE
;
899 // Check for an invalid parameter
902 return RETURN_INVALID_PARAMETER
;
906 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
907 (Length
&~MtrrValidAddressMask
) != 0
909 return RETURN_UNSUPPORTED
;
913 // Check if Fixed MTRR
915 Status
= RETURN_SUCCESS
;
916 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
917 Cr4
= PreMtrrChange ();
918 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
919 PostMtrrChange (Cr4
);
920 if (RETURN_ERROR (Status
)) {
927 // A Length of 0 can only make sense for fixed MTTR ranges.
928 // Since we just handled the fixed MTRRs, we can skip the
929 // variable MTRR section.
935 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
936 // we can set the bade to 0 to save variable MTRRs.
938 if (BaseAddress
== BASE_1MB
) {
944 // Check memory base address alignment
946 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
947 if (Remainder
!= 0) {
948 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
949 if (Remainder
!= 0) {
950 Status
= RETURN_UNSUPPORTED
;
958 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
959 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
961 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
962 if (RETURN_ERROR (Status
)) {
968 // Combined successfully
970 Status
= RETURN_SUCCESS
;
976 // Program Variable MTRRs
978 // Avoid hardcode here and read data dynamically
980 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
981 Status
= RETURN_OUT_OF_RESOURCES
;
986 // The memory type is the same with the type specified by
987 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
989 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
991 // Invalidate the now-unused MTRRs
993 InvalidateMtrr(VariableMtrr
);
1000 if (TempQword
== Power2MaxMemory (TempQword
)) {
1002 // Invalidate the now-unused MTRRs
1004 InvalidateMtrr(VariableMtrr
);
1007 // Find first unused MTRR
1009 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1010 MsrNum
< VariableMtrrEnd
;
1013 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1018 ProgramVariableMtrr (
1023 MtrrValidAddressMask
1027 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1029 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1030 Status
= RETURN_OUT_OF_RESOURCES
;
1035 // Invalidate the now-unused MTRRs
1037 InvalidateMtrr(VariableMtrr
);
1040 // Find first unused MTRR
1042 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1043 MsrNum
< VariableMtrrEnd
;
1046 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1052 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1053 ProgramVariableMtrr (
1058 MtrrValidAddressMask
1060 BaseAddress
+= Length
;
1061 TempQword
= Length
- TempQword
;
1062 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1069 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1070 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1075 Length
= Power2MaxMemory (TempQword
);
1077 BaseAddress
-= Length
;
1080 ProgramVariableMtrr (
1085 MtrrValidAddressMask
1089 BaseAddress
+= Length
;
1091 TempQword
-= Length
;
1093 } while (TempQword
> 0);
1103 This function will get the memory cache type of the specific address.
1105 This function is mainly for debug purpose.
1107 @param Address The specific address
1109 @return Memory cache type of the sepcific address
1112 MTRR_MEMORY_CACHE_TYPE
1114 MtrrGetMemoryAttribute (
1115 IN PHYSICAL_ADDRESS Address
1122 UINT64 TempMtrrType
;
1123 MTRR_MEMORY_CACHE_TYPE CacheType
;
1124 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1125 UINT64 MtrrValidBitsMask
;
1126 UINT64 MtrrValidAddressMask
;
1127 UINTN VariableMtrrCount
;
1129 if (!IsMtrrSupported ()) {
1130 return CacheUncacheable
;
1134 // Check if MTRR is enabled, if not, return UC as attribute
1136 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1137 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1139 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1140 return CacheUncacheable
;
1144 // If address is less than 1M, then try to go through the fixed MTRR
1146 if (Address
< BASE_1MB
) {
1147 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1149 // Go through the fixed MTRR
1151 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1152 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1154 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1155 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1159 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1160 MtrrLibFixedMtrrTable
[Index
].Length
;
1161 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1162 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1163 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1168 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1169 MtrrGetMemoryAttributeInVariableMtrr(
1171 MtrrValidAddressMask
,
1176 // Go through the variable MTRR
1178 VariableMtrrCount
= GetVariableMtrrCount ();
1179 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1181 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1182 if (VariableMtrr
[Index
].Valid
) {
1183 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1184 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1185 TempMtrrType
= VariableMtrr
[Index
].Type
;
1186 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1190 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1197 This function will get the raw value in variable MTRRs
1199 @param VariableSettings A buffer to hold variable MTRRs content.
1201 @return The VariableSettings input pointer
1204 MTRR_VARIABLE_SETTINGS
*
1206 MtrrGetVariableMtrr (
1207 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1211 UINT32 VariableMtrrCount
;
1213 if (!IsMtrrSupported ()) {
1214 return VariableSettings
;
1217 VariableMtrrCount
= GetVariableMtrrCount ();
1218 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1220 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1221 VariableSettings
->Mtrr
[Index
].Base
=
1222 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1223 VariableSettings
->Mtrr
[Index
].Mask
=
1224 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1227 return VariableSettings
;
1232 Worker function setting variable MTRRs
1234 @param VariableSettings A buffer to hold variable MTRRs content.
1238 MtrrSetVariableMtrrWorker (
1239 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1243 UINT32 VariableMtrrCount
;
1245 VariableMtrrCount
= GetVariableMtrrCount ();
1246 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1248 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1250 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1251 VariableSettings
->Mtrr
[Index
].Base
1254 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1255 VariableSettings
->Mtrr
[Index
].Mask
1262 This function sets variable MTRRs
1264 @param VariableSettings A buffer to hold variable MTRRs content.
1266 @return The pointer of VariableSettings
1269 MTRR_VARIABLE_SETTINGS
*
1271 MtrrSetVariableMtrr (
1272 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1277 if (!IsMtrrSupported ()) {
1278 return VariableSettings
;
1281 Cr4
= PreMtrrChange ();
1282 MtrrSetVariableMtrrWorker (VariableSettings
);
1283 PostMtrrChange (Cr4
);
1284 return VariableSettings
;
1289 This function gets the content in fixed MTRRs
1291 @param FixedSettings A buffer to hold fixed Mtrrs content.
1293 @retval The pointer of FixedSettings
1296 MTRR_FIXED_SETTINGS
*
1299 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1304 if (!IsMtrrSupported ()) {
1305 return FixedSettings
;
1308 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1309 FixedSettings
->Mtrr
[Index
] =
1310 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1313 return FixedSettings
;
1317 Worker function setting fixed MTRRs
1319 @param FixedSettings A buffer to hold fixed Mtrrs content.
1323 MtrrSetFixedMtrrWorker (
1324 IN MTRR_FIXED_SETTINGS
*FixedSettings
1329 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1331 MtrrLibFixedMtrrTable
[Index
].Msr
,
1332 FixedSettings
->Mtrr
[Index
]
1339 This function sets fixed MTRRs
1341 @param FixedSettings A buffer to hold fixed Mtrrs content.
1343 @retval The pointer of FixedSettings
1346 MTRR_FIXED_SETTINGS
*
1349 IN MTRR_FIXED_SETTINGS
*FixedSettings
1354 if (!IsMtrrSupported ()) {
1355 return FixedSettings
;
1358 Cr4
= PreMtrrChange ();
1359 MtrrSetFixedMtrrWorker (FixedSettings
);
1360 PostMtrrChange (Cr4
);
1362 return FixedSettings
;
1367 This function gets the content in all MTRRs (variable and fixed)
1369 @param MtrrSetting A buffer to hold all Mtrrs content.
1371 @retval the pointer of MtrrSetting
1377 OUT MTRR_SETTINGS
*MtrrSetting
1380 if (!IsMtrrSupported ()) {
1387 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1390 // Get variable MTRRs
1392 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1395 // Get MTRR_DEF_TYPE value
1397 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1404 This function sets all MTRRs (variable and fixed)
1406 @param MtrrSetting A buffer holding all MTRRs content.
1408 @retval The pointer of MtrrSetting
1414 IN MTRR_SETTINGS
*MtrrSetting
1419 if (!IsMtrrSupported ()) {
1423 Cr4
= PreMtrrChange ();
1428 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1431 // Set variable MTRRs
1433 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1436 // Set MTRR_DEF_TYPE value
1438 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1440 PostMtrrChange (Cr4
);
1447 This function prints all MTRRs for debugging.
1451 MtrrDebugPrintAllMtrrs (
1457 MTRR_SETTINGS MtrrSettings
;
1459 UINTN VariableMtrrCount
;
1461 if (!IsMtrrSupported ()) {
1465 MtrrGetAllMtrrs (&MtrrSettings
);
1466 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1467 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1469 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1471 MtrrSettings
.Fixed
.Mtrr
[Index
]
1475 VariableMtrrCount
= GetVariableMtrrCount ();
1476 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1478 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1480 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1481 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1489 Checks if MTRR is supported.
1491 @retval TRUE MTRR is supported.
1492 @retval FALSE MTRR is not supported.
1505 // Check CPUID(1).EDX[12] for MTRR capability
1507 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1508 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1513 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1514 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1515 // exist, return false.
1517 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1518 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {