4 Copyright (c) 2008 - 2015, 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
;
143 UINT32 ReservedMtrrNumber
;
145 VariableMtrrCount
= GetVariableMtrrCount ();
146 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
147 if (VariableMtrrCount
< ReservedMtrrNumber
) {
151 return VariableMtrrCount
- ReservedMtrrNumber
;
155 Returns the default MTRR cache type for the system.
157 @return The default MTRR cache type.
160 MTRR_MEMORY_CACHE_TYPE
162 MtrrGetDefaultMemoryType (
166 if (!IsMtrrSupported ()) {
167 return CacheUncacheable
;
170 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
174 Preparation before programming MTRR.
176 This function will do some preparation for programming MTRRs:
177 disable cache, invalid cache and disable MTRR caching functionality
179 @param[out] MtrrContext Pointer to context to save
184 OUT MTRR_CONTEXT
*MtrrContext
188 // Disable interrupts and save current interrupt state
190 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
193 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
198 // Save original CR4 value and clear PGE flag (Bit 7)
200 MtrrContext
->Cr4
= AsmReadCr4 ();
201 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
211 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
215 Cleaning up after programming MTRRs.
217 This function will do some clean up after programming MTRRs:
218 Flush all TLBs, re-enable caching, restore CR4.
220 @param[in] MtrrContext Pointer to context to restore
224 PostMtrrChangeEnableCache (
225 IN MTRR_CONTEXT
*MtrrContext
234 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
239 // Restore original CR4 value
241 AsmWriteCr4 (MtrrContext
->Cr4
);
244 // Restore original interrupt state
246 SetInterruptState (MtrrContext
->InterruptState
);
250 Cleaning up after programming MTRRs.
252 This function will do some clean up after programming MTRRs:
253 enable MTRR caching functionality, and enable cache
255 @param[in] MtrrContext Pointer to context to restore
260 IN MTRR_CONTEXT
*MtrrContext
266 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
268 PostMtrrChangeEnableCache (MtrrContext
);
273 Programs fixed MTRRs registers.
275 @param[in] MemoryCacheType The memory type to set.
276 @param[in, out] Base The base address of memory range.
277 @param[in, out] Length The length of memory range.
279 @retval RETURN_SUCCESS The cache type was updated successfully
280 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
286 IN UINT64 MemoryCacheType
,
288 IN OUT UINT64
*Length
301 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
302 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
305 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
306 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
314 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
315 return RETURN_UNSUPPORTED
;
319 // We found the fixed MTRR to be programmed
321 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
324 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
325 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
332 if (ByteShift
== 8) {
333 return RETURN_UNSUPPORTED
;
338 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
341 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
342 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
343 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
344 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
347 if (ByteShift
< 8 && (*Length
!= 0)) {
348 return RETURN_UNSUPPORTED
;
352 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
353 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
354 return RETURN_SUCCESS
;
359 Gets the attribute of variable MTRRs.
361 This function shadows the content of variable MTRRs into an
362 internal array: VariableMtrr.
364 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
365 @param[in] MtrrValidAddressMask The valid address mask for MTRR
366 @param[out] VariableMtrr The array to shadow variable MTRRs content
368 @return The return value of this paramter indicates the
369 number of MTRRs which has been used.
374 MtrrGetMemoryAttributeInVariableMtrr (
375 IN UINT64 MtrrValidBitsMask
,
376 IN UINT64 MtrrValidAddressMask
,
377 OUT VARIABLE_MTRR
*VariableMtrr
383 UINT32 FirmwareVariableMtrrCount
;
384 UINT32 VariableMtrrEnd
;
386 if (!IsMtrrSupported ()) {
390 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
391 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
393 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
396 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
398 (MsrNum
< VariableMtrrEnd
) &&
399 (Index
< FirmwareVariableMtrrCount
)
403 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
404 VariableMtrr
[Index
].Msr
= MsrNum
;
405 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
406 MtrrValidAddressMask
);
407 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
408 MtrrValidAddressMask
)
412 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
413 VariableMtrr
[Index
].Valid
= TRUE
;
414 VariableMtrr
[Index
].Used
= TRUE
;
415 UsedMtrr
= UsedMtrr
+ 1;
424 Checks overlap between given memory range and MTRRs.
426 @param[in] Start The start address of memory range.
427 @param[in] End The end address of memory range.
428 @param[in] VariableMtrr The array to shadow variable MTRRs content
430 @retval TRUE Overlap exists.
431 @retval FALSE No overlap.
435 CheckMemoryAttributeOverlap (
436 IN PHYSICAL_ADDRESS Start
,
437 IN PHYSICAL_ADDRESS End
,
438 IN VARIABLE_MTRR
*VariableMtrr
443 for (Index
= 0; Index
< 6; Index
++) {
445 VariableMtrr
[Index
].Valid
&&
447 (Start
> (VariableMtrr
[Index
].BaseAddress
+
448 VariableMtrr
[Index
].Length
- 1)
450 (End
< VariableMtrr
[Index
].BaseAddress
)
462 Marks a variable MTRR as non-valid.
464 @param[in] Index The index of the array VariableMtrr to be invalidated
465 @param[in] VariableMtrr The array to shadow variable MTRRs content
466 @param[out] UsedMtrr The number of MTRRs which has already been used
470 InvalidateShadowMtrr (
472 IN VARIABLE_MTRR
*VariableMtrr
,
476 VariableMtrr
[Index
].Valid
= FALSE
;
477 *UsedMtrr
= *UsedMtrr
- 1;
482 Combines memory attributes.
484 If overlap exists between given memory range and MTRRs, try to combine them.
486 @param[in] Attributes The memory type to set.
487 @param[in, out] Base The base address of memory range.
488 @param[in, out] Length The length of memory range.
489 @param[in] VariableMtrr The array to shadow variable MTRRs content
490 @param[in, out] UsedMtrr The number of MTRRs which has already been used
491 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
493 @retval EFI_SUCCESS Memory region successfully combined.
494 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
498 CombineMemoryAttribute (
499 IN UINT64 Attributes
,
501 IN OUT UINT64
*Length
,
502 IN VARIABLE_MTRR
*VariableMtrr
,
503 IN OUT UINT32
*UsedMtrr
,
504 OUT BOOLEAN
*OverwriteExistingMtrr
512 UINT32 FirmwareVariableMtrrCount
;
513 BOOLEAN CoveredByExistingMtrr
;
515 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
517 *OverwriteExistingMtrr
= FALSE
;
518 CoveredByExistingMtrr
= FALSE
;
519 EndAddress
= *Base
+*Length
- 1;
521 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
523 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
525 !VariableMtrr
[Index
].Valid
||
528 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
535 // Combine same attribute MTRR range
537 if (Attributes
== VariableMtrr
[Index
].Type
) {
539 // if the MTRR range contain the request range, set a flag, then continue to
540 // invalidate any MTRR of the same request range with higher priority cache type.
542 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
543 CoveredByExistingMtrr
= TRUE
;
547 // invalid this MTRR, and program the combine range
550 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
552 VariableMtrr
[Index
].BaseAddress
;
553 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
556 // Record the MTRR usage status in VariableMtrr array.
558 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
559 *Base
= CombineStart
;
560 *Length
= CombineEnd
- CombineStart
+ 1;
561 EndAddress
= CombineEnd
;
562 *OverwriteExistingMtrr
= TRUE
;
566 // The cache type is different, but the range is convered by one MTRR
568 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
569 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
575 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
576 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
577 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
578 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
579 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
580 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
582 *OverwriteExistingMtrr
= TRUE
;
586 // Other type memory overlap is invalid
588 return RETURN_ACCESS_DENIED
;
591 if (CoveredByExistingMtrr
) {
595 return RETURN_SUCCESS
;
600 Calculates the maximum value which is a power of 2, but less the MemoryLength.
602 @param[in] MemoryLength The number to pass in.
604 @return The maximum value which is align to power of 2 and less the MemoryLength
609 IN UINT64 MemoryLength
614 if (RShiftU64 (MemoryLength
, 32) != 0) {
616 (UINT64
) GetPowerOfTwo32 (
617 (UINT32
) RShiftU64 (MemoryLength
, 32)
622 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
630 Determines the MTRR numbers used to program a memory range.
632 This function first checks the alignment of the base address.
633 If the alignment of the base address <= Length, cover the memory range
634 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
635 Length -= alignment. Repeat the step until alignment > Length.
637 Then this function determines which direction of programming the variable
638 MTRRs for the remaining length will use fewer MTRRs.
640 @param[in] BaseAddress Length of Memory to program MTRR
641 @param[in] Length Length of Memory to program MTRR
642 @param[in] MtrrNumber Pointer to the number of necessary MTRRs
644 @retval TRUE Positive direction is better.
645 FALSE Negative direction is better.
649 GetMtrrNumberAndDirection (
650 IN UINT64 BaseAddress
,
662 if (BaseAddress
!= 0) {
665 // Calculate the alignment of the base address.
667 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
669 if (Alignment
> Length
) {
674 BaseAddress
+= Alignment
;
688 TempQword
-= Power2MaxMemory (TempQword
);
690 } while (TempQword
!= 0);
692 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
695 TempQword
-= Power2MaxMemory (TempQword
);
697 } while (TempQword
!= 0);
699 if (Positive
<= Subtractive
) {
700 *MtrrNumber
+= Positive
;
703 *MtrrNumber
+= Subtractive
;
709 Invalid variable MTRRs according to the value in the shadow array.
711 This function programs MTRRs according to the values specified
714 @param[in, out] VariableMtrr Shadow of variable MTRR contents
719 IN OUT VARIABLE_MTRR
*VariableMtrr
723 UINTN VariableMtrrCount
;
724 MTRR_CONTEXT MtrrContext
;
726 PreMtrrChange (&MtrrContext
);
728 VariableMtrrCount
= GetVariableMtrrCount ();
729 while (Index
< VariableMtrrCount
) {
730 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
731 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
732 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
733 VariableMtrr
[Index
].Used
= FALSE
;
737 PostMtrrChange (&MtrrContext
);
742 Programs variable MTRRs
744 This function programs variable MTRRs
746 @param[in] MtrrNumber Index of MTRR to program.
747 @param[in] BaseAddress Base address of memory region.
748 @param[in] Length Length of memory region.
749 @param[in] MemoryCacheType Memory type to set.
750 @param[in] MtrrValidAddressMask The valid address mask for MTRR
754 ProgramVariableMtrr (
756 IN PHYSICAL_ADDRESS BaseAddress
,
758 IN UINT64 MemoryCacheType
,
759 IN UINT64 MtrrValidAddressMask
763 MTRR_CONTEXT MtrrContext
;
765 PreMtrrChange (&MtrrContext
);
768 // MTRR Physical Base
770 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
771 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
774 // MTRR Physical Mask
776 TempQword
= ~(Length
- 1);
778 (UINT32
) (MtrrNumber
+ 1),
779 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
782 PostMtrrChange (&MtrrContext
);
787 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
789 @param[in] MtrrType MTRR memory type
791 @return The enum item in MTRR_MEMORY_CACHE_TYPE
794 MTRR_MEMORY_CACHE_TYPE
795 GetMemoryCacheTypeFromMtrrType (
800 case MTRR_CACHE_UNCACHEABLE
:
801 return CacheUncacheable
;
802 case MTRR_CACHE_WRITE_COMBINING
:
803 return CacheWriteCombining
;
804 case MTRR_CACHE_WRITE_THROUGH
:
805 return CacheWriteThrough
;
806 case MTRR_CACHE_WRITE_PROTECTED
:
807 return CacheWriteProtected
;
808 case MTRR_CACHE_WRITE_BACK
:
809 return CacheWriteBack
;
812 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
813 // no MTRR covers the range
815 return MtrrGetDefaultMemoryType ();
820 Initializes the valid bits mask and valid address mask for MTRRs.
822 This function initializes the valid bits mask and valid address mask for MTRRs.
824 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
825 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
829 MtrrLibInitializeMtrrMask (
830 OUT UINT64
*MtrrValidBitsMask
,
831 OUT UINT64
*MtrrValidAddressMask
835 UINT8 PhysicalAddressBits
;
837 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
839 if (RegEax
>= 0x80000008) {
840 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
842 PhysicalAddressBits
= (UINT8
) RegEax
;
844 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
845 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
847 *MtrrValidBitsMask
= MTRR_LIB_MSR_VALID_MASK
;
848 *MtrrValidAddressMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
854 Determines the real attribute of a memory range.
856 This function is to arbitrate the real attribute of the memory when
857 there are 2 MTRRs covers the same memory range. For further details,
858 please refer the IA32 Software Developer's Manual, Volume 3,
861 @param[in] MtrrType1 The first kind of Memory type
862 @param[in] MtrrType2 The second kind of memory type
873 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
875 case MTRR_CACHE_UNCACHEABLE
:
876 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
878 case MTRR_CACHE_WRITE_COMBINING
:
880 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
881 MtrrType2
==MTRR_CACHE_UNCACHEABLE
883 MtrrType
= MtrrType2
;
886 case MTRR_CACHE_WRITE_THROUGH
:
888 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
889 MtrrType2
==MTRR_CACHE_WRITE_BACK
891 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
892 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
893 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
896 case MTRR_CACHE_WRITE_PROTECTED
:
897 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
898 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
899 MtrrType
= MtrrType2
;
902 case MTRR_CACHE_WRITE_BACK
:
904 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
905 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
906 MtrrType2
== MTRR_CACHE_WRITE_BACK
908 MtrrType
= MtrrType2
;
911 case MTRR_CACHE_INVALID_TYPE
:
912 MtrrType
= MtrrType2
;
918 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
919 MtrrType
= MtrrType1
;
926 This function attempts to set the attributes for a memory range.
928 @param[in] BaseAddress The physical address that is the start
929 address of a memory region.
930 @param[in] Length The size in bytes of the memory region.
931 @param[in] Attribute The bit mask of attributes to set for the
934 @retval RETURN_SUCCESS The attributes were set for the memory
936 @retval RETURN_INVALID_PARAMETER Length is zero.
937 @retval RETURN_UNSUPPORTED The processor does not support one or
938 more bytes of the memory resource range
939 specified by BaseAddress and Length.
940 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
941 for the memory resource range specified
942 by BaseAddress and Length.
943 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
944 range specified by BaseAddress and Length
946 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
947 modify the attributes of the memory
953 MtrrSetMemoryAttribute (
954 IN PHYSICAL_ADDRESS BaseAddress
,
956 IN MTRR_MEMORY_CACHE_TYPE Attribute
960 RETURN_STATUS Status
;
967 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
969 UINT64 MtrrValidBitsMask
;
970 UINT64 MtrrValidAddressMask
;
971 BOOLEAN OverwriteExistingMtrr
;
972 UINT32 FirmwareVariableMtrrCount
;
973 UINT32 VariableMtrrEnd
;
974 MTRR_CONTEXT MtrrContext
;
976 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
978 if (!IsMtrrSupported ()) {
979 Status
= RETURN_UNSUPPORTED
;
983 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
984 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
986 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
989 MemoryType
= (UINT64
)Attribute
;
990 OverwriteExistingMtrr
= FALSE
;
993 // Check for an invalid parameter
996 Status
= RETURN_INVALID_PARAMETER
;
1001 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
1002 (Length
& ~MtrrValidAddressMask
) != 0
1004 Status
= RETURN_UNSUPPORTED
;
1009 // Check if Fixed MTRR
1011 Status
= RETURN_SUCCESS
;
1012 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
1013 PreMtrrChange (&MtrrContext
);
1014 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
1015 PostMtrrChange (&MtrrContext
);
1016 if (RETURN_ERROR (Status
)) {
1023 // A Length of 0 can only make sense for fixed MTTR ranges.
1024 // Since we just handled the fixed MTRRs, we can skip the
1025 // variable MTRR section.
1031 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1032 // we can set the base to 0 to save variable MTRRs.
1034 if (BaseAddress
== BASE_1MB
) {
1040 // Check for overlap
1042 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1043 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1045 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1046 if (RETURN_ERROR (Status
)) {
1052 // Combined successfully, invalidate the now-unused MTRRs
1054 InvalidateMtrr(VariableMtrr
);
1055 Status
= RETURN_SUCCESS
;
1061 // The memory type is the same with the type specified by
1062 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1064 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryType ())) {
1066 // Invalidate the now-unused MTRRs
1068 InvalidateMtrr(VariableMtrr
);
1072 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1074 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1075 Status
= RETURN_OUT_OF_RESOURCES
;
1080 // Invalidate the now-unused MTRRs
1082 InvalidateMtrr(VariableMtrr
);
1085 // Find first unused MTRR
1087 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1088 MsrNum
< VariableMtrrEnd
;
1091 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1096 if (BaseAddress
!= 0) {
1099 // Calculate the alignment of the base address.
1101 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1103 if (Alignment
> Length
) {
1110 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1111 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1116 ProgramVariableMtrr (
1121 MtrrValidAddressMask
1123 BaseAddress
+= Alignment
;
1124 Length
-= Alignment
;
1135 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1140 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1141 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1146 ProgramVariableMtrr (
1151 MtrrValidAddressMask
1153 BaseAddress
+= Length
;
1154 TempQword
= Length
- TempQword
;
1155 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1162 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1163 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1168 Length
= Power2MaxMemory (TempQword
);
1170 BaseAddress
-= Length
;
1173 ProgramVariableMtrr (
1178 MtrrValidAddressMask
1182 BaseAddress
+= Length
;
1184 TempQword
-= Length
;
1186 } while (TempQword
> 0);
1189 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1190 if (!RETURN_ERROR (Status
)) {
1191 MtrrDebugPrintAllMtrrs ();
1199 This function will get the memory cache type of the specific address.
1201 This function is mainly for debug purpose.
1203 @param[in] Address The specific address
1205 @return Memory cache type of the specific address
1208 MTRR_MEMORY_CACHE_TYPE
1210 MtrrGetMemoryAttribute (
1211 IN PHYSICAL_ADDRESS Address
1218 UINT64 TempMtrrType
;
1219 MTRR_MEMORY_CACHE_TYPE CacheType
;
1220 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1221 UINT64 MtrrValidBitsMask
;
1222 UINT64 MtrrValidAddressMask
;
1223 UINTN VariableMtrrCount
;
1225 if (!IsMtrrSupported ()) {
1226 return CacheUncacheable
;
1230 // Check if MTRR is enabled, if not, return UC as attribute
1232 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1233 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1235 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1236 return CacheUncacheable
;
1240 // If address is less than 1M, then try to go through the fixed MTRR
1242 if (Address
< BASE_1MB
) {
1243 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1245 // Go through the fixed MTRR
1247 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1248 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1250 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1251 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1255 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1256 mMtrrLibFixedMtrrTable
[Index
].Length
;
1257 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1258 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1259 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1264 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1265 MtrrGetMemoryAttributeInVariableMtrr(
1267 MtrrValidAddressMask
,
1272 // Go through the variable MTRR
1274 VariableMtrrCount
= GetVariableMtrrCount ();
1275 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1277 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1278 if (VariableMtrr
[Index
].Valid
) {
1279 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1280 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1281 TempMtrrType
= VariableMtrr
[Index
].Type
;
1282 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1286 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1293 This function will get the raw value in variable MTRRs
1295 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
1297 @return The VariableSettings input pointer
1300 MTRR_VARIABLE_SETTINGS
*
1302 MtrrGetVariableMtrr (
1303 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1307 UINT32 VariableMtrrCount
;
1309 if (!IsMtrrSupported ()) {
1310 return VariableSettings
;
1313 VariableMtrrCount
= GetVariableMtrrCount ();
1314 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1316 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1317 VariableSettings
->Mtrr
[Index
].Base
=
1318 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1319 VariableSettings
->Mtrr
[Index
].Mask
=
1320 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1323 return VariableSettings
;
1328 Worker function setting variable MTRRs
1330 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1334 MtrrSetVariableMtrrWorker (
1335 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1339 UINT32 VariableMtrrCount
;
1341 VariableMtrrCount
= GetVariableMtrrCount ();
1342 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1344 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1346 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1347 VariableSettings
->Mtrr
[Index
].Base
1350 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1351 VariableSettings
->Mtrr
[Index
].Mask
1358 This function sets variable MTRRs
1360 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1362 @return The pointer of VariableSettings
1365 MTRR_VARIABLE_SETTINGS
*
1367 MtrrSetVariableMtrr (
1368 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1371 MTRR_CONTEXT MtrrContext
;
1373 if (!IsMtrrSupported ()) {
1374 return VariableSettings
;
1377 PreMtrrChange (&MtrrContext
);
1378 MtrrSetVariableMtrrWorker (VariableSettings
);
1379 PostMtrrChange (&MtrrContext
);
1380 return VariableSettings
;
1385 This function gets the content in fixed MTRRs
1387 @param[out] FixedSettings A buffer to hold fixed Mtrrs content.
1389 @retval The pointer of FixedSettings
1392 MTRR_FIXED_SETTINGS
*
1395 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1400 if (!IsMtrrSupported ()) {
1401 return FixedSettings
;
1404 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1405 FixedSettings
->Mtrr
[Index
] =
1406 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1409 return FixedSettings
;
1413 Worker function setting fixed MTRRs
1415 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.
1419 MtrrSetFixedMtrrWorker (
1420 IN MTRR_FIXED_SETTINGS
*FixedSettings
1425 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1427 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1428 FixedSettings
->Mtrr
[Index
]
1435 This function sets fixed MTRRs
1437 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.
1439 @retval The pointer of FixedSettings
1442 MTRR_FIXED_SETTINGS
*
1445 IN MTRR_FIXED_SETTINGS
*FixedSettings
1448 MTRR_CONTEXT MtrrContext
;
1450 if (!IsMtrrSupported ()) {
1451 return FixedSettings
;
1454 PreMtrrChange (&MtrrContext
);
1455 MtrrSetFixedMtrrWorker (FixedSettings
);
1456 PostMtrrChange (&MtrrContext
);
1458 return FixedSettings
;
1463 This function gets the content in all MTRRs (variable and fixed)
1465 @param[out] MtrrSetting A buffer to hold all Mtrrs content.
1467 @retval the pointer of MtrrSetting
1473 OUT MTRR_SETTINGS
*MtrrSetting
1476 if (!IsMtrrSupported ()) {
1483 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1486 // Get variable MTRRs
1488 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1491 // Get MTRR_DEF_TYPE value
1493 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1500 This function sets all MTRRs (variable and fixed)
1502 @param[in] MtrrSetting A buffer holding all MTRRs content.
1504 @retval The pointer of MtrrSetting
1510 IN MTRR_SETTINGS
*MtrrSetting
1513 MTRR_CONTEXT MtrrContext
;
1515 if (!IsMtrrSupported ()) {
1519 PreMtrrChange (&MtrrContext
);
1524 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1527 // Set variable MTRRs
1529 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1532 // Set MTRR_DEF_TYPE value
1534 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1536 PostMtrrChangeEnableCache (&MtrrContext
);
1542 This function prints all MTRRs for debugging.
1546 MtrrDebugPrintAllMtrrs (
1551 MTRR_SETTINGS MtrrSettings
;
1554 UINTN VariableMtrrCount
;
1562 UINT64 NoRangeLimit
;
1565 UINTN PreviousMemoryType
;
1568 if (!IsMtrrSupported ()) {
1572 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1573 DEBUG((DEBUG_CACHE
, "=============\n"));
1575 MtrrGetAllMtrrs (&MtrrSettings
);
1576 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1577 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1578 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1581 VariableMtrrCount
= GetVariableMtrrCount ();
1582 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1583 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1585 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1586 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1589 DEBUG((DEBUG_CACHE
, "\n"));
1590 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1591 DEBUG((DEBUG_CACHE
, "====================================\n"));
1594 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1595 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1596 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1597 for (Index1
= 0; Index1
< 8; Index1
++) {
1598 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1599 if (MemoryType
> CacheWriteBack
) {
1600 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1602 if (MemoryType
!= PreviousMemoryType
) {
1603 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1604 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1606 PreviousMemoryType
= MemoryType
;
1607 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1609 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1612 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1614 VariableMtrrCount
= GetVariableMtrrCount ();
1617 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1618 if (RegEax
>= 0x80000008) {
1619 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1620 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1623 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1625 MemoryType
= MtrrGetMemoryAttribute (Base
);
1626 if (MemoryType
> CacheWriteBack
) {
1627 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1630 if (MemoryType
!= PreviousMemoryType
) {
1631 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1632 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1634 PreviousMemoryType
= MemoryType
;
1635 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1638 RangeBase
= BASE_1MB
;
1639 NoRangeBase
= BASE_1MB
;
1641 NoRangeLimit
= Limit
;
1643 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1644 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1646 // If mask is not valid, then do not display range
1650 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1651 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1653 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1657 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1658 RangeBase
= MtrrBase
;
1660 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1661 RangeBase
= MtrrLimit
+ 1;
1663 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1664 RangeLimit
= MtrrBase
- 1;
1666 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1667 RangeLimit
= MtrrLimit
;
1670 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1671 NoRangeBase
= MtrrLimit
+ 1;
1673 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1674 NoRangeLimit
= MtrrBase
- 1;
1679 Base
= RangeLimit
+ 1;
1681 Base
= NoRangeLimit
+ 1;
1683 } while (Base
< Limit
);
1684 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1689 Checks if MTRR is supported.
1691 @retval TRUE MTRR is supported.
1692 @retval FALSE MTRR is not supported.
1705 // Check CPUID(1).EDX[12] for MTRR capability
1707 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1708 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1713 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1714 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1715 // exist, return false.
1717 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1718 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {