5 Most of services in this library instance are suggested to be invoked by BSP only,
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
8 Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include <Register/Cpuid.h>
22 #include <Register/Msr.h>
24 #include <Library/MtrrLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/CpuLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
30 #define OR_SEED 0x0101010101010101ull
31 #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
33 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
35 // Context to save and restore when MTRRs are programmed
39 BOOLEAN InterruptState
;
45 MTRR_MEMORY_CACHE_TYPE Type
;
49 // This table defines the offset, base and length of the fixed MTRRs
51 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
53 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
58 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
63 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
68 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
73 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
78 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
83 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
88 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
93 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
98 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
103 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
110 // Lookup table used to print MTRRs
112 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
113 "UC", // CacheUncacheable
114 "WC", // CacheWriteCombining
117 "WT", // CacheWriteThrough
118 "WP", // CacheWriteProtected
119 "WB", // CacheWriteBack
124 Worker function returns the variable MTRR count for the CPU.
126 @return Variable MTRR count
130 GetVariableMtrrCountWorker (
134 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
136 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
137 ASSERT (MtrrCap
.Bits
.VCNT
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
138 return MtrrCap
.Bits
.VCNT
;
142 Returns the variable MTRR count for the CPU.
144 @return Variable MTRR count
149 GetVariableMtrrCount (
153 if (!IsMtrrSupported ()) {
156 return GetVariableMtrrCountWorker ();
160 Worker function returns the firmware usable variable MTRR count for the CPU.
162 @return Firmware usable variable MTRR count
166 GetFirmwareVariableMtrrCountWorker (
170 UINT32 VariableMtrrCount
;
171 UINT32 ReservedMtrrNumber
;
173 VariableMtrrCount
= GetVariableMtrrCountWorker ();
174 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
175 if (VariableMtrrCount
< ReservedMtrrNumber
) {
179 return VariableMtrrCount
- ReservedMtrrNumber
;
183 Returns the firmware usable variable MTRR count for the CPU.
185 @return Firmware usable variable MTRR count
190 GetFirmwareVariableMtrrCount (
194 if (!IsMtrrSupported ()) {
197 return GetFirmwareVariableMtrrCountWorker ();
201 Worker function returns the default MTRR cache type for the system.
203 If MtrrSetting is not NULL, returns the default MTRR cache type from input
204 MTRR settings buffer.
205 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
207 @param[in] MtrrSetting A buffer holding all MTRRs content.
209 @return The default MTRR cache type.
212 MTRR_MEMORY_CACHE_TYPE
213 MtrrGetDefaultMemoryTypeWorker (
214 IN MTRR_SETTINGS
*MtrrSetting
217 if (MtrrSetting
== NULL
) {
218 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
220 return (MTRR_MEMORY_CACHE_TYPE
) (MtrrSetting
->MtrrDefType
& 0x7);
226 Returns the default MTRR cache type for the system.
228 @return The default MTRR cache type.
231 MTRR_MEMORY_CACHE_TYPE
233 MtrrGetDefaultMemoryType (
237 if (!IsMtrrSupported ()) {
238 return CacheUncacheable
;
240 return MtrrGetDefaultMemoryTypeWorker (NULL
);
244 Preparation before programming MTRR.
246 This function will do some preparation for programming MTRRs:
247 disable cache, invalid cache and disable MTRR caching functionality
249 @param[out] MtrrContext Pointer to context to save
253 MtrrLibPreMtrrChange (
254 OUT MTRR_CONTEXT
*MtrrContext
258 // Disable interrupts and save current interrupt state
260 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
263 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
268 // Save original CR4 value and clear PGE flag (Bit 7)
270 MtrrContext
->Cr4
= AsmReadCr4 ();
271 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
281 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
285 Cleaning up after programming MTRRs.
287 This function will do some clean up after programming MTRRs:
288 Flush all TLBs, re-enable caching, restore CR4.
290 @param[in] MtrrContext Pointer to context to restore
294 MtrrLibPostMtrrChangeEnableCache (
295 IN MTRR_CONTEXT
*MtrrContext
304 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
309 // Restore original CR4 value
311 AsmWriteCr4 (MtrrContext
->Cr4
);
314 // Restore original interrupt state
316 SetInterruptState (MtrrContext
->InterruptState
);
320 Cleaning up after programming MTRRs.
322 This function will do some clean up after programming MTRRs:
323 enable MTRR caching functionality, and enable cache
325 @param[in] MtrrContext Pointer to context to restore
329 MtrrLibPostMtrrChange (
330 IN MTRR_CONTEXT
*MtrrContext
336 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
338 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
342 Worker function gets the content in fixed MTRRs
344 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
346 @retval The pointer of FixedSettings
350 MtrrGetFixedMtrrWorker (
351 OUT MTRR_FIXED_SETTINGS
*FixedSettings
356 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
357 FixedSettings
->Mtrr
[Index
] =
358 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
361 return FixedSettings
;
366 This function gets the content in fixed MTRRs
368 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
370 @retval The pointer of FixedSettings
376 OUT MTRR_FIXED_SETTINGS
*FixedSettings
379 if (!IsMtrrSupported ()) {
380 return FixedSettings
;
383 return MtrrGetFixedMtrrWorker (FixedSettings
);
388 Worker function will get the raw value in variable MTRRs
390 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
391 MTRR settings buffer.
392 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
394 @param[in] MtrrSetting A buffer holding all MTRRs content.
395 @param[in] VariableMtrrCount Number of variable MTRRs.
396 @param[out] VariableSettings A buffer to hold variable MTRRs content.
398 @return The VariableSettings input pointer
401 MTRR_VARIABLE_SETTINGS
*
402 MtrrGetVariableMtrrWorker (
403 IN MTRR_SETTINGS
*MtrrSetting
,
404 IN UINT32 VariableMtrrCount
,
405 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
410 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
412 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
413 if (MtrrSetting
== NULL
) {
414 VariableSettings
->Mtrr
[Index
].Base
=
415 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
416 VariableSettings
->Mtrr
[Index
].Mask
=
417 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
419 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
420 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
424 return VariableSettings
;
428 This function will get the raw value in variable MTRRs
430 @param[out] VariableSettings A buffer to hold variable MTRRs content.
432 @return The VariableSettings input pointer
435 MTRR_VARIABLE_SETTINGS
*
437 MtrrGetVariableMtrr (
438 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
441 if (!IsMtrrSupported ()) {
442 return VariableSettings
;
445 return MtrrGetVariableMtrrWorker (
447 GetVariableMtrrCountWorker (),
453 Programs fixed MTRRs registers.
455 @param[in] Type The memory type to set.
456 @param[in, out] Base The base address of memory range.
457 @param[in, out] Length The length of memory range.
458 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.
459 On return, the current index of the fixed MTRR MSR to program.
460 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
461 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
463 @retval RETURN_SUCCESS The cache type was updated successfully
464 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
469 MtrrLibProgramFixedMtrr (
470 IN MTRR_MEMORY_CACHE_TYPE Type
,
472 IN OUT UINT64
*Length
,
473 IN OUT UINT32
*LastMsrNum
,
474 OUT UINT64
*ReturnClearMask
,
475 OUT UINT64
*ReturnOrMask
479 UINT32 LeftByteShift
;
480 UINT32 RightByteShift
;
486 // Find the fixed MTRR index to be programmed
488 for (MsrNum
= *LastMsrNum
+ 1; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
489 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
492 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
493 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
501 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
502 return RETURN_UNSUPPORTED
;
506 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
508 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
)
509 / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
511 if (LeftByteShift
>= 8) {
512 return RETURN_UNSUPPORTED
;
516 // Find the end offset in fixed MTRR and calculate byte offset of right shift
518 SubLength
= mMtrrLibFixedMtrrTable
[MsrNum
].Length
* (8 - LeftByteShift
);
519 if (*Length
>= SubLength
) {
522 RightByteShift
= 8 - LeftByteShift
-
523 (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
524 if ((LeftByteShift
>= 8) ||
525 (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrNum
].Length
) != 0)
527 return RETURN_UNSUPPORTED
;
530 // Update SubLength by actual length
535 ClearMask
= CLEAR_SEED
;
536 OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
538 if (LeftByteShift
!= 0) {
540 // Clear the low bits by LeftByteShift
542 ClearMask
&= LShiftU64 (ClearMask
, LeftByteShift
* 8);
543 OrMask
&= LShiftU64 (OrMask
, LeftByteShift
* 8);
546 if (RightByteShift
!= 0) {
548 // Clear the high bits by RightByteShift
550 ClearMask
&= RShiftU64 (ClearMask
, RightByteShift
* 8);
551 OrMask
&= RShiftU64 (OrMask
, RightByteShift
* 8);
554 *Length
-= SubLength
;
557 *LastMsrNum
= MsrNum
;
558 *ReturnClearMask
= ClearMask
;
559 *ReturnOrMask
= OrMask
;
561 return RETURN_SUCCESS
;
566 Worker function gets the attribute of variable MTRRs.
568 This function shadows the content of variable MTRRs into an
569 internal array: VariableMtrr.
571 @param[in] VariableSettings The variable MTRR values to shadow
572 @param[in] VariableMtrrCount The number of variable MTRRs
573 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
574 @param[in] MtrrValidAddressMask The valid address mask for MTRR
575 @param[out] VariableMtrr The array to shadow variable MTRRs content
577 @return Number of MTRRs which has been used.
581 MtrrGetMemoryAttributeInVariableMtrrWorker (
582 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
583 IN UINTN VariableMtrrCount
,
584 IN UINT64 MtrrValidBitsMask
,
585 IN UINT64 MtrrValidAddressMask
,
586 OUT VARIABLE_MTRR
*VariableMtrr
592 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
593 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
594 if ((VariableSettings
->Mtrr
[Index
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
595 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
596 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
597 VariableMtrr
[Index
].Length
= ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
598 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
599 VariableMtrr
[Index
].Valid
= TRUE
;
600 VariableMtrr
[Index
].Used
= TRUE
;
609 Gets the attribute of variable MTRRs.
611 This function shadows the content of variable MTRRs into an
612 internal array: VariableMtrr.
614 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
615 @param[in] MtrrValidAddressMask The valid address mask for MTRR
616 @param[out] VariableMtrr The array to shadow variable MTRRs content
618 @return The return value of this parameter indicates the
619 number of MTRRs which has been used.
624 MtrrGetMemoryAttributeInVariableMtrr (
625 IN UINT64 MtrrValidBitsMask
,
626 IN UINT64 MtrrValidAddressMask
,
627 OUT VARIABLE_MTRR
*VariableMtrr
630 MTRR_VARIABLE_SETTINGS VariableSettings
;
632 if (!IsMtrrSupported ()) {
636 MtrrGetVariableMtrrWorker (
638 GetVariableMtrrCountWorker (),
642 return MtrrGetMemoryAttributeInVariableMtrrWorker (
644 GetFirmwareVariableMtrrCountWorker (),
646 MtrrValidAddressMask
,
652 Return the least alignment of address.
654 @param Address The address to return the alignment.
655 @param Alignment0 The alignment to return when Address is 0.
657 @return The least alignment of the Address.
660 MtrrLibLeastAlignment (
669 return LShiftU64 (1, (UINTN
) LowBitSet64 (Address
));
673 Return the number of required variable MTRRs to positively cover the
676 @param BaseAddress Base address of the range.
677 @param Length Length of the range.
678 @param Alignment0 Alignment of 0.
680 @return The number of the required variable MTRRs.
683 MtrrLibGetPositiveMtrrNumber (
684 IN UINT64 BaseAddress
,
691 BOOLEAN UseLeastAlignment
;
693 UseLeastAlignment
= TRUE
;
696 // Calculate the alignment of the base address.
698 for (MtrrNumber
= 0; Length
!= 0; MtrrNumber
++) {
699 if (UseLeastAlignment
) {
700 SubLength
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
702 if (SubLength
> Length
) {
704 // Set a flag when remaining length is too small
705 // so that MtrrLibLeastAlignment() is not called in following loops.
707 UseLeastAlignment
= FALSE
;
711 if (!UseLeastAlignment
) {
712 SubLength
= GetPowerOfTwo64 (Length
);
715 BaseAddress
+= SubLength
;
723 Return whether the left MTRR type precedes the right MTRR type.
725 The MTRR type precedence rules are:
726 1. UC precedes any other type
728 For further details, please refer the IA32 Software Developer's Manual,
729 Volume 3, Section "MTRR Precedences".
731 @param Left The left MTRR type.
732 @param Right The right MTRR type.
734 @retval TRUE Left precedes Right.
735 @retval FALSE Left doesn't precede Right.
738 MtrrLibTypeLeftPrecedeRight (
739 IN MTRR_MEMORY_CACHE_TYPE Left
,
740 IN MTRR_MEMORY_CACHE_TYPE Right
743 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
748 Return whether the type of the specified range can precede the specified type.
750 @param Ranges Memory range array holding memory type settings for all
752 @param RangeCount Count of memory ranges.
753 @param Type Type to check precedence.
754 @param SubBase Base address of the specified range.
755 @param SubLength Length of the specified range.
757 @retval TRUE The type of the specified range can precede the Type.
758 @retval FALSE The type of the specified range cannot precede the Type.
759 So the subtraction is not applicable.
762 MtrrLibSubstractable (
763 IN CONST MEMORY_RANGE
*Ranges
,
764 IN UINT32 RangeCount
,
765 IN MTRR_MEMORY_CACHE_TYPE Type
,
774 for (Index
= 0; Index
< RangeCount
; Index
++) {
775 if (Ranges
[Index
].BaseAddress
<= SubBase
&& SubBase
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
777 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= SubBase
+ SubLength
) {
778 return MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
);
781 if (!MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
)) {
785 Length
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- SubBase
;
797 Return the number of required variable MTRRs to cover the specified range.
799 The routine considers subtraction in the both side of the range to find out
800 the most optimal solution (which uses the least MTRRs).
802 @param Ranges Array holding memory type settings of all memory
804 @param RangeCount Count of memory ranges.
805 @param VariableMtrr Array holding allocated variable MTRRs.
806 @param VariableMtrrCount Count of allocated variable MTRRs.
807 @param BaseAddress Base address of the specified range.
808 @param Length Length of the specified range.
809 @param Type MTRR type of the specified range.
810 @param Alignment0 Alignment of 0.
811 @param SubLeft Return the count of left subtraction.
812 @param SubRight Return the count of right subtraction.
814 @return Number of required variable MTRRs.
817 MtrrLibGetMtrrNumber (
818 IN CONST MEMORY_RANGE
*Ranges
,
819 IN UINT32 RangeCount
,
820 IN CONST VARIABLE_MTRR
*VariableMtrr
,
821 IN UINT32 VariableMtrrCount
,
822 IN UINT64 BaseAddress
,
824 IN MTRR_MEMORY_CACHE_TYPE Type
,
825 IN UINT64 Alignment0
,
826 OUT UINT32
*SubLeft
, // subtractive from BaseAddress to get more aligned address, to save MTRR
827 OUT UINT32
*SubRight
// subtractive from BaseAddress + Length, to save MTRR
831 UINT32 LeastLeftMtrrNumber
;
832 UINT32 MiddleMtrrNumber
;
833 UINT32 LeastRightMtrrNumber
;
834 UINT32 CurrentMtrrNumber
;
835 UINT32 SubtractiveCount
;
836 UINT32 SubtractiveMtrrNumber
;
837 UINT32 LeastSubtractiveMtrrNumber
;
838 UINT64 SubtractiveBaseAddress
;
839 UINT64 SubtractiveLength
;
840 UINT64 BaseAlignment
;
845 LeastSubtractiveMtrrNumber
= 0;
848 // Get the optimal left subtraction solution.
850 if (BaseAddress
!= 0) {
852 // Get the MTRR number needed without left subtraction.
854 LeastLeftMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
857 // Left subtraction bit by bit, to find the optimal left subtraction solution.
859 for (SubtractiveMtrrNumber
= 0, SubtractiveCount
= 1; BaseAddress
!= 0; SubtractiveCount
++) {
860 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
863 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
864 // IA32 Manual defines the following override rules:
868 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
- Alignment
, Alignment
)) {
872 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
873 if ((VariableMtrr
[Index
].BaseAddress
== BaseAddress
- Alignment
) &&
874 (VariableMtrr
[Index
].Length
== Alignment
)) {
878 if (Index
== VariableMtrrCount
) {
880 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
882 SubtractiveMtrrNumber
++;
885 BaseAddress
-= Alignment
;
888 CurrentMtrrNumber
= SubtractiveMtrrNumber
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
889 if (CurrentMtrrNumber
<= LeastLeftMtrrNumber
) {
890 LeastLeftMtrrNumber
= CurrentMtrrNumber
;
891 LeastSubtractiveMtrrNumber
= SubtractiveMtrrNumber
;
892 *SubLeft
= SubtractiveCount
;
893 SubtractiveBaseAddress
= BaseAddress
;
894 SubtractiveLength
= Length
;
899 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
902 BaseAddress
= SubtractiveBaseAddress
;
903 Length
= SubtractiveLength
;
908 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
910 MiddleMtrrNumber
= 0;
911 while (Length
!= 0) {
912 BaseAlignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
913 if (BaseAlignment
> Length
) {
916 BaseAddress
+= BaseAlignment
;
917 Length
-= BaseAlignment
;
923 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
;
928 // Get the optimal right subtraction solution.
932 // Get the MTRR number needed without right subtraction.
934 LeastRightMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
936 for (SubtractiveCount
= 1; Length
< BaseAlignment
; SubtractiveCount
++) {
937 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
938 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
+ Length
, Alignment
)) {
945 // SubtractiveCount = Number of MTRRs used for subtraction
947 CurrentMtrrNumber
= SubtractiveCount
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
948 if (CurrentMtrrNumber
<= LeastRightMtrrNumber
) {
949 LeastRightMtrrNumber
= CurrentMtrrNumber
;
950 *SubRight
= SubtractiveCount
;
951 SubtractiveLength
= Length
;
955 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
+ LeastRightMtrrNumber
;
959 Initializes the valid bits mask and valid address mask for MTRRs.
961 This function initializes the valid bits mask and valid address mask for MTRRs.
963 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
964 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
968 MtrrLibInitializeMtrrMask (
969 OUT UINT64
*MtrrValidBitsMask
,
970 OUT UINT64
*MtrrValidAddressMask
973 UINT32 MaxExtendedFunction
;
974 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
977 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
979 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
980 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
982 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
985 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
986 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
991 Determines the real attribute of a memory range.
993 This function is to arbitrate the real attribute of the memory when
994 there are 2 MTRRs covers the same memory range. For further details,
995 please refer the IA32 Software Developer's Manual, Volume 3,
996 Section "MTRR Precedences".
998 @param[in] MtrrType1 The first kind of Memory type
999 @param[in] MtrrType2 The second kind of memory type
1002 MTRR_MEMORY_CACHE_TYPE
1004 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
1005 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
1008 if (MtrrType1
== MtrrType2
) {
1013 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
1014 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
1017 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
1025 Worker function will get the memory cache type of the specific address.
1027 If MtrrSetting is not NULL, gets the memory cache type from input
1028 MTRR settings buffer.
1029 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1031 @param[in] MtrrSetting A buffer holding all MTRRs content.
1032 @param[in] Address The specific address
1034 @return Memory cache type of the specific address
1037 MTRR_MEMORY_CACHE_TYPE
1038 MtrrGetMemoryAttributeByAddressWorker (
1039 IN MTRR_SETTINGS
*MtrrSetting
,
1040 IN PHYSICAL_ADDRESS Address
1043 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
1047 MTRR_MEMORY_CACHE_TYPE MtrrType
;
1048 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1049 UINT64 MtrrValidBitsMask
;
1050 UINT64 MtrrValidAddressMask
;
1051 UINT32 VariableMtrrCount
;
1052 MTRR_VARIABLE_SETTINGS VariableSettings
;
1055 // Check if MTRR is enabled, if not, return UC as attribute
1057 if (MtrrSetting
== NULL
) {
1058 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
1060 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
1063 if (DefType
.Bits
.E
== 0) {
1064 return CacheUncacheable
;
1068 // If address is less than 1M, then try to go through the fixed MTRR
1070 if (Address
< BASE_1MB
) {
1071 if (DefType
.Bits
.FE
!= 0) {
1073 // Go through the fixed MTRR
1075 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1076 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1077 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1078 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
1080 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1081 mMtrrLibFixedMtrrTable
[Index
].Length
;
1082 if (MtrrSetting
== NULL
) {
1083 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1085 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1087 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
1093 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1094 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1095 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
1097 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1098 MtrrGetMemoryAttributeInVariableMtrrWorker (
1102 MtrrValidAddressMask
,
1107 // Go through the variable MTRR
1109 MtrrType
= CacheInvalid
;
1110 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1111 if (VariableMtrr
[Index
].Valid
) {
1112 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1113 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
1114 if (MtrrType
== CacheInvalid
) {
1115 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
1117 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
1124 // If there is no MTRR which covers the Address, use the default MTRR type.
1126 if (MtrrType
== CacheInvalid
) {
1127 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
1135 This function will get the memory cache type of the specific address.
1137 This function is mainly for debug purpose.
1139 @param[in] Address The specific address
1141 @return Memory cache type of the specific address
1144 MTRR_MEMORY_CACHE_TYPE
1146 MtrrGetMemoryAttribute (
1147 IN PHYSICAL_ADDRESS Address
1150 if (!IsMtrrSupported ()) {
1151 return CacheUncacheable
;
1154 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1158 Worker function prints all MTRRs for debugging.
1160 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1162 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1164 @param MtrrSetting A buffer holding all MTRRs content.
1167 MtrrDebugPrintAllMtrrsWorker (
1168 IN MTRR_SETTINGS
*MtrrSetting
1172 MTRR_SETTINGS LocalMtrrs
;
1173 MTRR_SETTINGS
*Mtrrs
;
1176 UINTN VariableMtrrCount
;
1184 UINT64 NoRangeLimit
;
1187 UINTN PreviousMemoryType
;
1190 if (!IsMtrrSupported ()) {
1194 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1195 DEBUG((DEBUG_CACHE
, "=============\n"));
1197 if (MtrrSetting
!= NULL
) {
1198 Mtrrs
= MtrrSetting
;
1200 MtrrGetAllMtrrs (&LocalMtrrs
);
1201 Mtrrs
= &LocalMtrrs
;
1204 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1205 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1206 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1209 VariableMtrrCount
= GetVariableMtrrCount ();
1210 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1211 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1213 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1214 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1217 DEBUG((DEBUG_CACHE
, "\n"));
1218 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1219 DEBUG((DEBUG_CACHE
, "====================================\n"));
1222 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1223 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1224 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1225 for (Index1
= 0; Index1
< 8; Index1
++) {
1226 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1227 if (MemoryType
> CacheWriteBack
) {
1228 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1230 if (MemoryType
!= PreviousMemoryType
) {
1231 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1232 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1234 PreviousMemoryType
= MemoryType
;
1235 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1237 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1240 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1242 VariableMtrrCount
= GetVariableMtrrCount ();
1245 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1246 if (RegEax
>= 0x80000008) {
1247 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1248 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1251 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1253 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1254 if (MemoryType
> CacheWriteBack
) {
1255 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1258 if (MemoryType
!= PreviousMemoryType
) {
1259 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1260 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1262 PreviousMemoryType
= MemoryType
;
1263 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1266 RangeBase
= BASE_1MB
;
1267 NoRangeBase
= BASE_1MB
;
1269 NoRangeLimit
= Limit
;
1271 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1272 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1274 // If mask is not valid, then do not display range
1278 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1279 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1281 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1285 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1286 RangeBase
= MtrrBase
;
1288 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1289 RangeBase
= MtrrLimit
+ 1;
1291 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1292 RangeLimit
= MtrrBase
- 1;
1294 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1295 RangeLimit
= MtrrLimit
;
1298 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1299 NoRangeBase
= MtrrLimit
+ 1;
1301 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1302 NoRangeLimit
= MtrrBase
- 1;
1307 Base
= RangeLimit
+ 1;
1309 Base
= NoRangeLimit
+ 1;
1311 } while (Base
< Limit
);
1312 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1318 This function prints all MTRRs for debugging.
1322 MtrrDebugPrintAllMtrrs (
1326 MtrrDebugPrintAllMtrrsWorker (NULL
);
1330 Update the Ranges array to change the specified range identified by
1331 BaseAddress and Length to Type.
1333 @param Ranges Array holding memory type settings for all memory regions.
1334 @param Capacity The maximum count of memory ranges the array can hold.
1335 @param Count Return the new memory range count in the array.
1336 @param BaseAddress The base address of the memory range to change type.
1337 @param Length The length of the memory range to change type.
1338 @param Type The new type of the specified memory range.
1340 @retval RETURN_SUCCESS The type of the specified memory range is
1341 changed successfully.
1342 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1343 range exceeds capacity.
1346 MtrrLibSetMemoryType (
1347 IN MEMORY_RANGE
*Ranges
,
1349 IN OUT UINT32
*Count
,
1350 IN UINT64 BaseAddress
,
1352 IN MTRR_MEMORY_CACHE_TYPE Type
1363 Limit
= BaseAddress
+ Length
;
1364 StartIndex
= *Count
;
1366 for (Index
= 0; Index
< *Count
; Index
++) {
1367 if ((StartIndex
== *Count
) &&
1368 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1369 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1371 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1374 if ((EndIndex
== *Count
) &&
1375 (Ranges
[Index
].BaseAddress
< Limit
) &&
1376 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1378 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1383 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1384 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1385 return RETURN_SUCCESS
;
1389 // The type change may cause merging with previous range or next range.
1390 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1391 // logic doesn't need to consider merging.
1393 if (StartIndex
!= 0) {
1394 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1396 Length
+= Ranges
[StartIndex
].Length
;
1397 BaseAddress
-= Ranges
[StartIndex
].Length
;
1400 if (EndIndex
!= (*Count
) - 1) {
1401 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1403 Length
+= Ranges
[EndIndex
].Length
;
1408 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1409 // |++++++++++++++++++| 0 3 1=3-0-2 3
1410 // |+++++++| 0 1 -1=1-0-2 5
1411 // |+| 0 0 -2=0-0-2 6
1412 // |+++| 0 0 -1=0-0-2+1 5
1415 DeltaCount
= EndIndex
- StartIndex
- 2;
1416 if (LengthLeft
== 0) {
1419 if (LengthRight
== 0) {
1422 if (*Count
- DeltaCount
> Capacity
) {
1423 return RETURN_OUT_OF_RESOURCES
;
1427 // Reserve (-DeltaCount) space
1429 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1430 *Count
-= DeltaCount
;
1432 if (LengthLeft
!= 0) {
1433 Ranges
[StartIndex
].Length
= LengthLeft
;
1436 if (LengthRight
!= 0) {
1437 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1438 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1439 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1441 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1442 Ranges
[StartIndex
].Length
= Length
;
1443 Ranges
[StartIndex
].Type
= Type
;
1444 return RETURN_SUCCESS
;
1448 Allocate one or more variable MTRR to cover the range identified by
1449 BaseAddress and Length.
1451 @param Ranges Memory range array holding the memory type
1452 settings for all memory address.
1453 @param RangeCount Count of memory ranges.
1454 @param VariableMtrr Variable MTRR array.
1455 @param VariableMtrrCapacity Capacity of variable MTRR array.
1456 @param VariableMtrrCount Count of variable MTRR.
1457 @param BaseAddress Base address of the memory range.
1458 @param Length Length of the memory range.
1459 @param Type MTRR type of the memory range.
1460 @param Alignment0 Alignment of 0.
1462 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1463 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1466 MtrrLibSetMemoryAttributeInVariableMtrr (
1467 IN CONST MEMORY_RANGE
*Ranges
,
1468 IN UINT32 RangeCount
,
1469 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1470 IN UINT32 VariableMtrrCapacity
,
1471 IN OUT UINT32
*VariableMtrrCount
,
1472 IN UINT64 BaseAddress
,
1474 IN MTRR_MEMORY_CACHE_TYPE Type
,
1475 IN UINT64 Alignment0
1479 Allocate one or more variable MTRR to cover the range identified by
1480 BaseAddress and Length.
1482 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1483 to allocate variable MTRRs when the range contains several sub-ranges
1484 with different attributes.
1486 @param Ranges Memory range array holding the memory type
1487 settings for all memory address.
1488 @param RangeCount Count of memory ranges.
1489 @param VariableMtrr Variable MTRR array.
1490 @param VariableMtrrCapacity Capacity of variable MTRR array.
1491 @param VariableMtrrCount Count of variable MTRR.
1492 @param BaseAddress Base address of the memory range.
1493 @param Length Length of the memory range.
1494 @param Type MTRR type of the range.
1495 If it's CacheInvalid, the memory range may
1496 contains several sub-ranges with different
1498 @param Alignment0 Alignment of 0.
1500 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1501 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1504 MtrrLibAddVariableMtrr (
1505 IN CONST MEMORY_RANGE
*Ranges
,
1506 IN UINT32 RangeCount
,
1507 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1508 IN UINT32 VariableMtrrCapacity
,
1509 IN OUT UINT32
*VariableMtrrCount
,
1510 IN PHYSICAL_ADDRESS BaseAddress
,
1512 IN MTRR_MEMORY_CACHE_TYPE Type
,
1513 IN UINT64 Alignment0
1516 RETURN_STATUS Status
;
1520 MTRR_LIB_ASSERT_ALIGNED (BaseAddress
, Length
);
1521 if (Type
== CacheInvalid
) {
1522 for (Index
= 0; Index
< RangeCount
; Index
++) {
1523 if (Ranges
[Index
].BaseAddress
<= BaseAddress
&& BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1526 // Because the Length may not be aligned to BaseAddress, below code calls
1527 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1528 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1531 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= BaseAddress
+ Length
) {
1532 return MtrrLibSetMemoryAttributeInVariableMtrr (
1533 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1534 BaseAddress
, Length
, Ranges
[Index
].Type
, Alignment0
1537 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1538 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1539 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1540 BaseAddress
, SubLength
, Ranges
[Index
].Type
, Alignment0
1542 if (RETURN_ERROR (Status
)) {
1545 BaseAddress
+= SubLength
;
1546 Length
-= SubLength
;
1552 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1555 return RETURN_DEVICE_ERROR
;
1557 for (Index
= 0; Index
< *VariableMtrrCount
; Index
++) {
1558 if (VariableMtrr
[Index
].BaseAddress
== BaseAddress
&& VariableMtrr
[Index
].Length
== Length
) {
1559 ASSERT (VariableMtrr
[Index
].Type
== Type
);
1563 if (Index
== *VariableMtrrCount
) {
1564 if (*VariableMtrrCount
== VariableMtrrCapacity
) {
1565 return RETURN_OUT_OF_RESOURCES
;
1567 VariableMtrr
[Index
].BaseAddress
= BaseAddress
;
1568 VariableMtrr
[Index
].Length
= Length
;
1569 VariableMtrr
[Index
].Type
= Type
;
1570 VariableMtrr
[Index
].Valid
= TRUE
;
1571 VariableMtrr
[Index
].Used
= TRUE
;
1572 (*VariableMtrrCount
)++;
1574 return RETURN_SUCCESS
;
1579 Allocate one or more variable MTRR to cover the range identified by
1580 BaseAddress and Length.
1582 @param Ranges Memory range array holding the memory type
1583 settings for all memory address.
1584 @param RangeCount Count of memory ranges.
1585 @param VariableMtrr Variable MTRR array.
1586 @param VariableMtrrCapacity Capacity of variable MTRR array.
1587 @param VariableMtrrCount Count of variable MTRR.
1588 @param BaseAddress Base address of the memory range.
1589 @param Length Length of the memory range.
1590 @param Type MTRR type of the memory range.
1591 @param Alignment0 Alignment of 0.
1593 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1594 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1597 MtrrLibSetMemoryAttributeInVariableMtrr (
1598 IN CONST MEMORY_RANGE
*Ranges
,
1599 IN UINT32 RangeCount
,
1600 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1601 IN UINT32 VariableMtrrCapacity
,
1602 IN OUT UINT32
*VariableMtrrCount
,
1603 IN UINT64 BaseAddress
,
1605 IN MTRR_MEMORY_CACHE_TYPE Type
,
1606 IN UINT64 Alignment0
1611 UINT32 SubtractiveLeft
;
1612 UINT32 SubtractiveRight
;
1613 BOOLEAN UseLeastAlignment
;
1615 MtrrNumber
= MtrrLibGetMtrrNumber (Ranges
, RangeCount
, VariableMtrr
, *VariableMtrrCount
,
1616 BaseAddress
, Length
, Type
, Alignment0
, &SubtractiveLeft
, &SubtractiveRight
);
1618 if (MtrrNumber
+ *VariableMtrrCount
> VariableMtrrCapacity
) {
1619 return RETURN_OUT_OF_RESOURCES
;
1622 while (SubtractiveLeft
-- != 0) {
1623 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1624 ASSERT (Alignment
<= Length
);
1626 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1627 BaseAddress
- Alignment
, Alignment
, CacheInvalid
, Alignment0
);
1628 BaseAddress
-= Alignment
;
1629 Length
+= Alignment
;
1632 while (Length
!= 0) {
1633 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1634 if (Alignment
> Length
) {
1637 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1638 BaseAddress
, Alignment
, Type
, Alignment0
);
1639 BaseAddress
+= Alignment
;
1640 Length
-= Alignment
;
1643 while (SubtractiveRight
-- != 0) {
1644 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
1645 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1646 BaseAddress
+ Length
, Alignment
, CacheInvalid
, Alignment0
);
1647 Length
+= Alignment
;
1650 UseLeastAlignment
= TRUE
;
1651 while (Length
!= 0) {
1652 if (UseLeastAlignment
) {
1653 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1654 if (Alignment
> Length
) {
1655 UseLeastAlignment
= FALSE
;
1659 if (!UseLeastAlignment
) {
1660 Alignment
= GetPowerOfTwo64 (Length
);
1663 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1664 BaseAddress
, Alignment
, Type
, Alignment0
);
1665 BaseAddress
+= Alignment
;
1666 Length
-= Alignment
;
1668 return RETURN_SUCCESS
;
1672 Return an array of memory ranges holding memory type settings for all memory
1675 @param DefaultType The default memory type.
1676 @param TotalLength The total length of the memory.
1677 @param VariableMtrr The variable MTRR array.
1678 @param VariableMtrrCount The count of variable MTRRs.
1679 @param Ranges Return the memory range array holding memory type
1680 settings for all memory address.
1681 @param RangeCapacity The capacity of memory range array.
1682 @param RangeCount Return the count of memory range.
1684 @retval RETURN_SUCCESS The memory range array is returned successfully.
1685 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1688 MtrrLibGetMemoryTypes (
1689 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1690 IN UINT64 TotalLength
,
1691 IN CONST VARIABLE_MTRR
*VariableMtrr
,
1692 IN UINT32 VariableMtrrCount
,
1693 OUT MEMORY_RANGE
*Ranges
,
1694 IN UINT32 RangeCapacity
,
1695 OUT UINT32
*RangeCount
1698 RETURN_STATUS Status
;
1704 // UC > * (except WB, UC) > WB
1708 // 0. Set whole range as DefaultType
1711 Ranges
[0].BaseAddress
= 0;
1712 Ranges
[0].Length
= TotalLength
;
1713 Ranges
[0].Type
= DefaultType
;
1718 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1719 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheWriteBack
) {
1720 Status
= MtrrLibSetMemoryType (
1721 Ranges
, RangeCapacity
, RangeCount
,
1722 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1724 if (RETURN_ERROR (Status
)) {
1731 // 2. Set other types than WB or UC
1733 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1734 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
!= CacheWriteBack
&& VariableMtrr
[Index
].Type
!= CacheUncacheable
) {
1735 Status
= MtrrLibSetMemoryType (
1736 Ranges
, RangeCapacity
, RangeCount
,
1737 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1739 if (RETURN_ERROR (Status
)) {
1748 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1749 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1750 Status
= MtrrLibSetMemoryType (
1751 Ranges
, RangeCapacity
, RangeCount
,
1752 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1754 if (RETURN_ERROR (Status
)) {
1759 return RETURN_SUCCESS
;
1763 Worker function attempts to set the attributes for a memory range.
1765 If MtrrSetting is not NULL, set the attributes into the input MTRR
1767 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1769 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1770 @param[in] BaseAddress The physical address that is the start
1771 address of a memory range.
1772 @param[in] Length The size in bytes of the memory range.
1773 @param[in] Type The MTRR type to set for the memory range.
1775 @retval RETURN_SUCCESS The attributes were set for the memory
1777 @retval RETURN_INVALID_PARAMETER Length is zero.
1778 @retval RETURN_UNSUPPORTED The processor does not support one or
1779 more bytes of the memory resource range
1780 specified by BaseAddress and Length.
1781 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1782 memory resource range specified
1783 by BaseAddress and Length.
1784 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1785 modify the attributes of the memory
1790 MtrrSetMemoryAttributeWorker (
1791 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1792 IN PHYSICAL_ADDRESS BaseAddress
,
1794 IN MTRR_MEMORY_CACHE_TYPE Type
1797 RETURN_STATUS Status
;
1799 UINT32 WorkingIndex
;
1801 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1803 MEMORY_RANGE Ranges
[MTRR_NUMBER_OF_VARIABLE_MTRR
* 2 + 2];
1805 UINT64 MtrrValidBitsMask
;
1806 UINT64 MtrrValidAddressMask
;
1808 MTRR_CONTEXT MtrrContext
;
1809 BOOLEAN MtrrContextValid
;
1811 MTRR_MEMORY_CACHE_TYPE DefaultType
;
1817 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1818 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1819 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1821 UINT32 FirmwareVariableMtrrCount
;
1822 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1823 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1824 UINT32 OriginalVariableMtrrCount
;
1825 VARIABLE_MTRR OriginalVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1826 UINT32 WorkingVariableMtrrCount
;
1827 VARIABLE_MTRR WorkingVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1828 BOOLEAN VariableSettingModified
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1829 UINTN FreeVariableMtrrCount
;
1832 return RETURN_INVALID_PARAMETER
;
1835 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1836 if (((BaseAddress
& ~MtrrValidAddressMask
) != 0) || (Length
& ~MtrrValidAddressMask
) != 0) {
1837 return RETURN_UNSUPPORTED
;
1840 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1841 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1842 FixedSettingsValid
[Index
] = FALSE
;
1843 FixedSettingsModified
[Index
] = FALSE
;
1847 // Check if Fixed MTRR
1849 if (BaseAddress
< BASE_1MB
) {
1850 MsrIndex
= (UINT32
)-1;
1851 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
1852 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
1853 if (RETURN_ERROR (Status
)) {
1856 if (MtrrSetting
!= NULL
) {
1857 MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] = (MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1858 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
1860 if (!FixedSettingsValid
[MsrIndex
]) {
1861 WorkingFixedSettings
.Mtrr
[MsrIndex
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrIndex
].Msr
);
1862 FixedSettingsValid
[MsrIndex
] = TRUE
;
1864 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1865 if (WorkingFixedSettings
.Mtrr
[MsrIndex
] != NewValue
) {
1866 WorkingFixedSettings
.Mtrr
[MsrIndex
] = NewValue
;
1867 FixedSettingsModified
[MsrIndex
] = TRUE
;
1874 // A Length of 0 can only make sense for fixed MTTR ranges.
1875 // Since we just handled the fixed MTRRs, we can skip the
1876 // variable MTRR section.
1883 // Read the default MTRR type
1885 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1888 // Read all variable MTRRs and convert to Ranges.
1890 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
1891 if (MtrrSetting
== NULL
) {
1892 ZeroMem (&OriginalVariableSettings
, sizeof (OriginalVariableSettings
));
1893 MtrrGetVariableMtrrWorker (NULL
, OriginalVariableMtrrCount
, &OriginalVariableSettings
);
1894 VariableSettings
= &OriginalVariableSettings
;
1896 VariableSettings
= &MtrrSetting
->Variables
;
1898 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings
, OriginalVariableMtrrCount
, MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
);
1900 Status
= MtrrLibGetMemoryTypes (
1901 DefaultType
, MtrrValidBitsMask
+ 1, OriginalVariableMtrr
, OriginalVariableMtrrCount
,
1902 Ranges
, 2 * OriginalVariableMtrrCount
+ 1, &RangeCount
1904 ASSERT (Status
== RETURN_SUCCESS
);
1906 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1907 ASSERT (RangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
1910 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1912 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, 0, SIZE_1MB
, CacheUncacheable
);
1913 ASSERT (Status
== RETURN_SUCCESS
);
1915 // Apply Type to [BaseAddress, BaseAddress + Length)
1917 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, BaseAddress
, Length
, Type
);
1918 if (RETURN_ERROR (Status
)) {
1922 Alignment0
= LShiftU64 (1, (UINTN
) HighBitSet64 (MtrrValidBitsMask
));
1923 WorkingVariableMtrrCount
= 0;
1924 ZeroMem (&WorkingVariableMtrr
, sizeof (WorkingVariableMtrr
));
1925 for (Index
= 0; Index
< RangeCount
; Index
++) {
1926 if (Ranges
[Index
].Type
!= DefaultType
) {
1928 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
1929 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
1931 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1933 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
,
1934 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
,
1935 Ranges
[Index
].Type
, Alignment0
1937 if (RETURN_ERROR (Status
)) {
1944 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
1946 if (WorkingVariableMtrr
[0].BaseAddress
== 0 && WorkingVariableMtrr
[0].Length
== SIZE_1MB
) {
1947 ASSERT (WorkingVariableMtrr
[0].Type
== CacheUncacheable
);
1948 WorkingVariableMtrrCount
--;
1949 CopyMem (&WorkingVariableMtrr
[0], &WorkingVariableMtrr
[1], WorkingVariableMtrrCount
* sizeof (VARIABLE_MTRR
));
1952 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
1953 return RETURN_OUT_OF_RESOURCES
;
1956 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
1957 VariableSettingModified
[Index
] = FALSE
;
1959 if (!OriginalVariableMtrr
[Index
].Valid
) {
1962 for (WorkingIndex
= 0; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
1963 if (OriginalVariableMtrr
[Index
].BaseAddress
== WorkingVariableMtrr
[WorkingIndex
].BaseAddress
&&
1964 OriginalVariableMtrr
[Index
].Length
== WorkingVariableMtrr
[WorkingIndex
].Length
&&
1965 OriginalVariableMtrr
[Index
].Type
== WorkingVariableMtrr
[WorkingIndex
].Type
) {
1970 if (WorkingIndex
== WorkingVariableMtrrCount
) {
1972 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
1974 OriginalVariableMtrr
[Index
].Valid
= FALSE
;
1975 VariableSettingModified
[Index
] = TRUE
;
1978 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
1980 WorkingVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
1983 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
1988 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
1990 for (FreeVariableMtrrCount
= 0, WorkingIndex
= 0, Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
1991 if (!OriginalVariableMtrr
[Index
].Valid
) {
1992 for (; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
1993 if (WorkingVariableMtrr
[WorkingIndex
].Valid
) {
1997 if (WorkingIndex
== WorkingVariableMtrrCount
) {
1998 FreeVariableMtrrCount
++;
2000 CopyMem (&OriginalVariableMtrr
[Index
], &WorkingVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2001 VariableSettingModified
[Index
] = TRUE
;
2006 ASSERT (OriginalVariableMtrrCount
- FreeVariableMtrrCount
<= FirmwareVariableMtrrCount
);
2009 // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning
2011 WorkingIndex
= FirmwareVariableMtrrCount
;
2012 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
2013 if (!OriginalVariableMtrr
[Index
].Valid
) {
2015 // Found an empty MTRR in WorkingIndex position
2017 for (; WorkingIndex
< OriginalVariableMtrrCount
; WorkingIndex
++) {
2018 if (OriginalVariableMtrr
[WorkingIndex
].Valid
) {
2023 if (WorkingIndex
!= OriginalVariableMtrrCount
) {
2024 CopyMem (&OriginalVariableMtrr
[Index
], &OriginalVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2025 VariableSettingModified
[Index
] = TRUE
;
2026 VariableSettingModified
[WorkingIndex
] = TRUE
;
2027 OriginalVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2033 // Convert OriginalVariableMtrr to VariableSettings
2034 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2036 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2037 if (VariableSettingModified
[Index
]) {
2038 if (OriginalVariableMtrr
[Index
].Valid
) {
2039 VariableSettings
->Mtrr
[Index
].Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
) | (UINT8
) OriginalVariableMtrr
[Index
].Type
;
2040 VariableSettings
->Mtrr
[Index
].Mask
= (~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
| BIT11
;
2042 VariableSettings
->Mtrr
[Index
].Base
= 0;
2043 VariableSettings
->Mtrr
[Index
].Mask
= 0;
2049 if (MtrrSetting
!= NULL
) {
2050 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2051 return RETURN_SUCCESS
;
2054 MtrrContextValid
= FALSE
;
2056 // Write fixed MTRRs that have been modified
2058 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2059 if (FixedSettingsModified
[Index
]) {
2060 if (!MtrrContextValid
) {
2061 MtrrLibPreMtrrChange (&MtrrContext
);
2062 MtrrContextValid
= TRUE
;
2065 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2066 WorkingFixedSettings
.Mtrr
[Index
]
2072 // Write variable MTRRs
2074 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2075 if (VariableSettingModified
[Index
]) {
2076 if (!MtrrContextValid
) {
2077 MtrrLibPreMtrrChange (&MtrrContext
);
2078 MtrrContextValid
= TRUE
;
2081 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2082 VariableSettings
->Mtrr
[Index
].Base
2085 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2086 VariableSettings
->Mtrr
[Index
].Mask
2090 if (MtrrContextValid
) {
2091 MtrrLibPostMtrrChange (&MtrrContext
);
2098 This function attempts to set the attributes for a memory range.
2100 @param[in] BaseAddress The physical address that is the start
2101 address of a memory range.
2102 @param[in] Length The size in bytes of the memory range.
2103 @param[in] Attributes The bit mask of attributes to set for the
2106 @retval RETURN_SUCCESS The attributes were set for the memory
2108 @retval RETURN_INVALID_PARAMETER Length is zero.
2109 @retval RETURN_UNSUPPORTED The processor does not support one or
2110 more bytes of the memory resource range
2111 specified by BaseAddress and Length.
2112 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2113 for the memory resource range specified
2114 by BaseAddress and Length.
2115 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2116 range specified by BaseAddress and Length
2118 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2119 modify the attributes of the memory
2125 MtrrSetMemoryAttribute (
2126 IN PHYSICAL_ADDRESS BaseAddress
,
2128 IN MTRR_MEMORY_CACHE_TYPE Attribute
2131 RETURN_STATUS Status
;
2133 if (!IsMtrrSupported ()) {
2134 return RETURN_UNSUPPORTED
;
2137 Status
= MtrrSetMemoryAttributeWorker (NULL
, BaseAddress
, Length
, Attribute
);
2138 DEBUG ((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2139 mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2141 if (!RETURN_ERROR (Status
)) {
2142 MtrrDebugPrintAllMtrrsWorker (NULL
);
2148 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2150 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2151 @param[in] BaseAddress The physical address that is the start address
2153 @param[in] Length The size in bytes of the memory range.
2154 @param[in] Attribute The bit mask of attributes to set for the
2157 @retval RETURN_SUCCESS The attributes were set for the memory range.
2158 @retval RETURN_INVALID_PARAMETER Length is zero.
2159 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2160 memory resource range specified by BaseAddress and Length.
2161 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2162 range specified by BaseAddress and Length.
2163 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2164 BaseAddress and Length cannot be modified.
2165 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2166 the memory resource range.
2171 MtrrSetMemoryAttributeInMtrrSettings (
2172 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2173 IN PHYSICAL_ADDRESS BaseAddress
,
2175 IN MTRR_MEMORY_CACHE_TYPE Attribute
2178 RETURN_STATUS Status
;
2179 Status
= MtrrSetMemoryAttributeWorker (MtrrSetting
, BaseAddress
, Length
, Attribute
);
2180 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2181 MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2183 if (!RETURN_ERROR (Status
)) {
2184 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2191 Worker function setting variable MTRRs
2193 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2197 MtrrSetVariableMtrrWorker (
2198 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2202 UINT32 VariableMtrrCount
;
2204 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2205 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
2207 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2209 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
2210 VariableSettings
->Mtrr
[Index
].Base
2213 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
2214 VariableSettings
->Mtrr
[Index
].Mask
2221 This function sets variable MTRRs
2223 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2225 @return The pointer of VariableSettings
2228 MTRR_VARIABLE_SETTINGS
*
2230 MtrrSetVariableMtrr (
2231 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2234 MTRR_CONTEXT MtrrContext
;
2236 if (!IsMtrrSupported ()) {
2237 return VariableSettings
;
2240 MtrrLibPreMtrrChange (&MtrrContext
);
2241 MtrrSetVariableMtrrWorker (VariableSettings
);
2242 MtrrLibPostMtrrChange (&MtrrContext
);
2243 MtrrDebugPrintAllMtrrs ();
2245 return VariableSettings
;
2249 Worker function setting fixed MTRRs
2251 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2255 MtrrSetFixedMtrrWorker (
2256 IN MTRR_FIXED_SETTINGS
*FixedSettings
2261 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2263 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2264 FixedSettings
->Mtrr
[Index
]
2271 This function sets fixed MTRRs
2273 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2275 @retval The pointer of FixedSettings
2278 MTRR_FIXED_SETTINGS
*
2281 IN MTRR_FIXED_SETTINGS
*FixedSettings
2284 MTRR_CONTEXT MtrrContext
;
2286 if (!IsMtrrSupported ()) {
2287 return FixedSettings
;
2290 MtrrLibPreMtrrChange (&MtrrContext
);
2291 MtrrSetFixedMtrrWorker (FixedSettings
);
2292 MtrrLibPostMtrrChange (&MtrrContext
);
2293 MtrrDebugPrintAllMtrrs ();
2295 return FixedSettings
;
2300 This function gets the content in all MTRRs (variable and fixed)
2302 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2304 @retval the pointer of MtrrSetting
2310 OUT MTRR_SETTINGS
*MtrrSetting
2313 if (!IsMtrrSupported ()) {
2320 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2323 // Get variable MTRRs
2325 MtrrGetVariableMtrrWorker (
2327 GetVariableMtrrCountWorker (),
2328 &MtrrSetting
->Variables
2332 // Get MTRR_DEF_TYPE value
2334 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
2341 This function sets all MTRRs (variable and fixed)
2343 @param[in] MtrrSetting A buffer holding all MTRRs content.
2345 @retval The pointer of MtrrSetting
2351 IN MTRR_SETTINGS
*MtrrSetting
2354 MTRR_CONTEXT MtrrContext
;
2356 if (!IsMtrrSupported ()) {
2360 MtrrLibPreMtrrChange (&MtrrContext
);
2365 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2368 // Set variable MTRRs
2370 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2373 // Set MTRR_DEF_TYPE value
2375 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2377 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2384 Checks if MTRR is supported.
2386 @retval TRUE MTRR is supported.
2387 @retval FALSE MTRR is not supported.
2396 CPUID_VERSION_INFO_EDX Edx
;
2397 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2400 // Check CPUID(1).EDX[12] for MTRR capability
2402 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2403 if (Edx
.Bits
.MTRR
== 0) {
2408 // Check number of variable MTRRs and fixed MTRRs existence.
2409 // If number of variable MTRRs is zero, or fixed MTRRs do not
2410 // exist, return false.
2412 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2413 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {