4 Copyright (c) 2008 - 2014, 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 // Context to save and restore when MTRRs are programmed
28 BOOLEAN InterruptState
;
32 // This table defines the offset, base and length of the fixed MTRRs
34 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
36 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
41 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
46 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
51 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
56 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
61 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
66 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
71 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
76 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
81 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
86 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
93 // Lookup table used to print MTRRs
95 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
96 "UC", // CacheUncacheable
97 "WC", // CacheWriteCombining
100 "WT", // CacheWriteThrough
101 "WP", // CacheWriteProtected
102 "WB", // CacheWriteBack
107 Returns the variable MTRR count for the CPU.
109 @return Variable MTRR count
114 GetVariableMtrrCount (
118 UINT32 VariableMtrrCount
;
120 if (!IsMtrrSupported ()) {
124 VariableMtrrCount
= (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
125 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
127 return VariableMtrrCount
;
131 Returns the firmware usable variable MTRR count for the CPU.
133 @return Firmware usable variable MTRR count
138 GetFirmwareVariableMtrrCount (
142 UINT32 VariableMtrrCount
;
144 VariableMtrrCount
= GetVariableMtrrCount ();
145 if (VariableMtrrCount
< RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
) {
149 return VariableMtrrCount
- RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
153 Returns the default MTRR cache type for the system.
155 @return The default MTRR cache type.
158 MTRR_MEMORY_CACHE_TYPE
160 MtrrGetDefaultMemoryType (
164 if (!IsMtrrSupported ()) {
165 return CacheUncacheable
;
168 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
172 Preparation before programming MTRR.
174 This function will do some preparation for programming MTRRs:
175 disable cache, invalid cache and disable MTRR caching functionality
177 @param[out] MtrrContext Pointer to context to save
182 OUT MTRR_CONTEXT
*MtrrContext
186 // Disable interrupts and save current interrupt state
188 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
191 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
196 // Save original CR4 value and clear PGE flag (Bit 7)
198 MtrrContext
->Cr4
= AsmReadCr4 ();
199 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
209 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
213 Cleaning up after programming MTRRs.
215 This function will do some clean up after programming MTRRs:
216 Flush all TLBs, re-enable caching, restore CR4.
218 @param[in] MtrrContext Pointer to context to restore
222 PostMtrrChangeEnableCache (
223 IN MTRR_CONTEXT
*MtrrContext
232 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
237 // Restore original CR4 value
239 AsmWriteCr4 (MtrrContext
->Cr4
);
242 // Restore original interrupt state
244 SetInterruptState (MtrrContext
->InterruptState
);
248 Cleaning up after programming MTRRs.
250 This function will do some clean up after programming MTRRs:
251 enable MTRR caching functionality, and enable cache
253 @param[in] MtrrContext Pointer to context to restore
258 IN MTRR_CONTEXT
*MtrrContext
264 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
266 PostMtrrChangeEnableCache (MtrrContext
);
271 Programs fixed MTRRs registers.
273 @param MemoryCacheType The memory type to set.
274 @param Base The base address of memory range.
275 @param Length The length of memory range.
277 @retval RETURN_SUCCESS The cache type was updated successfully
278 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
284 IN UINT64 MemoryCacheType
,
286 IN OUT UINT64
*Length
299 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
300 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
303 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
304 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
312 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
313 return RETURN_UNSUPPORTED
;
317 // We found the fixed MTRR to be programmed
319 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
322 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
323 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
330 if (ByteShift
== 8) {
331 return RETURN_UNSUPPORTED
;
336 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
339 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
340 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
341 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
342 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
345 if (ByteShift
< 8 && (*Length
!= 0)) {
346 return RETURN_UNSUPPORTED
;
350 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
351 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
352 return RETURN_SUCCESS
;
357 Get the attribute of variable MTRRs.
359 This function shadows the content of variable MTRRs into an
360 internal array: VariableMtrr.
362 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
363 @param MtrrValidAddressMask The valid address mask for MTRR
364 @param VariableMtrr The array to shadow variable MTRRs content
366 @return The return value of this paramter indicates the
367 number of MTRRs which has been used.
372 MtrrGetMemoryAttributeInVariableMtrr (
373 IN UINT64 MtrrValidBitsMask
,
374 IN UINT64 MtrrValidAddressMask
,
375 OUT VARIABLE_MTRR
*VariableMtrr
381 UINT32 FirmwareVariableMtrrCount
;
382 UINT32 VariableMtrrEnd
;
384 if (!IsMtrrSupported ()) {
388 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
389 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
391 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
394 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
396 (MsrNum
< VariableMtrrEnd
) &&
397 (Index
< FirmwareVariableMtrrCount
)
401 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
402 VariableMtrr
[Index
].Msr
= MsrNum
;
403 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
404 MtrrValidAddressMask
);
405 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
406 MtrrValidAddressMask
)
410 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
411 VariableMtrr
[Index
].Valid
= TRUE
;
412 VariableMtrr
[Index
].Used
= TRUE
;
413 UsedMtrr
= UsedMtrr
+ 1;
422 Checks overlap between given memory range and MTRRs.
424 @param Start The start address of memory range.
425 @param End The end address of memory range.
426 @param VariableMtrr The array to shadow variable MTRRs content
428 @retval TRUE Overlap exists.
429 @retval FALSE No overlap.
433 CheckMemoryAttributeOverlap (
434 IN PHYSICAL_ADDRESS Start
,
435 IN PHYSICAL_ADDRESS End
,
436 IN VARIABLE_MTRR
*VariableMtrr
441 for (Index
= 0; Index
< 6; Index
++) {
443 VariableMtrr
[Index
].Valid
&&
445 (Start
> (VariableMtrr
[Index
].BaseAddress
+
446 VariableMtrr
[Index
].Length
- 1)
448 (End
< VariableMtrr
[Index
].BaseAddress
)
460 Marks a variable MTRR as non-valid.
462 @param Index The index of the array VariableMtrr to be invalidated
463 @param VariableMtrr The array to shadow variable MTRRs content
464 @param UsedMtrr The number of MTRRs which has already been used
468 InvalidateShadowMtrr (
470 IN VARIABLE_MTRR
*VariableMtrr
,
474 VariableMtrr
[Index
].Valid
= FALSE
;
475 *UsedMtrr
= *UsedMtrr
- 1;
480 Combine memory attributes.
482 If overlap exists between given memory range and MTRRs, try to combine them.
484 @param Attributes The memory type to set.
485 @param Base The base address of memory range.
486 @param Length The length of memory range.
487 @param VariableMtrr The array to shadow variable MTRRs content
488 @param UsedMtrr The number of MTRRs which has already been used
489 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
491 @retval EFI_SUCCESS Memory region successfully combined.
492 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
496 CombineMemoryAttribute (
497 IN UINT64 Attributes
,
499 IN OUT UINT64
*Length
,
500 IN VARIABLE_MTRR
*VariableMtrr
,
501 IN OUT UINT32
*UsedMtrr
,
502 OUT BOOLEAN
*OverwriteExistingMtrr
510 UINT32 FirmwareVariableMtrrCount
;
511 BOOLEAN CoveredByExistingMtrr
;
513 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
515 *OverwriteExistingMtrr
= FALSE
;
516 CoveredByExistingMtrr
= FALSE
;
517 EndAddress
= *Base
+*Length
- 1;
519 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
521 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
523 !VariableMtrr
[Index
].Valid
||
526 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
533 // Combine same attribute MTRR range
535 if (Attributes
== VariableMtrr
[Index
].Type
) {
537 // if the Mtrr range contain the request range, set a flag, then continue to
538 // invalidate any MTRR of the same request range with higher priority cache type.
540 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
541 CoveredByExistingMtrr
= TRUE
;
545 // invalid this MTRR, and program the combine range
548 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
550 VariableMtrr
[Index
].BaseAddress
;
551 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
554 // Record the MTRR usage status in VariableMtrr array.
556 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
557 *Base
= CombineStart
;
558 *Length
= CombineEnd
- CombineStart
+ 1;
559 EndAddress
= CombineEnd
;
560 *OverwriteExistingMtrr
= TRUE
;
564 // The cache type is different, but the range is convered by one MTRR
566 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
567 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
573 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
574 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
575 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
576 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
577 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
578 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
580 *OverwriteExistingMtrr
= TRUE
;
584 // Other type memory overlap is invalid
586 return RETURN_ACCESS_DENIED
;
589 if (CoveredByExistingMtrr
) {
593 return RETURN_SUCCESS
;
598 Calculate the maximum value which is a power of 2, but less the MemoryLength.
600 @param MemoryLength The number to pass in.
601 @return The maximum value which is align to power of 2 and less the MemoryLength
606 IN UINT64 MemoryLength
611 if (RShiftU64 (MemoryLength
, 32) != 0) {
613 (UINT64
) GetPowerOfTwo32 (
614 (UINT32
) RShiftU64 (MemoryLength
, 32)
619 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
627 Determine the MTRR numbers used to program a memory range.
629 This function first checks the alignment of the base address. If the alignment of the base address <= Length,
630 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
631 Repeat the step until alignment > Length.
633 Then this function determines which direction of programming the variable MTRRs for the remaining length
634 will use fewer MTRRs.
636 @param BaseAddress Length of Memory to program MTRR
637 @param Length Length of Memory to program MTRR
638 @param MtrrNumber Pointer to the number of necessary MTRRs
640 @retval TRUE Positive direction is better.
641 FALSE Negtive direction is better.
645 GetMtrrNumberAndDirection (
646 IN UINT64 BaseAddress
,
658 if (BaseAddress
!= 0) {
661 // Calculate the alignment of the base address.
663 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
665 if (Alignment
> Length
) {
670 BaseAddress
+= Alignment
;
684 TempQword
-= Power2MaxMemory (TempQword
);
686 } while (TempQword
!= 0);
688 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
691 TempQword
-= Power2MaxMemory (TempQword
);
693 } while (TempQword
!= 0);
695 if (Positive
<= Subtractive
) {
696 *MtrrNumber
+= Positive
;
699 *MtrrNumber
+= Subtractive
;
705 Invalid variable MTRRs according to the value in the shadow array.
707 This function programs MTRRs according to the values specified
710 @param VariableMtrr The array to shadow variable MTRRs content
715 IN VARIABLE_MTRR
*VariableMtrr
719 UINTN VariableMtrrCount
;
720 MTRR_CONTEXT MtrrContext
;
722 PreMtrrChange (&MtrrContext
);
724 VariableMtrrCount
= GetVariableMtrrCount ();
725 while (Index
< VariableMtrrCount
) {
726 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
727 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
728 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
729 VariableMtrr
[Index
].Used
= FALSE
;
733 PostMtrrChange (&MtrrContext
);
738 Programs variable MTRRs
740 This function programs variable MTRRs
742 @param MtrrNumber Index of MTRR to program.
743 @param BaseAddress Base address of memory region.
744 @param Length Length of memory region.
745 @param MemoryCacheType Memory type to set.
746 @param MtrrValidAddressMask The valid address mask for MTRR
750 ProgramVariableMtrr (
752 IN PHYSICAL_ADDRESS BaseAddress
,
754 IN UINT64 MemoryCacheType
,
755 IN UINT64 MtrrValidAddressMask
759 MTRR_CONTEXT MtrrContext
;
761 PreMtrrChange (&MtrrContext
);
764 // MTRR Physical Base
766 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
767 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
770 // MTRR Physical Mask
772 TempQword
= ~(Length
- 1);
774 (UINT32
) (MtrrNumber
+ 1),
775 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
778 PostMtrrChange (&MtrrContext
);
783 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
785 @param MtrrType MTRR memory type
787 @return The enum item in MTRR_MEMORY_CACHE_TYPE
790 MTRR_MEMORY_CACHE_TYPE
791 GetMemoryCacheTypeFromMtrrType (
796 case MTRR_CACHE_UNCACHEABLE
:
797 return CacheUncacheable
;
798 case MTRR_CACHE_WRITE_COMBINING
:
799 return CacheWriteCombining
;
800 case MTRR_CACHE_WRITE_THROUGH
:
801 return CacheWriteThrough
;
802 case MTRR_CACHE_WRITE_PROTECTED
:
803 return CacheWriteProtected
;
804 case MTRR_CACHE_WRITE_BACK
:
805 return CacheWriteBack
;
808 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
809 // no mtrr covers the range
811 return MtrrGetDefaultMemoryType ();
816 Initializes the valid bits mask and valid address mask for MTRRs.
818 This function initializes the valid bits mask and valid address mask for MTRRs.
820 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
821 @param MtrrValidAddressMask The valid address mask for the MTRR
825 MtrrLibInitializeMtrrMask (
826 OUT UINT64
*MtrrValidBitsMask
,
827 OUT UINT64
*MtrrValidAddressMask
831 UINT8 PhysicalAddressBits
;
833 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
835 if (RegEax
>= 0x80000008) {
836 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
838 PhysicalAddressBits
= (UINT8
) RegEax
;
840 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
841 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
843 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
844 *MtrrValidAddressMask
= 0xFFFFFFFF;
850 Determing the real attribute of a memory range.
852 This function is to arbitrate the real attribute of the memory when
853 there are 2 MTRR covers the same memory range. For further details,
854 please refer the IA32 Software Developer's Manual, Volume 3,
857 @param MtrrType1 the first kind of Memory type
858 @param MtrrType2 the second kind of memory type
869 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
871 case MTRR_CACHE_UNCACHEABLE
:
872 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
874 case MTRR_CACHE_WRITE_COMBINING
:
876 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
877 MtrrType2
==MTRR_CACHE_UNCACHEABLE
879 MtrrType
= MtrrType2
;
882 case MTRR_CACHE_WRITE_THROUGH
:
884 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
885 MtrrType2
==MTRR_CACHE_WRITE_BACK
887 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
888 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
889 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
892 case MTRR_CACHE_WRITE_PROTECTED
:
893 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
894 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
895 MtrrType
= MtrrType2
;
898 case MTRR_CACHE_WRITE_BACK
:
900 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
901 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
902 MtrrType2
== MTRR_CACHE_WRITE_BACK
904 MtrrType
= MtrrType2
;
907 case MTRR_CACHE_INVALID_TYPE
:
908 MtrrType
= MtrrType2
;
914 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
915 MtrrType
= MtrrType1
;
922 This function attempts to set the attributes for a memory range.
924 @param BaseAddress The physical address that is the start
925 address of a memory region.
926 @param Length The size in bytes of the memory region.
927 @param Attributes The bit mask of attributes to set for the
930 @retval RETURN_SUCCESS The attributes were set for the memory
932 @retval RETURN_INVALID_PARAMETER Length is zero.
933 @retval RETURN_UNSUPPORTED The processor does not support one or
934 more bytes of the memory resource range
935 specified by BaseAddress and Length.
936 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
937 for the memory resource range specified
938 by BaseAddress and Length.
939 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
940 range specified by BaseAddress and Length
942 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
943 modify the attributes of the memory
949 MtrrSetMemoryAttribute (
950 IN PHYSICAL_ADDRESS BaseAddress
,
952 IN MTRR_MEMORY_CACHE_TYPE Attribute
956 RETURN_STATUS Status
;
963 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
965 UINT64 MtrrValidBitsMask
;
966 UINT64 MtrrValidAddressMask
;
967 BOOLEAN OverwriteExistingMtrr
;
968 UINT32 FirmwareVariableMtrrCount
;
969 UINT32 VariableMtrrEnd
;
970 MTRR_CONTEXT MtrrContext
;
972 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
974 if (!IsMtrrSupported ()) {
975 Status
= RETURN_UNSUPPORTED
;
979 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
980 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
982 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
985 MemoryType
= (UINT64
)Attribute
;
986 OverwriteExistingMtrr
= FALSE
;
989 // Check for an invalid parameter
992 Status
= RETURN_INVALID_PARAMETER
;
997 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
998 (Length
& ~MtrrValidAddressMask
) != 0
1000 Status
= RETURN_UNSUPPORTED
;
1005 // Check if Fixed MTRR
1007 Status
= RETURN_SUCCESS
;
1008 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
1009 PreMtrrChange (&MtrrContext
);
1010 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
1011 PostMtrrChange (&MtrrContext
);
1012 if (RETURN_ERROR (Status
)) {
1019 // A Length of 0 can only make sense for fixed MTTR ranges.
1020 // Since we just handled the fixed MTRRs, we can skip the
1021 // variable MTRR section.
1027 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1028 // we can set the base to 0 to save variable MTRRs.
1030 if (BaseAddress
== BASE_1MB
) {
1036 // Check for overlap
1038 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1039 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1041 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1042 if (RETURN_ERROR (Status
)) {
1048 // Combined successfully, invalidate the now-unused MTRRs
1050 InvalidateMtrr(VariableMtrr
);
1051 Status
= RETURN_SUCCESS
;
1057 // The memory type is the same with the type specified by
1058 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1060 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryType ())) {
1062 // Invalidate the now-unused MTRRs
1064 InvalidateMtrr(VariableMtrr
);
1068 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1070 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1071 Status
= RETURN_OUT_OF_RESOURCES
;
1076 // Invalidate the now-unused MTRRs
1078 InvalidateMtrr(VariableMtrr
);
1081 // Find first unused MTRR
1083 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1084 MsrNum
< VariableMtrrEnd
;
1087 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1092 if (BaseAddress
!= 0) {
1095 // Calculate the alignment of the base address.
1097 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1099 if (Alignment
> Length
) {
1106 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1107 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1112 ProgramVariableMtrr (
1117 MtrrValidAddressMask
1119 BaseAddress
+= Alignment
;
1120 Length
-= Alignment
;
1131 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1136 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1137 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1142 ProgramVariableMtrr (
1147 MtrrValidAddressMask
1149 BaseAddress
+= Length
;
1150 TempQword
= Length
- TempQword
;
1151 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1158 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1159 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1164 Length
= Power2MaxMemory (TempQword
);
1166 BaseAddress
-= Length
;
1169 ProgramVariableMtrr (
1174 MtrrValidAddressMask
1178 BaseAddress
+= Length
;
1180 TempQword
-= Length
;
1182 } while (TempQword
> 0);
1185 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1186 if (!RETURN_ERROR (Status
)) {
1187 MtrrDebugPrintAllMtrrs ();
1195 This function will get the memory cache type of the specific address.
1197 This function is mainly for debug purpose.
1199 @param Address The specific address
1201 @return Memory cache type of the sepcific address
1204 MTRR_MEMORY_CACHE_TYPE
1206 MtrrGetMemoryAttribute (
1207 IN PHYSICAL_ADDRESS Address
1214 UINT64 TempMtrrType
;
1215 MTRR_MEMORY_CACHE_TYPE CacheType
;
1216 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1217 UINT64 MtrrValidBitsMask
;
1218 UINT64 MtrrValidAddressMask
;
1219 UINTN VariableMtrrCount
;
1221 if (!IsMtrrSupported ()) {
1222 return CacheUncacheable
;
1226 // Check if MTRR is enabled, if not, return UC as attribute
1228 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1229 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1231 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1232 return CacheUncacheable
;
1236 // If address is less than 1M, then try to go through the fixed MTRR
1238 if (Address
< BASE_1MB
) {
1239 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1241 // Go through the fixed MTRR
1243 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1244 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1246 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1247 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1251 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1252 mMtrrLibFixedMtrrTable
[Index
].Length
;
1253 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1254 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1255 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1260 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1261 MtrrGetMemoryAttributeInVariableMtrr(
1263 MtrrValidAddressMask
,
1268 // Go through the variable MTRR
1270 VariableMtrrCount
= GetVariableMtrrCount ();
1271 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1273 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1274 if (VariableMtrr
[Index
].Valid
) {
1275 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1276 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1277 TempMtrrType
= VariableMtrr
[Index
].Type
;
1278 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1282 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1289 This function will get the raw value in variable MTRRs
1291 @param VariableSettings A buffer to hold variable MTRRs content.
1293 @return The VariableSettings input pointer
1296 MTRR_VARIABLE_SETTINGS
*
1298 MtrrGetVariableMtrr (
1299 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1303 UINT32 VariableMtrrCount
;
1305 if (!IsMtrrSupported ()) {
1306 return VariableSettings
;
1309 VariableMtrrCount
= GetVariableMtrrCount ();
1310 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1312 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1313 VariableSettings
->Mtrr
[Index
].Base
=
1314 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1315 VariableSettings
->Mtrr
[Index
].Mask
=
1316 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1319 return VariableSettings
;
1324 Worker function setting variable MTRRs
1326 @param VariableSettings A buffer to hold variable MTRRs content.
1330 MtrrSetVariableMtrrWorker (
1331 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1335 UINT32 VariableMtrrCount
;
1337 VariableMtrrCount
= GetVariableMtrrCount ();
1338 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1340 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1342 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1343 VariableSettings
->Mtrr
[Index
].Base
1346 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1347 VariableSettings
->Mtrr
[Index
].Mask
1354 This function sets variable MTRRs
1356 @param VariableSettings A buffer to hold variable MTRRs content.
1358 @return The pointer of VariableSettings
1361 MTRR_VARIABLE_SETTINGS
*
1363 MtrrSetVariableMtrr (
1364 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1367 MTRR_CONTEXT MtrrContext
;
1369 if (!IsMtrrSupported ()) {
1370 return VariableSettings
;
1373 PreMtrrChange (&MtrrContext
);
1374 MtrrSetVariableMtrrWorker (VariableSettings
);
1375 PostMtrrChange (&MtrrContext
);
1376 return VariableSettings
;
1381 This function gets the content in fixed MTRRs
1383 @param FixedSettings A buffer to hold fixed Mtrrs content.
1385 @retval The pointer of FixedSettings
1388 MTRR_FIXED_SETTINGS
*
1391 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1396 if (!IsMtrrSupported ()) {
1397 return FixedSettings
;
1400 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1401 FixedSettings
->Mtrr
[Index
] =
1402 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1405 return FixedSettings
;
1409 Worker function setting fixed MTRRs
1411 @param FixedSettings A buffer to hold fixed Mtrrs content.
1415 MtrrSetFixedMtrrWorker (
1416 IN MTRR_FIXED_SETTINGS
*FixedSettings
1421 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1423 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1424 FixedSettings
->Mtrr
[Index
]
1431 This function sets fixed MTRRs
1433 @param FixedSettings A buffer to hold fixed Mtrrs content.
1435 @retval The pointer of FixedSettings
1438 MTRR_FIXED_SETTINGS
*
1441 IN MTRR_FIXED_SETTINGS
*FixedSettings
1444 MTRR_CONTEXT MtrrContext
;
1446 if (!IsMtrrSupported ()) {
1447 return FixedSettings
;
1450 PreMtrrChange (&MtrrContext
);
1451 MtrrSetFixedMtrrWorker (FixedSettings
);
1452 PostMtrrChange (&MtrrContext
);
1454 return FixedSettings
;
1459 This function gets the content in all MTRRs (variable and fixed)
1461 @param MtrrSetting A buffer to hold all Mtrrs content.
1463 @retval the pointer of MtrrSetting
1469 OUT MTRR_SETTINGS
*MtrrSetting
1472 if (!IsMtrrSupported ()) {
1479 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1482 // Get variable MTRRs
1484 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1487 // Get MTRR_DEF_TYPE value
1489 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1496 This function sets all MTRRs (variable and fixed)
1498 @param MtrrSetting A buffer holding all MTRRs content.
1500 @retval The pointer of MtrrSetting
1506 IN MTRR_SETTINGS
*MtrrSetting
1509 MTRR_CONTEXT MtrrContext
;
1511 if (!IsMtrrSupported ()) {
1515 PreMtrrChange (&MtrrContext
);
1520 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1523 // Set variable MTRRs
1525 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1528 // Set MTRR_DEF_TYPE value
1530 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1532 PostMtrrChangeEnableCache (&MtrrContext
);
1538 This function prints all MTRRs for debugging.
1542 MtrrDebugPrintAllMtrrs (
1547 MTRR_SETTINGS MtrrSettings
;
1550 UINTN VariableMtrrCount
;
1558 UINT64 NoRangeLimit
;
1561 UINTN PreviousMemoryType
;
1564 if (!IsMtrrSupported ()) {
1568 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1569 DEBUG((DEBUG_CACHE
, "=============\n"));
1571 MtrrGetAllMtrrs (&MtrrSettings
);
1572 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1573 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1574 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1577 VariableMtrrCount
= GetVariableMtrrCount ();
1578 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1579 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1581 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1582 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1585 DEBUG((DEBUG_CACHE
, "\n"));
1586 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1587 DEBUG((DEBUG_CACHE
, "====================================\n"));
1590 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1591 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1592 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1593 for (Index1
= 0; Index1
< 8; Index1
++) {
1594 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1595 if (MemoryType
> CacheWriteBack
) {
1596 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1598 if (MemoryType
!= PreviousMemoryType
) {
1599 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1600 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1602 PreviousMemoryType
= MemoryType
;
1603 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1605 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1608 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1610 VariableMtrrCount
= GetVariableMtrrCount ();
1613 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1614 if (RegEax
>= 0x80000008) {
1615 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1616 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1619 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1621 MemoryType
= MtrrGetMemoryAttribute (Base
);
1622 if (MemoryType
> CacheWriteBack
) {
1623 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1626 if (MemoryType
!= PreviousMemoryType
) {
1627 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1628 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1630 PreviousMemoryType
= MemoryType
;
1631 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1634 RangeBase
= BASE_1MB
;
1635 NoRangeBase
= BASE_1MB
;
1637 NoRangeLimit
= Limit
;
1639 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1640 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1642 // If mask is not valid, then do not display range
1646 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1647 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1649 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1653 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1654 RangeBase
= MtrrBase
;
1656 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1657 RangeBase
= MtrrLimit
+ 1;
1659 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1660 RangeLimit
= MtrrBase
- 1;
1662 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1663 RangeLimit
= MtrrLimit
;
1666 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1667 NoRangeBase
= MtrrLimit
+ 1;
1669 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1670 NoRangeLimit
= MtrrBase
- 1;
1675 Base
= RangeLimit
+ 1;
1677 Base
= NoRangeLimit
+ 1;
1679 } while (Base
< Limit
);
1680 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1685 Checks if MTRR is supported.
1687 @retval TRUE MTRR is supported.
1688 @retval FALSE MTRR is not supported.
1701 // Check CPUID(1).EDX[12] for MTRR capability
1703 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1704 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1709 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1710 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1711 // exist, return false.
1713 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1714 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {