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 Worker function returns the variable MTRR count for the CPU.
109 @return Variable MTRR count
113 GetVariableMtrrCountWorker (
117 UINT32 VariableMtrrCount
;
119 VariableMtrrCount
= (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
120 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
121 return VariableMtrrCount
;
125 Returns the variable MTRR count for the CPU.
127 @return Variable MTRR count
132 GetVariableMtrrCount (
136 if (!IsMtrrSupported ()) {
139 return GetVariableMtrrCountWorker ();
143 Worker function returns the firmware usable variable MTRR count for the CPU.
145 @return Firmware usable variable MTRR count
149 GetFirmwareVariableMtrrCountWorker (
153 UINT32 VariableMtrrCount
;
154 UINT32 ReservedMtrrNumber
;
156 VariableMtrrCount
= GetVariableMtrrCountWorker ();
157 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
158 if (VariableMtrrCount
< ReservedMtrrNumber
) {
162 return VariableMtrrCount
- ReservedMtrrNumber
;
166 Returns the firmware usable variable MTRR count for the CPU.
168 @return Firmware usable variable MTRR count
173 GetFirmwareVariableMtrrCount (
177 if (!IsMtrrSupported ()) {
180 return GetFirmwareVariableMtrrCountWorker ();
184 Worker function returns the default MTRR cache type for the system.
186 @return The default MTRR cache type.
189 MTRR_MEMORY_CACHE_TYPE
190 MtrrGetDefaultMemoryTypeWorker (
194 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
199 Returns the default MTRR cache type for the system.
201 @return The default MTRR cache type.
204 MTRR_MEMORY_CACHE_TYPE
206 MtrrGetDefaultMemoryType (
210 if (!IsMtrrSupported ()) {
211 return CacheUncacheable
;
213 return MtrrGetDefaultMemoryTypeWorker ();
217 Preparation before programming MTRR.
219 This function will do some preparation for programming MTRRs:
220 disable cache, invalid cache and disable MTRR caching functionality
222 @param[out] MtrrContext Pointer to context to save
227 OUT MTRR_CONTEXT
*MtrrContext
231 // Disable interrupts and save current interrupt state
233 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
236 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
241 // Save original CR4 value and clear PGE flag (Bit 7)
243 MtrrContext
->Cr4
= AsmReadCr4 ();
244 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
254 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
258 Cleaning up after programming MTRRs.
260 This function will do some clean up after programming MTRRs:
261 Flush all TLBs, re-enable caching, restore CR4.
263 @param[in] MtrrContext Pointer to context to restore
267 PostMtrrChangeEnableCache (
268 IN MTRR_CONTEXT
*MtrrContext
277 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
282 // Restore original CR4 value
284 AsmWriteCr4 (MtrrContext
->Cr4
);
287 // Restore original interrupt state
289 SetInterruptState (MtrrContext
->InterruptState
);
293 Cleaning up after programming MTRRs.
295 This function will do some clean up after programming MTRRs:
296 enable MTRR caching functionality, and enable cache
298 @param[in] MtrrContext Pointer to context to restore
303 IN MTRR_CONTEXT
*MtrrContext
309 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
311 PostMtrrChangeEnableCache (MtrrContext
);
316 Programs fixed MTRRs registers.
318 @param[in] MemoryCacheType The memory type to set.
319 @param[in, out] Base The base address of memory range.
320 @param[in, out] Length The length of memory range.
322 @retval RETURN_SUCCESS The cache type was updated successfully
323 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
329 IN UINT64 MemoryCacheType
,
331 IN OUT UINT64
*Length
344 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
345 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
348 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
349 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
357 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
358 return RETURN_UNSUPPORTED
;
362 // We found the fixed MTRR to be programmed
364 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
367 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
368 (ByteShift
* mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
375 if (ByteShift
== 8) {
376 return RETURN_UNSUPPORTED
;
381 ((ByteShift
< 8) && (*Length
>= mMtrrLibFixedMtrrTable
[MsrNum
].Length
));
384 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
385 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
386 *Length
-= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
387 *Base
+= mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
390 if (ByteShift
< 8 && (*Length
!= 0)) {
391 return RETURN_UNSUPPORTED
;
395 (AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
396 AsmWriteMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
397 return RETURN_SUCCESS
;
402 Gets the attribute of variable MTRRs.
404 This function shadows the content of variable MTRRs into an
405 internal array: VariableMtrr.
407 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
408 @param[in] MtrrValidAddressMask The valid address mask for MTRR
409 @param[out] VariableMtrr The array to shadow variable MTRRs content
411 @return The return value of this paramter indicates the
412 number of MTRRs which has been used.
417 MtrrGetMemoryAttributeInVariableMtrr (
418 IN UINT64 MtrrValidBitsMask
,
419 IN UINT64 MtrrValidAddressMask
,
420 OUT VARIABLE_MTRR
*VariableMtrr
426 UINT32 FirmwareVariableMtrrCount
;
427 UINT32 VariableMtrrEnd
;
429 if (!IsMtrrSupported ()) {
433 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
434 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
436 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
439 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
441 (MsrNum
< VariableMtrrEnd
) &&
442 (Index
< FirmwareVariableMtrrCount
)
446 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
447 VariableMtrr
[Index
].Msr
= MsrNum
;
448 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
449 MtrrValidAddressMask
);
450 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
451 MtrrValidAddressMask
)
455 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
456 VariableMtrr
[Index
].Valid
= TRUE
;
457 VariableMtrr
[Index
].Used
= TRUE
;
458 UsedMtrr
= UsedMtrr
+ 1;
467 Checks overlap between given memory range and MTRRs.
469 @param[in] Start The start address of memory range.
470 @param[in] End The end address of memory range.
471 @param[in] VariableMtrr The array to shadow variable MTRRs content
473 @retval TRUE Overlap exists.
474 @retval FALSE No overlap.
478 CheckMemoryAttributeOverlap (
479 IN PHYSICAL_ADDRESS Start
,
480 IN PHYSICAL_ADDRESS End
,
481 IN VARIABLE_MTRR
*VariableMtrr
486 for (Index
= 0; Index
< 6; Index
++) {
488 VariableMtrr
[Index
].Valid
&&
490 (Start
> (VariableMtrr
[Index
].BaseAddress
+
491 VariableMtrr
[Index
].Length
- 1)
493 (End
< VariableMtrr
[Index
].BaseAddress
)
505 Marks a variable MTRR as non-valid.
507 @param[in] Index The index of the array VariableMtrr to be invalidated
508 @param[in] VariableMtrr The array to shadow variable MTRRs content
509 @param[out] UsedMtrr The number of MTRRs which has already been used
513 InvalidateShadowMtrr (
515 IN VARIABLE_MTRR
*VariableMtrr
,
519 VariableMtrr
[Index
].Valid
= FALSE
;
520 *UsedMtrr
= *UsedMtrr
- 1;
525 Combines memory attributes.
527 If overlap exists between given memory range and MTRRs, try to combine them.
529 @param[in] Attributes The memory type to set.
530 @param[in, out] Base The base address of memory range.
531 @param[in, out] Length The length of memory range.
532 @param[in] VariableMtrr The array to shadow variable MTRRs content
533 @param[in, out] UsedMtrr The number of MTRRs which has already been used
534 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
536 @retval EFI_SUCCESS Memory region successfully combined.
537 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
541 CombineMemoryAttribute (
542 IN UINT64 Attributes
,
544 IN OUT UINT64
*Length
,
545 IN VARIABLE_MTRR
*VariableMtrr
,
546 IN OUT UINT32
*UsedMtrr
,
547 OUT BOOLEAN
*OverwriteExistingMtrr
555 UINT32 FirmwareVariableMtrrCount
;
556 BOOLEAN CoveredByExistingMtrr
;
558 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
560 *OverwriteExistingMtrr
= FALSE
;
561 CoveredByExistingMtrr
= FALSE
;
562 EndAddress
= *Base
+*Length
- 1;
564 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
566 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
568 !VariableMtrr
[Index
].Valid
||
571 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
578 // Combine same attribute MTRR range
580 if (Attributes
== VariableMtrr
[Index
].Type
) {
582 // if the MTRR range contain the request range, set a flag, then continue to
583 // invalidate any MTRR of the same request range with higher priority cache type.
585 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
586 CoveredByExistingMtrr
= TRUE
;
590 // invalid this MTRR, and program the combine range
593 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
595 VariableMtrr
[Index
].BaseAddress
;
596 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
599 // Record the MTRR usage status in VariableMtrr array.
601 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
602 *Base
= CombineStart
;
603 *Length
= CombineEnd
- CombineStart
+ 1;
604 EndAddress
= CombineEnd
;
605 *OverwriteExistingMtrr
= TRUE
;
609 // The cache type is different, but the range is convered by one MTRR
611 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
612 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
618 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
619 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
620 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
621 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
622 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
623 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
625 *OverwriteExistingMtrr
= TRUE
;
629 // Other type memory overlap is invalid
631 return RETURN_ACCESS_DENIED
;
634 if (CoveredByExistingMtrr
) {
638 return RETURN_SUCCESS
;
643 Calculates the maximum value which is a power of 2, but less the MemoryLength.
645 @param[in] MemoryLength The number to pass in.
647 @return The maximum value which is align to power of 2 and less the MemoryLength
652 IN UINT64 MemoryLength
657 if (RShiftU64 (MemoryLength
, 32) != 0) {
659 (UINT64
) GetPowerOfTwo32 (
660 (UINT32
) RShiftU64 (MemoryLength
, 32)
665 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
673 Determines the MTRR numbers used to program a memory range.
675 This function first checks the alignment of the base address.
676 If the alignment of the base address <= Length, cover the memory range
677 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
678 Length -= alignment. Repeat the step until alignment > Length.
680 Then this function determines which direction of programming the variable
681 MTRRs for the remaining length will use fewer MTRRs.
683 @param[in] BaseAddress Length of Memory to program MTRR
684 @param[in] Length Length of Memory to program MTRR
685 @param[in] MtrrNumber Pointer to the number of necessary MTRRs
687 @retval TRUE Positive direction is better.
688 FALSE Negative direction is better.
692 GetMtrrNumberAndDirection (
693 IN UINT64 BaseAddress
,
705 if (BaseAddress
!= 0) {
708 // Calculate the alignment of the base address.
710 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
712 if (Alignment
> Length
) {
717 BaseAddress
+= Alignment
;
731 TempQword
-= Power2MaxMemory (TempQword
);
733 } while (TempQword
!= 0);
735 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
738 TempQword
-= Power2MaxMemory (TempQword
);
740 } while (TempQword
!= 0);
742 if (Positive
<= Subtractive
) {
743 *MtrrNumber
+= Positive
;
746 *MtrrNumber
+= Subtractive
;
752 Invalid variable MTRRs according to the value in the shadow array.
754 This function programs MTRRs according to the values specified
757 @param[in, out] VariableMtrr Shadow of variable MTRR contents
762 IN OUT VARIABLE_MTRR
*VariableMtrr
766 UINTN VariableMtrrCount
;
767 MTRR_CONTEXT MtrrContext
;
769 PreMtrrChange (&MtrrContext
);
771 VariableMtrrCount
= GetVariableMtrrCount ();
772 while (Index
< VariableMtrrCount
) {
773 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
774 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
775 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
776 VariableMtrr
[Index
].Used
= FALSE
;
780 PostMtrrChange (&MtrrContext
);
785 Programs variable MTRRs
787 This function programs variable MTRRs
789 @param[in] MtrrNumber Index of MTRR to program.
790 @param[in] BaseAddress Base address of memory region.
791 @param[in] Length Length of memory region.
792 @param[in] MemoryCacheType Memory type to set.
793 @param[in] MtrrValidAddressMask The valid address mask for MTRR
797 ProgramVariableMtrr (
799 IN PHYSICAL_ADDRESS BaseAddress
,
801 IN UINT64 MemoryCacheType
,
802 IN UINT64 MtrrValidAddressMask
806 MTRR_CONTEXT MtrrContext
;
808 PreMtrrChange (&MtrrContext
);
811 // MTRR Physical Base
813 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
814 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
817 // MTRR Physical Mask
819 TempQword
= ~(Length
- 1);
821 (UINT32
) (MtrrNumber
+ 1),
822 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
825 PostMtrrChange (&MtrrContext
);
830 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
832 @param[in] MtrrType MTRR memory type
834 @return The enum item in MTRR_MEMORY_CACHE_TYPE
837 MTRR_MEMORY_CACHE_TYPE
838 GetMemoryCacheTypeFromMtrrType (
843 case MTRR_CACHE_UNCACHEABLE
:
844 return CacheUncacheable
;
845 case MTRR_CACHE_WRITE_COMBINING
:
846 return CacheWriteCombining
;
847 case MTRR_CACHE_WRITE_THROUGH
:
848 return CacheWriteThrough
;
849 case MTRR_CACHE_WRITE_PROTECTED
:
850 return CacheWriteProtected
;
851 case MTRR_CACHE_WRITE_BACK
:
852 return CacheWriteBack
;
855 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
856 // no MTRR covers the range
858 return MtrrGetDefaultMemoryType ();
863 Initializes the valid bits mask and valid address mask for MTRRs.
865 This function initializes the valid bits mask and valid address mask for MTRRs.
867 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
868 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
872 MtrrLibInitializeMtrrMask (
873 OUT UINT64
*MtrrValidBitsMask
,
874 OUT UINT64
*MtrrValidAddressMask
878 UINT8 PhysicalAddressBits
;
880 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
882 if (RegEax
>= 0x80000008) {
883 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
885 PhysicalAddressBits
= (UINT8
) RegEax
;
887 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
888 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
890 *MtrrValidBitsMask
= MTRR_LIB_MSR_VALID_MASK
;
891 *MtrrValidAddressMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
897 Determines the real attribute of a memory range.
899 This function is to arbitrate the real attribute of the memory when
900 there are 2 MTRRs covers the same memory range. For further details,
901 please refer the IA32 Software Developer's Manual, Volume 3,
904 @param[in] MtrrType1 The first kind of Memory type
905 @param[in] MtrrType2 The second kind of memory type
916 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
918 case MTRR_CACHE_UNCACHEABLE
:
919 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
921 case MTRR_CACHE_WRITE_COMBINING
:
923 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
924 MtrrType2
==MTRR_CACHE_UNCACHEABLE
926 MtrrType
= MtrrType2
;
929 case MTRR_CACHE_WRITE_THROUGH
:
931 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
932 MtrrType2
==MTRR_CACHE_WRITE_BACK
934 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
935 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
936 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
939 case MTRR_CACHE_WRITE_PROTECTED
:
940 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
941 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
942 MtrrType
= MtrrType2
;
945 case MTRR_CACHE_WRITE_BACK
:
947 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
948 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
949 MtrrType2
== MTRR_CACHE_WRITE_BACK
951 MtrrType
= MtrrType2
;
954 case MTRR_CACHE_INVALID_TYPE
:
955 MtrrType
= MtrrType2
;
961 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
962 MtrrType
= MtrrType1
;
969 This function attempts to set the attributes for a memory range.
971 @param[in] BaseAddress The physical address that is the start
972 address of a memory region.
973 @param[in] Length The size in bytes of the memory region.
974 @param[in] Attribute The bit mask of attributes to set for the
977 @retval RETURN_SUCCESS The attributes were set for the memory
979 @retval RETURN_INVALID_PARAMETER Length is zero.
980 @retval RETURN_UNSUPPORTED The processor does not support one or
981 more bytes of the memory resource range
982 specified by BaseAddress and Length.
983 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
984 for the memory resource range specified
985 by BaseAddress and Length.
986 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
987 range specified by BaseAddress and Length
989 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
990 modify the attributes of the memory
996 MtrrSetMemoryAttribute (
997 IN PHYSICAL_ADDRESS BaseAddress
,
999 IN MTRR_MEMORY_CACHE_TYPE Attribute
1003 RETURN_STATUS Status
;
1010 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1012 UINT64 MtrrValidBitsMask
;
1013 UINT64 MtrrValidAddressMask
;
1014 BOOLEAN OverwriteExistingMtrr
;
1015 UINT32 FirmwareVariableMtrrCount
;
1016 UINT32 VariableMtrrEnd
;
1017 MTRR_CONTEXT MtrrContext
;
1019 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
1021 if (!IsMtrrSupported ()) {
1022 Status
= RETURN_UNSUPPORTED
;
1026 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
1027 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
1029 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1032 MemoryType
= (UINT64
)Attribute
;
1033 OverwriteExistingMtrr
= FALSE
;
1036 // Check for an invalid parameter
1039 Status
= RETURN_INVALID_PARAMETER
;
1044 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
1045 (Length
& ~MtrrValidAddressMask
) != 0
1047 Status
= RETURN_UNSUPPORTED
;
1052 // Check if Fixed MTRR
1054 Status
= RETURN_SUCCESS
;
1055 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
1056 PreMtrrChange (&MtrrContext
);
1057 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
1058 PostMtrrChange (&MtrrContext
);
1059 if (RETURN_ERROR (Status
)) {
1066 // A Length of 0 can only make sense for fixed MTTR ranges.
1067 // Since we just handled the fixed MTRRs, we can skip the
1068 // variable MTRR section.
1074 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1075 // we can set the base to 0 to save variable MTRRs.
1077 if (BaseAddress
== BASE_1MB
) {
1083 // Check for overlap
1085 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
1086 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
1088 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
1089 if (RETURN_ERROR (Status
)) {
1095 // Combined successfully, invalidate the now-unused MTRRs
1097 InvalidateMtrr(VariableMtrr
);
1098 Status
= RETURN_SUCCESS
;
1104 // The memory type is the same with the type specified by
1105 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1107 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryType ())) {
1109 // Invalidate the now-unused MTRRs
1111 InvalidateMtrr(VariableMtrr
);
1115 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1117 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1118 Status
= RETURN_OUT_OF_RESOURCES
;
1123 // Invalidate the now-unused MTRRs
1125 InvalidateMtrr(VariableMtrr
);
1128 // Find first unused MTRR
1130 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1131 MsrNum
< VariableMtrrEnd
;
1134 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1139 if (BaseAddress
!= 0) {
1142 // Calculate the alignment of the base address.
1144 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1146 if (Alignment
> Length
) {
1153 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1154 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1159 ProgramVariableMtrr (
1164 MtrrValidAddressMask
1166 BaseAddress
+= Alignment
;
1167 Length
-= Alignment
;
1178 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1183 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1184 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1189 ProgramVariableMtrr (
1194 MtrrValidAddressMask
1196 BaseAddress
+= Length
;
1197 TempQword
= Length
- TempQword
;
1198 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1205 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1206 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1211 Length
= Power2MaxMemory (TempQword
);
1213 BaseAddress
-= Length
;
1216 ProgramVariableMtrr (
1221 MtrrValidAddressMask
1225 BaseAddress
+= Length
;
1227 TempQword
-= Length
;
1229 } while (TempQword
> 0);
1232 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1233 if (!RETURN_ERROR (Status
)) {
1234 MtrrDebugPrintAllMtrrs ();
1242 This function will get the memory cache type of the specific address.
1244 This function is mainly for debug purpose.
1246 @param[in] Address The specific address
1248 @return Memory cache type of the specific address
1251 MTRR_MEMORY_CACHE_TYPE
1253 MtrrGetMemoryAttribute (
1254 IN PHYSICAL_ADDRESS Address
1261 UINT64 TempMtrrType
;
1262 MTRR_MEMORY_CACHE_TYPE CacheType
;
1263 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1264 UINT64 MtrrValidBitsMask
;
1265 UINT64 MtrrValidAddressMask
;
1266 UINTN VariableMtrrCount
;
1268 if (!IsMtrrSupported ()) {
1269 return CacheUncacheable
;
1273 // Check if MTRR is enabled, if not, return UC as attribute
1275 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1276 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1278 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1279 return CacheUncacheable
;
1283 // If address is less than 1M, then try to go through the fixed MTRR
1285 if (Address
< BASE_1MB
) {
1286 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1288 // Go through the fixed MTRR
1290 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1291 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1293 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1294 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1298 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1299 mMtrrLibFixedMtrrTable
[Index
].Length
;
1300 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1301 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1302 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1307 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1308 MtrrGetMemoryAttributeInVariableMtrr(
1310 MtrrValidAddressMask
,
1315 // Go through the variable MTRR
1317 VariableMtrrCount
= GetVariableMtrrCount ();
1318 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1320 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1321 if (VariableMtrr
[Index
].Valid
) {
1322 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1323 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1324 TempMtrrType
= VariableMtrr
[Index
].Type
;
1325 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1329 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1336 Worker function will get the raw value in variable MTRRs
1338 @param[out] VariableSettings A buffer to hold variable MTRRs content.
1340 @return The VariableSettings input pointer
1343 MTRR_VARIABLE_SETTINGS
*
1344 MtrrGetVariableMtrrWorker (
1345 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1349 UINT32 VariableMtrrCount
;
1351 VariableMtrrCount
= GetVariableMtrrCount ();
1352 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1354 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1355 VariableSettings
->Mtrr
[Index
].Base
=
1356 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1357 VariableSettings
->Mtrr
[Index
].Mask
=
1358 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1361 return VariableSettings
;
1365 This function will get the raw value in variable MTRRs
1367 @param[out] VariableSettings A buffer to hold variable MTRRs content.
1369 @return The VariableSettings input pointer
1372 MTRR_VARIABLE_SETTINGS
*
1374 MtrrGetVariableMtrr (
1375 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1378 if (!IsMtrrSupported ()) {
1379 return VariableSettings
;
1382 return MtrrGetVariableMtrrWorker (
1389 Worker function setting variable MTRRs
1391 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1395 MtrrSetVariableMtrrWorker (
1396 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1400 UINT32 VariableMtrrCount
;
1402 VariableMtrrCount
= GetVariableMtrrCount ();
1403 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1405 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1407 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1408 VariableSettings
->Mtrr
[Index
].Base
1411 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1412 VariableSettings
->Mtrr
[Index
].Mask
1419 This function sets variable MTRRs
1421 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1423 @return The pointer of VariableSettings
1426 MTRR_VARIABLE_SETTINGS
*
1428 MtrrSetVariableMtrr (
1429 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1432 MTRR_CONTEXT MtrrContext
;
1434 if (!IsMtrrSupported ()) {
1435 return VariableSettings
;
1438 PreMtrrChange (&MtrrContext
);
1439 MtrrSetVariableMtrrWorker (VariableSettings
);
1440 PostMtrrChange (&MtrrContext
);
1441 return VariableSettings
;
1445 Worker function gets the content in fixed MTRRs
1447 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
1449 @retval The pointer of FixedSettings
1452 MTRR_FIXED_SETTINGS
*
1453 MtrrGetFixedMtrrWorker (
1454 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1459 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1460 FixedSettings
->Mtrr
[Index
] =
1461 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1464 return FixedSettings
;
1469 This function gets the content in fixed MTRRs
1471 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
1473 @retval The pointer of FixedSettings
1476 MTRR_FIXED_SETTINGS
*
1479 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1482 if (!IsMtrrSupported ()) {
1483 return FixedSettings
;
1486 return MtrrGetFixedMtrrWorker (FixedSettings
);
1490 Worker function setting fixed MTRRs
1492 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.
1496 MtrrSetFixedMtrrWorker (
1497 IN MTRR_FIXED_SETTINGS
*FixedSettings
1502 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1504 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1505 FixedSettings
->Mtrr
[Index
]
1512 This function sets fixed MTRRs
1514 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.
1516 @retval The pointer of FixedSettings
1519 MTRR_FIXED_SETTINGS
*
1522 IN MTRR_FIXED_SETTINGS
*FixedSettings
1525 MTRR_CONTEXT MtrrContext
;
1527 if (!IsMtrrSupported ()) {
1528 return FixedSettings
;
1531 PreMtrrChange (&MtrrContext
);
1532 MtrrSetFixedMtrrWorker (FixedSettings
);
1533 PostMtrrChange (&MtrrContext
);
1535 return FixedSettings
;
1540 This function gets the content in all MTRRs (variable and fixed)
1542 @param[out] MtrrSetting A buffer to hold all Mtrrs content.
1544 @retval the pointer of MtrrSetting
1550 OUT MTRR_SETTINGS
*MtrrSetting
1553 if (!IsMtrrSupported ()) {
1560 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1563 // Get variable MTRRs
1565 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1568 // Get MTRR_DEF_TYPE value
1570 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1577 This function sets all MTRRs (variable and fixed)
1579 @param[in] MtrrSetting A buffer holding all MTRRs content.
1581 @retval The pointer of MtrrSetting
1587 IN MTRR_SETTINGS
*MtrrSetting
1590 MTRR_CONTEXT MtrrContext
;
1592 if (!IsMtrrSupported ()) {
1596 PreMtrrChange (&MtrrContext
);
1601 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1604 // Set variable MTRRs
1606 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1609 // Set MTRR_DEF_TYPE value
1611 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1613 PostMtrrChangeEnableCache (&MtrrContext
);
1619 This function prints all MTRRs for debugging.
1623 MtrrDebugPrintAllMtrrs (
1628 MTRR_SETTINGS MtrrSettings
;
1631 UINTN VariableMtrrCount
;
1639 UINT64 NoRangeLimit
;
1642 UINTN PreviousMemoryType
;
1645 if (!IsMtrrSupported ()) {
1649 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1650 DEBUG((DEBUG_CACHE
, "=============\n"));
1652 MtrrGetAllMtrrs (&MtrrSettings
);
1653 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", MtrrSettings
.MtrrDefType
));
1654 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1655 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, MtrrSettings
.Fixed
.Mtrr
[Index
]));
1658 VariableMtrrCount
= GetVariableMtrrCount ();
1659 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1660 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1662 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1663 MtrrSettings
.Variables
.Mtrr
[Index
].Mask
1666 DEBUG((DEBUG_CACHE
, "\n"));
1667 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1668 DEBUG((DEBUG_CACHE
, "====================================\n"));
1671 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1672 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1673 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1674 for (Index1
= 0; Index1
< 8; Index1
++) {
1675 MemoryType
= (UINTN
)(RShiftU64 (MtrrSettings
.Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1676 if (MemoryType
> CacheWriteBack
) {
1677 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1679 if (MemoryType
!= PreviousMemoryType
) {
1680 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1681 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1683 PreviousMemoryType
= MemoryType
;
1684 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1686 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1689 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1691 VariableMtrrCount
= GetVariableMtrrCount ();
1694 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1695 if (RegEax
>= 0x80000008) {
1696 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1697 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1700 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1702 MemoryType
= MtrrGetMemoryAttribute (Base
);
1703 if (MemoryType
> CacheWriteBack
) {
1704 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1707 if (MemoryType
!= PreviousMemoryType
) {
1708 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1709 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1711 PreviousMemoryType
= MemoryType
;
1712 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1715 RangeBase
= BASE_1MB
;
1716 NoRangeBase
= BASE_1MB
;
1718 NoRangeLimit
= Limit
;
1720 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1721 if ((MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1723 // If mask is not valid, then do not display range
1727 MtrrBase
= (MtrrSettings
.Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1728 MtrrLimit
= MtrrBase
+ ((~(MtrrSettings
.Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1730 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1734 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1735 RangeBase
= MtrrBase
;
1737 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1738 RangeBase
= MtrrLimit
+ 1;
1740 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1741 RangeLimit
= MtrrBase
- 1;
1743 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1744 RangeLimit
= MtrrLimit
;
1747 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1748 NoRangeBase
= MtrrLimit
+ 1;
1750 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1751 NoRangeLimit
= MtrrBase
- 1;
1756 Base
= RangeLimit
+ 1;
1758 Base
= NoRangeLimit
+ 1;
1760 } while (Base
< Limit
);
1761 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1766 Checks if MTRR is supported.
1768 @retval TRUE MTRR is supported.
1769 @retval FALSE MTRR is not supported.
1782 // Check CPUID(1).EDX[12] for MTRR capability
1784 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
1785 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
1790 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1791 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1792 // exist, return false.
1794 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
1795 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {