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 UINT32 VariableMtrrCount
;
98 if (!IsMtrrSupported ()) {
102 VariableMtrrCount
= (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
103 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
105 return VariableMtrrCount
;
109 Returns the firmware usable variable MTRR count for the CPU.
111 @return Firmware usable variable MTRR count
116 GetFirmwareVariableMtrrCount (
120 UINT32 VariableMtrrCount
;
122 VariableMtrrCount
= GetVariableMtrrCount ();
123 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
127 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
131 Returns the default MTRR cache type for the system.
133 @return MTRR default type
137 GetMtrrDefaultMemoryType (
141 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
146 Preparation before programming MTRR.
148 This function will do some preparation for programming MTRRs:
149 disable cache, invalid cache and disable MTRR caching functionality
151 @return CR4 value before changing.
162 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
167 // Save original CR4 value and clear PGE flag (Bit 7)
169 Value
= AsmReadCr4 ();
170 AsmWriteCr4 (Value
& (~BIT7
));
180 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
183 // Return original CR4 value
190 Cleaning up after programming MTRRs.
192 This function will do some clean up after programming MTRRs:
193 enable MTRR caching functionality, and enable cache
195 @param Cr4 CR4 value to restore
206 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
214 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
219 // Restore original CR4 value
226 Programs fixed MTRRs registers.
228 @param MemoryCacheType The memory type to set.
229 @param Base The base address of memory range.
230 @param Length The length of memory range.
232 @retval RETURN_SUCCESS The cache type was updated successfully
233 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
239 IN UINT64 MemoryCacheType
,
241 IN OUT UINT64
*Length
254 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
255 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
258 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
259 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
267 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
268 return RETURN_UNSUPPORTED
;
272 // We found the fixed MTRR to be programmed
274 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
277 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
278 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
285 if (ByteShift
== 8) {
286 return RETURN_UNSUPPORTED
;
291 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
294 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
295 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
296 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
297 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
300 if (ByteShift
< 8 && (*Length
!= 0)) {
301 return RETURN_UNSUPPORTED
;
305 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
306 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
307 return RETURN_SUCCESS
;
312 Get the attribute of variable MTRRs.
314 This function shadows the content of variable MTRRs into an
315 internal array: VariableMtrr.
317 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
318 @param MtrrValidAddressMask The valid address mask for MTRR
319 @param VariableMtrr The array to shadow variable MTRRs content
321 @return The return value of this paramter indicates the
322 number of MTRRs which has been used.
327 MtrrGetMemoryAttributeInVariableMtrr (
328 IN UINT64 MtrrValidBitsMask
,
329 IN UINT64 MtrrValidAddressMask
,
330 OUT VARIABLE_MTRR
*VariableMtrr
336 UINT32 FirmwareVariableMtrrCount
;
337 UINT32 VariableMtrrEnd
;
339 if (!IsMtrrSupported ()) {
343 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
344 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
346 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
349 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
351 (MsrNum
< VariableMtrrEnd
) &&
352 (Index
< FirmwareVariableMtrrCount
)
356 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
357 VariableMtrr
[Index
].Msr
= MsrNum
;
358 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
359 MtrrValidAddressMask
);
360 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
361 MtrrValidAddressMask
)
365 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
366 VariableMtrr
[Index
].Valid
= TRUE
;
367 VariableMtrr
[Index
].Used
= TRUE
;
368 UsedMtrr
= UsedMtrr
+ 1;
377 Checks overlap between given memory range and MTRRs.
379 @param Start The start address of memory range.
380 @param End The end address of memory range.
381 @param VariableMtrr The array to shadow variable MTRRs content
383 @retval TRUE Overlap exists.
384 @retval FALSE No overlap.
388 CheckMemoryAttributeOverlap (
389 IN PHYSICAL_ADDRESS Start
,
390 IN PHYSICAL_ADDRESS End
,
391 IN VARIABLE_MTRR
*VariableMtrr
396 for (Index
= 0; Index
< 6; Index
++) {
398 VariableMtrr
[Index
].Valid
&&
400 (Start
> (VariableMtrr
[Index
].BaseAddress
+
401 VariableMtrr
[Index
].Length
- 1)
403 (End
< VariableMtrr
[Index
].BaseAddress
)
415 Marks a variable MTRR as non-valid.
417 @param Index The index of the array VariableMtrr to be invalidated
418 @param VariableMtrr The array to shadow variable MTRRs content
419 @param UsedMtrr The number of MTRRs which has already been used
423 InvalidateShadowMtrr (
425 IN VARIABLE_MTRR
*VariableMtrr
,
429 VariableMtrr
[Index
].Valid
= FALSE
;
430 *UsedMtrr
= *UsedMtrr
- 1;
435 Combine memory attributes.
437 If overlap exists between given memory range and MTRRs, try to combine them.
439 @param Attributes The memory type to set.
440 @param Base The base address of memory range.
441 @param Length The length of memory range.
442 @param VariableMtrr The array to shadow variable MTRRs content
443 @param UsedMtrr The number of MTRRs which has already been used
444 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
446 @retval EFI_SUCCESS Memory region successfully combined.
447 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
451 CombineMemoryAttribute (
452 IN UINT64 Attributes
,
454 IN OUT UINT64
*Length
,
455 IN VARIABLE_MTRR
*VariableMtrr
,
456 IN OUT UINT32
*UsedMtrr
,
457 OUT BOOLEAN
*OverwriteExistingMtrr
465 UINT32 FirmwareVariableMtrrCount
;
467 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
469 *OverwriteExistingMtrr
= FALSE
;
470 EndAddress
= *Base
+*Length
- 1;
472 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
474 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
476 !VariableMtrr
[Index
].Valid
||
479 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
486 // Combine same attribute MTRR range
488 if (Attributes
== VariableMtrr
[Index
].Type
) {
490 // if the Mtrr range contain the request range, return RETURN_SUCCESS
492 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
494 return RETURN_SUCCESS
;
497 // invalid this MTRR, and program the combine range
500 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
502 VariableMtrr
[Index
].BaseAddress
;
503 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
506 // Record the MTRR usage status in VariableMtrr array.
508 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
509 *Base
= CombineStart
;
510 *Length
= CombineEnd
- CombineStart
+ 1;
511 EndAddress
= CombineEnd
;
512 *OverwriteExistingMtrr
= TRUE
;
516 // The cache type is different, but the range is convered by one MTRR
518 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
519 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
525 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
526 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
527 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
528 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
529 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
530 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
532 *OverwriteExistingMtrr
= TRUE
;
536 // Other type memory overlap is invalid
538 return RETURN_ACCESS_DENIED
;
541 return RETURN_SUCCESS
;
546 Calculate the maximum value which is a power of 2, but less the MemoryLength.
548 @param MemoryLength The number to pass in.
549 @return The maximum value which is align to power of 2 and less the MemoryLength
554 IN UINT64 MemoryLength
559 if (RShiftU64 (MemoryLength
, 32) != 0) {
561 (UINT64
) GetPowerOfTwo32 (
562 (UINT32
) RShiftU64 (MemoryLength
, 32)
567 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
575 Check the direction to program variable MTRRs.
577 This function determines which direction of programming the variable
578 MTRRs will use fewer MTRRs.
580 @param Input Length of Memory to program MTRR
581 @param MtrrNumber Pointer to the number of necessary MTRRs
583 @retval TRUE Positive direction is better.
584 FALSE Negtive direction is better.
602 TempQword
-= Power2MaxMemory (TempQword
);
604 } while (TempQword
!= 0);
606 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
609 TempQword
-= Power2MaxMemory (TempQword
);
611 } while (TempQword
!= 0);
613 if (Positive
<= Subtractive
) {
614 *MtrrNumber
= Positive
;
617 *MtrrNumber
= Subtractive
;
623 Invalid variable MTRRs according to the value in the shadow array.
625 This function programs MTRRs according to the values specified
628 @param VariableMtrr The array to shadow variable MTRRs content
633 IN VARIABLE_MTRR
*VariableMtrr
638 UINTN VariableMtrrCount
;
640 Cr4
= PreMtrrChange ();
642 VariableMtrrCount
= GetVariableMtrrCount ();
643 while (Index
< VariableMtrrCount
) {
644 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
645 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
646 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
647 VariableMtrr
[Index
].Used
= FALSE
;
651 PostMtrrChange (Cr4
);
656 Programs variable MTRRs
658 This function programs variable MTRRs
660 @param MtrrNumber Index of MTRR to program.
661 @param BaseAddress Base address of memory region.
662 @param Length Length of memory region.
663 @param MemoryCacheType Memory type to set.
664 @param MtrrValidAddressMask The valid address mask for MTRR
668 ProgramVariableMtrr (
670 IN PHYSICAL_ADDRESS BaseAddress
,
672 IN UINT64 MemoryCacheType
,
673 IN UINT64 MtrrValidAddressMask
679 Cr4
= PreMtrrChange ();
682 // MTRR Physical Base
684 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
685 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
688 // MTRR Physical Mask
690 TempQword
= ~(Length
- 1);
692 (UINT32
) (MtrrNumber
+ 1),
693 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
696 PostMtrrChange (Cr4
);
701 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
703 @param MtrrType MTRR memory type
705 @return The enum item in MTRR_MEMORY_CACHE_TYPE
708 MTRR_MEMORY_CACHE_TYPE
709 GetMemoryCacheTypeFromMtrrType (
714 case MTRR_CACHE_UNCACHEABLE
:
715 return CacheUncacheable
;
716 case MTRR_CACHE_WRITE_COMBINING
:
717 return CacheWriteCombining
;
718 case MTRR_CACHE_WRITE_THROUGH
:
719 return CacheWriteThrough
;
720 case MTRR_CACHE_WRITE_PROTECTED
:
721 return CacheWriteProtected
;
722 case MTRR_CACHE_WRITE_BACK
:
723 return CacheWriteBack
;
726 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
727 // no mtrr covers the range
729 return CacheUncacheable
;
734 Initializes the valid bits mask and valid address mask for MTRRs.
736 This function initializes the valid bits mask and valid address mask for MTRRs.
738 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
739 @param MtrrValidAddressMask The valid address mask for the MTRR
743 MtrrLibInitializeMtrrMask (
744 OUT UINT64
*MtrrValidBitsMask
,
745 OUT UINT64
*MtrrValidAddressMask
749 UINT8 PhysicalAddressBits
;
751 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
753 if (RegEax
>= 0x80000008) {
754 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
756 PhysicalAddressBits
= (UINT8
) RegEax
;
758 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
759 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
761 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
762 *MtrrValidAddressMask
= 0xFFFFFFFF;
768 Determing the real attribute of a memory range.
770 This function is to arbitrate the real attribute of the memory when
771 there are 2 MTRR covers the same memory range. For further details,
772 please refer the IA32 Software Developer's Manual, Volume 3,
775 @param MtrrType1 the first kind of Memory type
776 @param MtrrType2 the second kind of memory type
787 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
789 case MTRR_CACHE_UNCACHEABLE
:
790 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
792 case MTRR_CACHE_WRITE_COMBINING
:
794 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
795 MtrrType2
==MTRR_CACHE_UNCACHEABLE
797 MtrrType
= MtrrType2
;
800 case MTRR_CACHE_WRITE_THROUGH
:
802 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
803 MtrrType2
==MTRR_CACHE_WRITE_BACK
805 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
806 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
807 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
810 case MTRR_CACHE_WRITE_PROTECTED
:
811 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
812 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
813 MtrrType
= MtrrType2
;
816 case MTRR_CACHE_WRITE_BACK
:
818 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
819 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
820 MtrrType2
== MTRR_CACHE_WRITE_BACK
822 MtrrType
= MtrrType2
;
825 case MTRR_CACHE_INVALID_TYPE
:
826 MtrrType
= MtrrType2
;
832 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
833 MtrrType
= MtrrType1
;
840 This function attempts to set the attributes for a memory range.
842 @param BaseAddress The physical address that is the start
843 address of a memory region.
844 @param Length The size in bytes of the memory region.
845 @param Attributes The bit mask of attributes to set for the
848 @retval RETURN_SUCCESS The attributes were set for the memory
850 @retval RETURN_INVALID_PARAMETER Length is zero.
851 @retval RETURN_UNSUPPORTED The processor does not support one or
852 more bytes of the memory resource range
853 specified by BaseAddress and Length.
854 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
855 for the memory resource range specified
856 by BaseAddress and Length.
857 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
858 range specified by BaseAddress and Length
860 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
861 modify the attributes of the memory
867 MtrrSetMemoryAttribute (
868 IN PHYSICAL_ADDRESS BaseAddress
,
870 IN MTRR_MEMORY_CACHE_TYPE Attribute
874 RETURN_STATUS Status
;
881 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
883 UINT64 MtrrValidBitsMask
;
884 UINT64 MtrrValidAddressMask
;
886 BOOLEAN OverwriteExistingMtrr
;
887 UINT32 FirmwareVariableMtrrCount
;
888 UINT32 VariableMtrrEnd
;
890 if (!IsMtrrSupported ()) {
891 return RETURN_UNSUPPORTED
;
894 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
895 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
897 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
900 MemoryType
= (UINT64
)Attribute
;
901 OverwriteExistingMtrr
= FALSE
;
904 // Check for an invalid parameter
907 return RETURN_INVALID_PARAMETER
;
911 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
912 (Length
&~MtrrValidAddressMask
) != 0
914 return RETURN_UNSUPPORTED
;
918 // Check if Fixed MTRR
920 Status
= RETURN_SUCCESS
;
921 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
922 Cr4
= PreMtrrChange ();
923 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
924 PostMtrrChange (Cr4
);
925 if (RETURN_ERROR (Status
)) {
932 // A Length of 0 can only make sense for fixed MTTR ranges.
933 // Since we just handled the fixed MTRRs, we can skip the
934 // variable MTRR section.
940 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
941 // we can set the bade to 0 to save variable MTRRs.
943 if (BaseAddress
== BASE_1MB
) {
949 // Check memory base address alignment
951 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
952 if (Remainder
!= 0) {
953 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
954 if (Remainder
!= 0) {
955 Status
= RETURN_UNSUPPORTED
;
963 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
964 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
966 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
967 if (RETURN_ERROR (Status
)) {
973 // Combined successfully
975 Status
= RETURN_SUCCESS
;
981 // Program Variable MTRRs
983 // Avoid hardcode here and read data dynamically
985 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
986 Status
= RETURN_OUT_OF_RESOURCES
;
991 // The memory type is the same with the type specified by
992 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
994 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
996 // Invalidate the now-unused MTRRs
998 InvalidateMtrr(VariableMtrr
);
1005 if (TempQword
== Power2MaxMemory (TempQword
)) {
1007 // Invalidate the now-unused MTRRs
1009 InvalidateMtrr(VariableMtrr
);
1012 // Find first unused MTRR
1014 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1015 MsrNum
< VariableMtrrEnd
;
1018 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1023 ProgramVariableMtrr (
1028 MtrrValidAddressMask
1032 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1034 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1035 Status
= RETURN_OUT_OF_RESOURCES
;
1040 // Invalidate the now-unused MTRRs
1042 InvalidateMtrr(VariableMtrr
);
1045 // Find first unused MTRR
1047 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1048 MsrNum
< VariableMtrrEnd
;
1051 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1057 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1058 ProgramVariableMtrr (
1063 MtrrValidAddressMask
1065 BaseAddress
+= Length
;
1066 TempQword
= Length
- TempQword
;
1067 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1074 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1075 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1080 Length
= Power2MaxMemory (TempQword
);
1082 BaseAddress
-= Length
;
1085 ProgramVariableMtrr (
1090 MtrrValidAddressMask
1094 BaseAddress
+= Length
;
1096 TempQword
-= Length
;
1098 } while (TempQword
> 0);
1108 This function will get the memory cache type of the specific address.
1110 This function is mainly for debug purpose.
1112 @param Address The specific address
1114 @return Memory cache type of the sepcific address
1117 MTRR_MEMORY_CACHE_TYPE
1119 MtrrGetMemoryAttribute (
1120 IN PHYSICAL_ADDRESS Address
1127 UINT64 TempMtrrType
;
1128 MTRR_MEMORY_CACHE_TYPE CacheType
;
1129 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1130 UINT64 MtrrValidBitsMask
;
1131 UINT64 MtrrValidAddressMask
;
1132 UINTN VariableMtrrCount
;
1134 if (!IsMtrrSupported ()) {
1135 return CacheUncacheable
;
1139 // Check if MTRR is enabled, if not, return UC as attribute
1141 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1142 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1144 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1145 return CacheUncacheable
;
1149 // If address is less than 1M, then try to go through the fixed MTRR
1151 if (Address
< BASE_1MB
) {
1152 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1154 // Go through the fixed MTRR
1156 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1157 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1159 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1160 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1164 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1165 MtrrLibFixedMtrrTable
[Index
].Length
;
1166 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1167 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1168 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1173 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1174 MtrrGetMemoryAttributeInVariableMtrr(
1176 MtrrValidAddressMask
,
1181 // Go through the variable MTRR
1183 VariableMtrrCount
= GetVariableMtrrCount ();
1184 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1186 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1187 if (VariableMtrr
[Index
].Valid
) {
1188 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1189 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1190 TempMtrrType
= VariableMtrr
[Index
].Type
;
1191 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1195 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1202 This function will get the raw value in variable MTRRs
1204 @param VariableSettings A buffer to hold variable MTRRs content.
1206 @return The VariableSettings input pointer
1209 MTRR_VARIABLE_SETTINGS
*
1211 MtrrGetVariableMtrr (
1212 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1216 UINT32 VariableMtrrCount
;
1218 if (!IsMtrrSupported ()) {
1219 return VariableSettings
;
1222 VariableMtrrCount
= GetVariableMtrrCount ();
1223 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1225 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1226 VariableSettings
->Mtrr
[Index
].Base
=
1227 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1228 VariableSettings
->Mtrr
[Index
].Mask
=
1229 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1232 return VariableSettings
;
1237 Worker function setting variable MTRRs
1239 @param VariableSettings A buffer to hold variable MTRRs content.
1243 MtrrSetVariableMtrrWorker (
1244 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1248 UINT32 VariableMtrrCount
;
1250 VariableMtrrCount
= GetVariableMtrrCount ();
1251 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1253 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1255 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1256 VariableSettings
->Mtrr
[Index
].Base
1259 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1260 VariableSettings
->Mtrr
[Index
].Mask
1267 This function sets variable MTRRs
1269 @param VariableSettings A buffer to hold variable MTRRs content.
1271 @return The pointer of VariableSettings
1274 MTRR_VARIABLE_SETTINGS
*
1276 MtrrSetVariableMtrr (
1277 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1282 if (!IsMtrrSupported ()) {
1283 return VariableSettings
;
1286 Cr4
= PreMtrrChange ();
1287 MtrrSetVariableMtrrWorker (VariableSettings
);
1288 PostMtrrChange (Cr4
);
1289 return VariableSettings
;
1294 This function gets the content in fixed MTRRs
1296 @param FixedSettings A buffer to hold fixed Mtrrs content.
1298 @retval The pointer of FixedSettings
1301 MTRR_FIXED_SETTINGS
*
1304 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1309 if (!IsMtrrSupported ()) {
1310 return FixedSettings
;
1313 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1314 FixedSettings
->Mtrr
[Index
] =
1315 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1318 return FixedSettings
;
1322 Worker function setting fixed MTRRs
1324 @param FixedSettings A buffer to hold fixed Mtrrs content.
1328 MtrrSetFixedMtrrWorker (
1329 IN MTRR_FIXED_SETTINGS
*FixedSettings
1334 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1336 MtrrLibFixedMtrrTable
[Index
].Msr
,
1337 FixedSettings
->Mtrr
[Index
]
1344 This function sets fixed MTRRs
1346 @param FixedSettings A buffer to hold fixed Mtrrs content.
1348 @retval The pointer of FixedSettings
1351 MTRR_FIXED_SETTINGS
*
1354 IN MTRR_FIXED_SETTINGS
*FixedSettings
1359 if (!IsMtrrSupported ()) {
1360 return FixedSettings
;
1363 Cr4
= PreMtrrChange ();
1364 MtrrSetFixedMtrrWorker (FixedSettings
);
1365 PostMtrrChange (Cr4
);
1367 return FixedSettings
;
1372 This function gets the content in all MTRRs (variable and fixed)
1374 @param MtrrSetting A buffer to hold all Mtrrs content.
1376 @retval the pointer of MtrrSetting
1382 OUT MTRR_SETTINGS
*MtrrSetting
1385 if (!IsMtrrSupported ()) {
1392 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1395 // Get variable MTRRs
1397 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1400 // Get MTRR_DEF_TYPE value
1402 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1409 This function sets all MTRRs (variable and fixed)
1411 @param MtrrSetting A buffer holding all MTRRs content.
1413 @retval The pointer of MtrrSetting
1419 IN MTRR_SETTINGS
*MtrrSetting
1424 if (!IsMtrrSupported ()) {
1428 Cr4
= PreMtrrChange ();
1433 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1436 // Set variable MTRRs
1438 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1441 // Set MTRR_DEF_TYPE value
1443 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1445 PostMtrrChange (Cr4
);
1452 This function prints all MTRRs for debugging.
1456 MtrrDebugPrintAllMtrrs (
1462 MTRR_SETTINGS MtrrSettings
;
1464 UINTN VariableMtrrCount
;
1466 if (!IsMtrrSupported ()) {
1470 MtrrGetAllMtrrs (&MtrrSettings
);
1471 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1472 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1474 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1476 MtrrSettings
.Fixed
.Mtrr
[Index
]
1480 VariableMtrrCount
= GetVariableMtrrCount ();
1481 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1483 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1485 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1486 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1494 Checks if MTRR is supported.
1496 @retval TRUE MTRR is supported.
1497 @retval FALSE MTRR is not supported.
1510 // Check CPUID(1).EDX[12] for MTRR capability
1512 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1513 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1518 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1519 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1520 // exist, return false.
1522 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1523 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {