4 Copyright (c) 2008 - 2010, Intel Corporation
5 All rights reserved. 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
27 FIXED_MTRR MtrrLibFixedMtrrTable
[] = {
29 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
34 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
39 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
44 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
49 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
54 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
59 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
64 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
69 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
74 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
79 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
86 Returns the variable MTRR count for the CPU.
88 @return Variable MTRR count
92 GetVariableMtrrCount (
96 return (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
100 Returns the firmware usable variable MTRR count for the CPU.
102 @return Firmware usable variable MTRR count
106 GetFirmwareVariableMtrrCount (
110 return GetVariableMtrrCount () - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
114 Returns the default MTRR cache type for the system.
116 @return MTRR default type
120 GetMtrrDefaultMemoryType (
124 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
129 Preparation before programming MTRR.
131 This function will do some preparation for programming MTRRs:
132 disable cache, invalid cache and disable MTRR caching functionality
134 @return CR4 value before changing.
145 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
150 // Save original CR4 value and clear PGE flag (Bit 7)
152 Value
= AsmReadCr4 ();
153 AsmWriteCr4 (Value
& (~BIT7
));
163 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
166 // Return original CR4 value
173 Cleaning up after programming MTRRs.
175 This function will do some clean up after programming MTRRs:
176 enable MTRR caching functionality, and enable cache
178 @param Cr4 CR4 value to restore
189 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
197 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
202 // Restore original CR4 value
209 Programs fixed MTRRs registers.
211 @param MemoryCacheType The memory type to set.
212 @param Base The base address of memory range.
213 @param Length The length of memory range.
215 @retval RETURN_SUCCESS The cache type was updated successfully
216 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
222 IN UINT64 MemoryCacheType
,
224 IN OUT UINT64
*Length
237 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
238 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
241 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
242 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
250 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
251 return RETURN_UNSUPPORTED
;
255 // We found the fixed MTRR to be programmed
257 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
260 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
261 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
268 if (ByteShift
== 8) {
269 return RETURN_UNSUPPORTED
;
274 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
277 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
278 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
279 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
280 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
283 if (ByteShift
< 8 && (*Length
!= 0)) {
284 return RETURN_UNSUPPORTED
;
288 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
289 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
290 return RETURN_SUCCESS
;
295 Get the attribute of variable MTRRs.
297 This function shadows the content of variable MTRRs into an
298 internal array: VariableMtrr.
300 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
301 @param MtrrValidAddressMask The valid address mask for MTRR
302 @param VariableMtrr The array to shadow variable MTRRs content
304 @return The return value of this paramter indicates the
305 number of MTRRs which has been used.
310 MtrrGetMemoryAttributeInVariableMtrr (
311 IN UINT64 MtrrValidBitsMask
,
312 IN UINT64 MtrrValidAddressMask
,
313 OUT VARIABLE_MTRR
*VariableMtrr
319 UINT32 FirmwareVariableMtrrCount
;
320 UINT32 VariableMtrrEnd
;
322 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
323 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
325 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
328 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
330 (MsrNum
< VariableMtrrEnd
) &&
331 (Index
< FirmwareVariableMtrrCount
)
335 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
336 VariableMtrr
[Index
].Msr
= MsrNum
;
337 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
338 MtrrValidAddressMask
);
339 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
340 MtrrValidAddressMask
)
344 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
345 VariableMtrr
[Index
].Valid
= TRUE
;
346 VariableMtrr
[Index
].Used
= TRUE
;
347 UsedMtrr
= UsedMtrr
+ 1;
356 Checks overlap between given memory range and MTRRs.
358 @param Start The start address of memory range.
359 @param End The end address of memory range.
360 @param VariableMtrr The array to shadow variable MTRRs content
362 @retval TRUE Overlap exists.
363 @retval FALSE No overlap.
367 CheckMemoryAttributeOverlap (
368 IN PHYSICAL_ADDRESS Start
,
369 IN PHYSICAL_ADDRESS End
,
370 IN VARIABLE_MTRR
*VariableMtrr
375 for (Index
= 0; Index
< 6; Index
++) {
377 VariableMtrr
[Index
].Valid
&&
379 (Start
> (VariableMtrr
[Index
].BaseAddress
+
380 VariableMtrr
[Index
].Length
- 1)
382 (End
< VariableMtrr
[Index
].BaseAddress
)
394 Marks a variable MTRR as non-valid.
396 @param Index The index of the array VariableMtrr to be invalidated
397 @param VariableMtrr The array to shadow variable MTRRs content
398 @param UsedMtrr The number of MTRRs which has already been used
402 InvalidateShadowMtrr (
404 IN VARIABLE_MTRR
*VariableMtrr
,
408 VariableMtrr
[Index
].Valid
= FALSE
;
409 *UsedMtrr
= *UsedMtrr
- 1;
414 Combine memory attributes.
416 If overlap exists between given memory range and MTRRs, try to combine them.
418 @param Attributes The memory type to set.
419 @param Base The base address of memory range.
420 @param Length The length of memory range.
421 @param VariableMtrr The array to shadow variable MTRRs content
422 @param UsedMtrr The number of MTRRs which has already been used
423 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
425 @retval EFI_SUCCESS Memory region successfully combined.
426 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
430 CombineMemoryAttribute (
431 IN UINT64 Attributes
,
433 IN OUT UINT64
*Length
,
434 IN VARIABLE_MTRR
*VariableMtrr
,
435 IN OUT UINT32
*UsedMtrr
,
436 OUT BOOLEAN
*OverwriteExistingMtrr
444 UINT32 FirmwareVariableMtrrCount
;
446 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
448 *OverwriteExistingMtrr
= FALSE
;
449 EndAddress
= *Base
+*Length
- 1;
451 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
453 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
455 !VariableMtrr
[Index
].Valid
||
458 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
465 // Combine same attribute MTRR range
467 if (Attributes
== VariableMtrr
[Index
].Type
) {
469 // if the Mtrr range contain the request range, return RETURN_SUCCESS
471 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
473 return RETURN_SUCCESS
;
476 // invalid this MTRR, and program the combine range
479 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
481 VariableMtrr
[Index
].BaseAddress
;
482 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
485 // Record the MTRR usage status in VariableMtrr array.
487 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
488 *Base
= CombineStart
;
489 *Length
= CombineEnd
- CombineStart
+ 1;
490 EndAddress
= CombineEnd
;
491 *OverwriteExistingMtrr
= TRUE
;
495 // The cache type is different, but the range is convered by one MTRR
497 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
498 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
504 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
505 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
506 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
507 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
508 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
509 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
511 *OverwriteExistingMtrr
= TRUE
;
515 // Other type memory overlap is invalid
517 return RETURN_ACCESS_DENIED
;
520 return RETURN_SUCCESS
;
525 Calculate the maximum value which is a power of 2, but less the MemoryLength.
527 @param MemoryLength The number to pass in.
528 @return The maximum value which is align to power of 2 and less the MemoryLength
533 IN UINT64 MemoryLength
538 if (RShiftU64 (MemoryLength
, 32)) {
540 (UINT64
) GetPowerOfTwo32 (
541 (UINT32
) RShiftU64 (MemoryLength
, 32)
546 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
554 Check the direction to program variable MTRRs.
556 This function determines which direction of programming the variable
557 MTRRs will use fewer MTRRs.
559 @param Input Length of Memory to program MTRR
560 @param MtrrNumber Pointer to the number of necessary MTRRs
562 @retval TRUE Positive direction is better.
563 FALSE Negtive direction is better.
581 TempQword
-= Power2MaxMemory (TempQword
);
583 } while (TempQword
!= 0);
585 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
588 TempQword
-= Power2MaxMemory (TempQword
);
590 } while (TempQword
!= 0);
592 if (Positive
<= Subtractive
) {
593 *MtrrNumber
= Positive
;
596 *MtrrNumber
= Subtractive
;
602 Invalid variable MTRRs according to the value in the shadow array.
604 This function programs MTRRs according to the values specified
607 @param VariableMtrr The array to shadow variable MTRRs content
613 IN VARIABLE_MTRR
*VariableMtrr
618 UINTN VariableMtrrCount
;
620 Cr4
= PreMtrrChange ();
622 VariableMtrrCount
= GetVariableMtrrCount ();
623 while (Index
< VariableMtrrCount
) {
624 if (VariableMtrr
[Index
].Valid
== FALSE
&& VariableMtrr
[Index
].Used
== TRUE
) {
625 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
626 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
627 VariableMtrr
[Index
].Used
= FALSE
;
631 PostMtrrChange (Cr4
);
636 Programs variable MTRRs
638 This function programs variable MTRRs
640 @param MtrrNumber Index of MTRR to program.
641 @param BaseAddress Base address of memory region.
642 @param Length Length of memory region.
643 @param MemoryCacheType Memory type to set.
644 @param MtrrValidAddressMask The valid address mask for MTRR
649 ProgramVariableMtrr (
651 IN PHYSICAL_ADDRESS BaseAddress
,
653 IN UINT64 MemoryCacheType
,
654 IN UINT64 MtrrValidAddressMask
660 Cr4
= PreMtrrChange ();
663 // MTRR Physical Base
665 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
666 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
669 // MTRR Physical Mask
671 TempQword
= ~(Length
- 1);
673 (UINT32
) (MtrrNumber
+ 1),
674 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
677 PostMtrrChange (Cr4
);
682 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
684 @param MtrrType MTRR memory type
686 @return The enum item in MTRR_MEMORY_CACHE_TYPE
690 MTRR_MEMORY_CACHE_TYPE
691 GetMemoryCacheTypeFromMtrrType (
696 case MTRR_CACHE_UNCACHEABLE
:
697 return CacheUncacheable
;
698 case MTRR_CACHE_WRITE_COMBINING
:
699 return CacheWriteCombining
;
700 case MTRR_CACHE_WRITE_THROUGH
:
701 return CacheWriteThrough
;
702 case MTRR_CACHE_WRITE_PROTECTED
:
703 return CacheWriteProtected
;
704 case MTRR_CACHE_WRITE_BACK
:
705 return CacheWriteBack
;
708 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
709 // no mtrr covers the range
711 return CacheUncacheable
;
716 Initializes the valid bits mask and valid address mask for MTRRs.
718 This function initializes the valid bits mask and valid address mask for MTRRs.
720 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
721 @param MtrrValidAddressMask The valid address mask for the MTRR
726 MtrrLibInitializeMtrrMask (
727 OUT UINT64
*MtrrValidBitsMask
,
728 OUT UINT64
*MtrrValidAddressMask
732 UINT8 PhysicalAddressBits
;
734 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
736 if (RegEax
>= 0x80000008) {
737 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
739 PhysicalAddressBits
= (UINT8
) RegEax
;
741 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
742 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
744 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
745 *MtrrValidAddressMask
= 0xFFFFFFFF;
751 Determing the real attribute of a memory range.
753 This function is to arbitrate the real attribute of the memory when
754 there are 2 MTRR covers the same memory range. For further details,
755 please refer the IA32 Software Developer's Manual, Volume 3,
758 @param MtrrType1 the first kind of Memory type
759 @param MtrrType2 the second kind of memory type
770 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
772 case MTRR_CACHE_UNCACHEABLE
:
773 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
775 case MTRR_CACHE_WRITE_COMBINING
:
777 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
778 MtrrType2
==MTRR_CACHE_UNCACHEABLE
780 MtrrType
= MtrrType2
;
783 case MTRR_CACHE_WRITE_THROUGH
:
785 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
786 MtrrType2
==MTRR_CACHE_WRITE_BACK
788 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
789 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
790 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
793 case MTRR_CACHE_WRITE_PROTECTED
:
794 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
795 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
796 MtrrType
= MtrrType2
;
799 case MTRR_CACHE_WRITE_BACK
:
801 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
802 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
803 MtrrType2
== MTRR_CACHE_WRITE_BACK
805 MtrrType
= MtrrType2
;
808 case MTRR_CACHE_INVALID_TYPE
:
809 MtrrType
= MtrrType2
;
815 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
816 MtrrType
= MtrrType1
;
823 This function attempts to set the attributes for a memory range.
825 @param BaseAddress The physical address that is the start
826 address of a memory region.
827 @param Length The size in bytes of the memory region.
828 @param Attributes The bit mask of attributes to set for the
831 @retval RETURN_SUCCESS The attributes were set for the memory
833 @retval RETURN_INVALID_PARAMETER Length is zero.
834 @retval RETURN_UNSUPPORTED The processor does not support one or
835 more bytes of the memory resource range
836 specified by BaseAddress and Length.
837 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
838 for the memory resource range specified
839 by BaseAddress and Length.
840 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
841 range specified by BaseAddress and Length
843 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
844 modify the attributes of the memory
850 MtrrSetMemoryAttribute (
851 IN PHYSICAL_ADDRESS BaseAddress
,
853 IN MTRR_MEMORY_CACHE_TYPE Attribute
857 RETURN_STATUS Status
;
864 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
866 UINT64 MtrrValidBitsMask
;
867 UINT64 MtrrValidAddressMask
;
869 BOOLEAN OverwriteExistingMtrr
;
870 UINT32 FirmwareVariableMtrrCount
;
871 UINT32 VariableMtrrEnd
;
873 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
874 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
876 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
879 MemoryType
= (UINT64
)Attribute
;
880 OverwriteExistingMtrr
= FALSE
;
883 // Check for an invalid parameter
886 return RETURN_INVALID_PARAMETER
;
890 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
891 (Length
&~MtrrValidAddressMask
) != 0
893 return RETURN_UNSUPPORTED
;
897 // Check if Fixed MTRR
899 Status
= RETURN_SUCCESS
;
900 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
901 Cr4
= PreMtrrChange ();
902 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
903 PostMtrrChange (Cr4
);
904 if (RETURN_ERROR (Status
)) {
911 // A Length of 0 can only make sense for fixed MTTR ranges.
912 // Since we just handled the fixed MTRRs, we can skip the
913 // variable MTRR section.
919 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
920 // we can set the bade to 0 to save variable MTRRs.
922 if (BaseAddress
== BASE_1MB
) {
928 // Check memory base address alignment
930 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
931 if (Remainder
!= 0) {
932 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
933 if (Remainder
!= 0) {
934 Status
= RETURN_UNSUPPORTED
;
942 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
943 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
945 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
946 if (RETURN_ERROR (Status
)) {
952 // Combined successfully
954 Status
= RETURN_SUCCESS
;
960 // Program Variable MTRRs
962 // Avoid hardcode here and read data dynamically
964 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
965 Status
= RETURN_OUT_OF_RESOURCES
;
970 // The memory type is the same with the type specified by
971 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
973 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
975 // Invalidate the now-unused MTRRs
977 InvalidateMtrr(VariableMtrr
);
984 if (TempQword
== Power2MaxMemory (TempQword
)) {
986 // Invalidate the now-unused MTRRs
988 InvalidateMtrr(VariableMtrr
);
991 // Find first unused MTRR
993 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
994 MsrNum
< VariableMtrrEnd
;
997 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1002 ProgramVariableMtrr (
1007 MtrrValidAddressMask
1011 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1013 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1014 Status
= RETURN_OUT_OF_RESOURCES
;
1019 // Invalidate the now-unused MTRRs
1021 InvalidateMtrr(VariableMtrr
);
1024 // Find first unused MTRR
1026 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1027 MsrNum
< VariableMtrrEnd
;
1030 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1036 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1037 ProgramVariableMtrr (
1042 MtrrValidAddressMask
1044 BaseAddress
+= Length
;
1045 TempQword
= Length
- TempQword
;
1046 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1053 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1054 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1059 Length
= Power2MaxMemory (TempQword
);
1061 BaseAddress
-= Length
;
1064 ProgramVariableMtrr (
1069 MtrrValidAddressMask
1073 BaseAddress
+= Length
;
1075 TempQword
-= Length
;
1077 } while (TempQword
> 0);
1087 This function will get the memory cache type of the specific address.
1089 This function is mainly for debug purpose.
1091 @param Address The specific address
1093 @return Memory cache type of the sepcific address
1096 MTRR_MEMORY_CACHE_TYPE
1098 MtrrGetMemoryAttribute (
1099 IN PHYSICAL_ADDRESS Address
1106 UINT64 TempMtrrType
;
1107 MTRR_MEMORY_CACHE_TYPE CacheType
;
1108 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1109 UINT64 MtrrValidBitsMask
;
1110 UINT64 MtrrValidAddressMask
;
1111 UINTN VariableMtrrCount
;
1114 // Check if MTRR is enabled, if not, return UC as attribute
1116 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1117 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1119 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1120 return CacheUncacheable
;
1124 // If address is less than 1M, then try to go through the fixed MTRR
1126 if (Address
< BASE_1MB
) {
1127 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1129 // Go through the fixed MTRR
1131 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1132 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1134 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1135 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1139 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1140 MtrrLibFixedMtrrTable
[Index
].Length
;
1141 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1142 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1143 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1148 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1149 MtrrGetMemoryAttributeInVariableMtrr(
1151 MtrrValidAddressMask
,
1156 // Go through the variable MTRR
1158 VariableMtrrCount
= GetVariableMtrrCount ();
1159 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1160 if (VariableMtrr
[Index
].Valid
) {
1161 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1162 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1163 TempMtrrType
= VariableMtrr
[Index
].Type
;
1164 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1168 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1175 This function will get the raw value in variable MTRRs
1177 @param VariableSettings A buffer to hold variable MTRRs content.
1179 @return The VariableSettings input pointer
1182 MTRR_VARIABLE_SETTINGS
*
1184 MtrrGetVariableMtrr (
1185 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1189 UINT32 VariableMtrrCount
;
1191 VariableMtrrCount
= GetVariableMtrrCount ();
1192 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1193 VariableSettings
->Mtrr
[Index
].Base
=
1194 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1195 VariableSettings
->Mtrr
[Index
].Mask
=
1196 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1199 return VariableSettings
;
1204 Worker function setting variable MTRRs
1206 @param VariableSettings A buffer to hold variable MTRRs content.
1210 MtrrSetVariableMtrrWorker (
1211 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1215 UINT32 VariableMtrrCount
;
1217 VariableMtrrCount
= GetVariableMtrrCount ();
1218 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1220 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1221 VariableSettings
->Mtrr
[Index
].Base
1224 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1225 VariableSettings
->Mtrr
[Index
].Mask
1232 This function sets variable MTRRs
1234 @param VariableSettings A buffer to hold variable MTRRs content.
1236 @return The pointer of VariableSettings
1239 MTRR_VARIABLE_SETTINGS
*
1241 MtrrSetVariableMtrr (
1242 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1247 Cr4
= PreMtrrChange ();
1248 MtrrSetVariableMtrrWorker (VariableSettings
);
1249 PostMtrrChange (Cr4
);
1250 return VariableSettings
;
1255 This function gets the content in fixed MTRRs
1257 @param FixedSettings A buffer to hold fixed Mtrrs content.
1259 @retval The pointer of FixedSettings
1262 MTRR_FIXED_SETTINGS
*
1265 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1270 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1271 FixedSettings
->Mtrr
[Index
] =
1272 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1275 return FixedSettings
;
1279 Worker function setting fixed MTRRs
1281 @param FixedSettings A buffer to hold fixed Mtrrs content.
1285 MtrrSetFixedMtrrWorker (
1286 IN MTRR_FIXED_SETTINGS
*FixedSettings
1291 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1293 MtrrLibFixedMtrrTable
[Index
].Msr
,
1294 FixedSettings
->Mtrr
[Index
]
1301 This function sets fixed MTRRs
1303 @param FixedSettings A buffer to hold fixed Mtrrs content.
1305 @retval The pointer of FixedSettings
1308 MTRR_FIXED_SETTINGS
*
1311 IN MTRR_FIXED_SETTINGS
*FixedSettings
1316 Cr4
= PreMtrrChange ();
1317 MtrrSetFixedMtrrWorker (FixedSettings
);
1318 PostMtrrChange (Cr4
);
1320 return FixedSettings
;
1325 This function gets the content in all MTRRs (variable and fixed)
1327 @param MtrrSetting A buffer to hold all Mtrrs content.
1329 @retval the pointer of MtrrSetting
1335 OUT MTRR_SETTINGS
*MtrrSetting
1341 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1344 // Get variable MTRRs
1346 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1349 // Get MTRR_DEF_TYPE value
1351 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1358 This function sets all MTRRs (variable and fixed)
1360 @param MtrrSetting A buffer holding all MTRRs content.
1362 @retval The pointer of MtrrSetting
1368 IN MTRR_SETTINGS
*MtrrSetting
1373 Cr4
= PreMtrrChange ();
1378 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1381 // Set variable MTRRs
1383 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1386 // Set MTRR_DEF_TYPE value
1388 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1390 PostMtrrChange (Cr4
);
1397 This function prints all MTRRs for debugging.
1400 MtrrDebugPrintAllMtrrs (
1405 MTRR_SETTINGS MtrrSettings
;
1407 UINTN VariableMtrrCount
;
1409 MtrrGetAllMtrrs (&MtrrSettings
);
1410 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1411 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1413 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1415 MtrrSettings
.Fixed
.Mtrr
[Index
]
1419 VariableMtrrCount
= GetVariableMtrrCount ();
1420 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1422 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1424 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1425 MtrrSettings
.Variables
.Mtrr
[Index
].Mask