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 MSR_IA32_MTRR_FIX64K_00000
,
58 MSR_IA32_MTRR_FIX16K_80000
,
63 MSR_IA32_MTRR_FIX16K_A0000
,
68 MSR_IA32_MTRR_FIX4K_C0000
,
73 MSR_IA32_MTRR_FIX4K_C8000
,
78 MSR_IA32_MTRR_FIX4K_D0000
,
83 MSR_IA32_MTRR_FIX4K_D8000
,
88 MSR_IA32_MTRR_FIX4K_E0000
,
93 MSR_IA32_MTRR_FIX4K_E8000
,
98 MSR_IA32_MTRR_FIX4K_F0000
,
103 MSR_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 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
219 if (MtrrSetting
== NULL
) {
220 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
222 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
225 return (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
230 Returns the default MTRR cache type for the system.
232 @return The default MTRR cache type.
235 MTRR_MEMORY_CACHE_TYPE
237 MtrrGetDefaultMemoryType (
241 if (!IsMtrrSupported ()) {
242 return CacheUncacheable
;
244 return MtrrGetDefaultMemoryTypeWorker (NULL
);
248 Preparation before programming MTRR.
250 This function will do some preparation for programming MTRRs:
251 disable cache, invalid cache and disable MTRR caching functionality
253 @param[out] MtrrContext Pointer to context to save
257 MtrrLibPreMtrrChange (
258 OUT MTRR_CONTEXT
*MtrrContext
261 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
263 // Disable interrupts and save current interrupt state
265 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
268 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
273 // Save original CR4 value and clear PGE flag (Bit 7)
275 MtrrContext
->Cr4
= AsmReadCr4 ();
276 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
286 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
288 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
292 Cleaning up after programming MTRRs.
294 This function will do some clean up after programming MTRRs:
295 Flush all TLBs, re-enable caching, restore CR4.
297 @param[in] MtrrContext Pointer to context to restore
301 MtrrLibPostMtrrChangeEnableCache (
302 IN MTRR_CONTEXT
*MtrrContext
311 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
316 // Restore original CR4 value
318 AsmWriteCr4 (MtrrContext
->Cr4
);
321 // Restore original interrupt state
323 SetInterruptState (MtrrContext
->InterruptState
);
327 Cleaning up after programming MTRRs.
329 This function will do some clean up after programming MTRRs:
330 enable MTRR caching functionality, and enable cache
332 @param[in] MtrrContext Pointer to context to restore
336 MtrrLibPostMtrrChange (
337 IN MTRR_CONTEXT
*MtrrContext
340 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
344 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
347 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
349 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
353 Worker function gets the content in fixed MTRRs
355 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
357 @retval The pointer of FixedSettings
361 MtrrGetFixedMtrrWorker (
362 OUT MTRR_FIXED_SETTINGS
*FixedSettings
367 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
368 FixedSettings
->Mtrr
[Index
] =
369 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
372 return FixedSettings
;
377 This function gets the content in fixed MTRRs
379 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
381 @retval The pointer of FixedSettings
387 OUT MTRR_FIXED_SETTINGS
*FixedSettings
390 if (!IsMtrrSupported ()) {
391 return FixedSettings
;
394 return MtrrGetFixedMtrrWorker (FixedSettings
);
399 Worker function will get the raw value in variable MTRRs
401 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
402 MTRR settings buffer.
403 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
405 @param[in] MtrrSetting A buffer holding all MTRRs content.
406 @param[in] VariableMtrrCount Number of variable MTRRs.
407 @param[out] VariableSettings A buffer to hold variable MTRRs content.
409 @return The VariableSettings input pointer
412 MTRR_VARIABLE_SETTINGS
*
413 MtrrGetVariableMtrrWorker (
414 IN MTRR_SETTINGS
*MtrrSetting
,
415 IN UINT32 VariableMtrrCount
,
416 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
421 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
423 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
424 if (MtrrSetting
== NULL
) {
425 VariableSettings
->Mtrr
[Index
].Base
=
426 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1));
427 VariableSettings
->Mtrr
[Index
].Mask
=
428 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1));
430 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
431 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
435 return VariableSettings
;
439 This function will get the raw value in variable MTRRs
441 @param[out] VariableSettings A buffer to hold variable MTRRs content.
443 @return The VariableSettings input pointer
446 MTRR_VARIABLE_SETTINGS
*
448 MtrrGetVariableMtrr (
449 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
452 if (!IsMtrrSupported ()) {
453 return VariableSettings
;
456 return MtrrGetVariableMtrrWorker (
458 GetVariableMtrrCountWorker (),
464 Programs fixed MTRRs registers.
466 @param[in] Type The memory type to set.
467 @param[in, out] Base The base address of memory range.
468 @param[in, out] Length The length of memory range.
469 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
470 On return, the current index of the fixed MTRR MSR to program.
471 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
472 @param[out] OrMask The bits to set in the fixed MTRR MSR.
474 @retval RETURN_SUCCESS The cache type was updated successfully
475 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
480 MtrrLibProgramFixedMtrr (
481 IN MTRR_MEMORY_CACHE_TYPE Type
,
483 IN OUT UINT64
*Length
,
484 IN OUT UINT32
*LastMsrIndex
,
485 OUT UINT64
*ClearMask
,
490 UINT32 LeftByteShift
;
491 UINT32 RightByteShift
;
495 // Find the fixed MTRR index to be programmed
497 for (MsrIndex
= *LastMsrIndex
+ 1; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
498 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) &&
501 mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
+
502 (8 * mMtrrLibFixedMtrrTable
[MsrIndex
].Length
)
510 ASSERT (MsrIndex
!= ARRAY_SIZE (mMtrrLibFixedMtrrTable
));
513 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
515 if ((((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
517 // Base address should be aligned to the begin of a certain Fixed MTRR range.
519 return RETURN_UNSUPPORTED
;
521 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
522 ASSERT (LeftByteShift
< 8);
525 // Find the end offset in fixed MTRR and calculate byte offset of right shift
527 SubLength
= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
* (8 - LeftByteShift
);
528 if (*Length
>= SubLength
) {
531 if (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
533 // Length should be aligned to the end of a certain Fixed MTRR range.
535 return RETURN_UNSUPPORTED
;
537 RightByteShift
= 8 - LeftByteShift
- (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
539 // Update SubLength by actual length
544 *ClearMask
= CLEAR_SEED
;
545 *OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
547 if (LeftByteShift
!= 0) {
549 // Clear the low bits by LeftByteShift
551 *ClearMask
&= LShiftU64 (*ClearMask
, LeftByteShift
* 8);
552 *OrMask
&= LShiftU64 (*OrMask
, LeftByteShift
* 8);
555 if (RightByteShift
!= 0) {
557 // Clear the high bits by RightByteShift
559 *ClearMask
&= RShiftU64 (*ClearMask
, RightByteShift
* 8);
560 *OrMask
&= RShiftU64 (*OrMask
, RightByteShift
* 8);
563 *Length
-= SubLength
;
566 *LastMsrIndex
= MsrIndex
;
568 return RETURN_SUCCESS
;
573 Worker function gets the attribute of variable MTRRs.
575 This function shadows the content of variable MTRRs into an
576 internal array: VariableMtrr.
578 @param[in] VariableSettings The variable MTRR values to shadow
579 @param[in] VariableMtrrCount The number of variable MTRRs
580 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
581 @param[in] MtrrValidAddressMask The valid address mask for MTRR
582 @param[out] VariableMtrr The array to shadow variable MTRRs content
584 @return Number of MTRRs which has been used.
588 MtrrGetMemoryAttributeInVariableMtrrWorker (
589 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
590 IN UINTN VariableMtrrCount
,
591 IN UINT64 MtrrValidBitsMask
,
592 IN UINT64 MtrrValidAddressMask
,
593 OUT VARIABLE_MTRR
*VariableMtrr
599 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
600 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
601 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
602 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
603 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
604 VariableMtrr
[Index
].Length
= ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
605 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
606 VariableMtrr
[Index
].Valid
= TRUE
;
607 VariableMtrr
[Index
].Used
= TRUE
;
616 Gets the attribute of variable MTRRs.
618 This function shadows the content of variable MTRRs into an
619 internal array: VariableMtrr.
621 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
622 @param[in] MtrrValidAddressMask The valid address mask for MTRR
623 @param[out] VariableMtrr The array to shadow variable MTRRs content
625 @return The return value of this parameter indicates the
626 number of MTRRs which has been used.
631 MtrrGetMemoryAttributeInVariableMtrr (
632 IN UINT64 MtrrValidBitsMask
,
633 IN UINT64 MtrrValidAddressMask
,
634 OUT VARIABLE_MTRR
*VariableMtrr
637 MTRR_VARIABLE_SETTINGS VariableSettings
;
639 if (!IsMtrrSupported ()) {
643 MtrrGetVariableMtrrWorker (
645 GetVariableMtrrCountWorker (),
649 return MtrrGetMemoryAttributeInVariableMtrrWorker (
651 GetFirmwareVariableMtrrCountWorker (),
653 MtrrValidAddressMask
,
659 Return the least alignment of address.
661 @param Address The address to return the alignment.
662 @param Alignment0 The alignment to return when Address is 0.
664 @return The least alignment of the Address.
667 MtrrLibLeastAlignment (
676 return LShiftU64 (1, (UINTN
) LowBitSet64 (Address
));
680 Return the number of required variable MTRRs to positively cover the
683 @param BaseAddress Base address of the range.
684 @param Length Length of the range.
685 @param Alignment0 Alignment of 0.
687 @return The number of the required variable MTRRs.
690 MtrrLibGetPositiveMtrrNumber (
691 IN UINT64 BaseAddress
,
698 BOOLEAN UseLeastAlignment
;
700 UseLeastAlignment
= TRUE
;
704 // Calculate the alignment of the base address.
706 for (MtrrNumber
= 0; Length
!= 0; MtrrNumber
++) {
707 if (UseLeastAlignment
) {
708 SubLength
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
710 if (SubLength
> Length
) {
712 // Set a flag when remaining length is too small
713 // so that MtrrLibLeastAlignment() is not called in following loops.
715 UseLeastAlignment
= FALSE
;
719 if (!UseLeastAlignment
) {
720 SubLength
= GetPowerOfTwo64 (Length
);
723 BaseAddress
+= SubLength
;
731 Return whether the left MTRR type precedes the right MTRR type.
733 The MTRR type precedence rules are:
734 1. UC precedes any other type
736 For further details, please refer the IA32 Software Developer's Manual,
737 Volume 3, Section "MTRR Precedences".
739 @param Left The left MTRR type.
740 @param Right The right MTRR type.
742 @retval TRUE Left precedes Right.
743 @retval FALSE Left doesn't precede Right.
746 MtrrLibTypeLeftPrecedeRight (
747 IN MTRR_MEMORY_CACHE_TYPE Left
,
748 IN MTRR_MEMORY_CACHE_TYPE Right
751 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
756 Return whether the type of the specified range can precede the specified type.
758 @param Ranges Memory range array holding memory type settings for all
760 @param RangeCount Count of memory ranges.
761 @param Type Type to check precedence.
762 @param SubBase Base address of the specified range.
763 @param SubLength Length of the specified range.
765 @retval TRUE The type of the specified range can precede the Type.
766 @retval FALSE The type of the specified range cannot precede the Type.
767 So the subtraction is not applicable.
770 MtrrLibSubstractable (
771 IN CONST MEMORY_RANGE
*Ranges
,
772 IN UINT32 RangeCount
,
773 IN MTRR_MEMORY_CACHE_TYPE Type
,
782 for (Index
= 0; Index
< RangeCount
; Index
++) {
783 if (Ranges
[Index
].BaseAddress
<= SubBase
&& SubBase
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
785 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= SubBase
+ SubLength
) {
786 return MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
);
789 if (!MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
)) {
793 Length
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- SubBase
;
805 Return the number of required variable MTRRs to cover the specified range.
807 The routine considers subtraction in the both side of the range to find out
808 the most optimal solution (which uses the least MTRRs).
810 @param Ranges Array holding memory type settings of all memory
812 @param RangeCount Count of memory ranges.
813 @param VariableMtrr Array holding allocated variable MTRRs.
814 @param VariableMtrrCount Count of allocated variable MTRRs.
815 @param BaseAddress Base address of the specified range.
816 @param Length Length of the specified range.
817 @param Type MTRR type of the specified range.
818 @param Alignment0 Alignment of 0.
819 @param SubLeft Return the count of left subtraction.
820 @param SubRight Return the count of right subtraction.
822 @return Number of required variable MTRRs.
825 MtrrLibGetMtrrNumber (
826 IN CONST MEMORY_RANGE
*Ranges
,
827 IN UINT32 RangeCount
,
828 IN CONST VARIABLE_MTRR
*VariableMtrr
,
829 IN UINT32 VariableMtrrCount
,
830 IN UINT64 BaseAddress
,
832 IN MTRR_MEMORY_CACHE_TYPE Type
,
833 IN UINT64 Alignment0
,
834 OUT UINT32
*SubLeft
, // subtractive from BaseAddress to get more aligned address, to save MTRR
835 OUT UINT32
*SubRight
// subtractive from BaseAddress + Length, to save MTRR
839 UINT32 LeastLeftMtrrNumber
;
840 UINT32 MiddleMtrrNumber
;
841 UINT32 LeastRightMtrrNumber
;
842 UINT32 CurrentMtrrNumber
;
843 UINT32 SubtractiveCount
;
844 UINT32 SubtractiveMtrrNumber
;
845 UINT32 LeastSubtractiveMtrrNumber
;
846 UINT64 SubtractiveBaseAddress
;
847 UINT64 SubtractiveLength
;
848 UINT64 BaseAlignment
;
850 UINT64 OriginalBaseAddress
;
851 UINT64 OriginalLength
;
855 LeastSubtractiveMtrrNumber
= 0;
859 // Get the optimal left subtraction solution.
861 if (BaseAddress
!= 0) {
863 OriginalBaseAddress
= BaseAddress
;
864 OriginalLength
= Length
;
865 SubtractiveBaseAddress
= 0;
866 SubtractiveLength
= 0;
868 // Get the MTRR number needed without left subtraction.
870 LeastLeftMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
873 // Left subtraction bit by bit, to find the optimal left subtraction solution.
875 for (SubtractiveMtrrNumber
= 0, SubtractiveCount
= 1; BaseAddress
!= 0; SubtractiveCount
++) {
876 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
879 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
880 // IA32 Manual defines the following override rules:
884 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
- Alignment
, Alignment
)) {
888 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
889 if ((VariableMtrr
[Index
].BaseAddress
== BaseAddress
- Alignment
) &&
890 (VariableMtrr
[Index
].Length
== Alignment
)) {
894 if (Index
== VariableMtrrCount
) {
896 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
898 SubtractiveMtrrNumber
++;
901 BaseAddress
-= Alignment
;
904 CurrentMtrrNumber
= SubtractiveMtrrNumber
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
905 if (CurrentMtrrNumber
<= LeastLeftMtrrNumber
) {
906 LeastLeftMtrrNumber
= CurrentMtrrNumber
;
907 LeastSubtractiveMtrrNumber
= SubtractiveMtrrNumber
;
908 *SubLeft
= SubtractiveCount
;
909 SubtractiveBaseAddress
= BaseAddress
;
910 SubtractiveLength
= Length
;
915 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
918 BaseAddress
= SubtractiveBaseAddress
;
919 Length
= SubtractiveLength
;
921 BaseAddress
= OriginalBaseAddress
;
922 Length
= OriginalLength
;
927 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
929 MiddleMtrrNumber
= 0;
930 while (Length
!= 0) {
931 BaseAlignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
932 if (BaseAlignment
> Length
) {
935 BaseAddress
+= BaseAlignment
;
936 Length
-= BaseAlignment
;
942 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
;
947 // Get the optimal right subtraction solution.
951 // Get the MTRR number needed without right subtraction.
953 LeastRightMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
955 for (SubtractiveCount
= 1; Length
< BaseAlignment
; SubtractiveCount
++) {
956 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
957 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
+ Length
, Alignment
)) {
964 // SubtractiveCount = Number of MTRRs used for subtraction
966 CurrentMtrrNumber
= SubtractiveCount
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
967 if (CurrentMtrrNumber
<= LeastRightMtrrNumber
) {
968 LeastRightMtrrNumber
= CurrentMtrrNumber
;
969 *SubRight
= SubtractiveCount
;
970 SubtractiveLength
= Length
;
974 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
+ LeastRightMtrrNumber
;
978 Initializes the valid bits mask and valid address mask for MTRRs.
980 This function initializes the valid bits mask and valid address mask for MTRRs.
982 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
983 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
987 MtrrLibInitializeMtrrMask (
988 OUT UINT64
*MtrrValidBitsMask
,
989 OUT UINT64
*MtrrValidAddressMask
992 UINT32 MaxExtendedFunction
;
993 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
996 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
998 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
999 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
1001 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
1004 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
1005 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
1010 Determines the real attribute of a memory range.
1012 This function is to arbitrate the real attribute of the memory when
1013 there are 2 MTRRs covers the same memory range. For further details,
1014 please refer the IA32 Software Developer's Manual, Volume 3,
1015 Section "MTRR Precedences".
1017 @param[in] MtrrType1 The first kind of Memory type
1018 @param[in] MtrrType2 The second kind of memory type
1021 MTRR_MEMORY_CACHE_TYPE
1023 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
1024 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
1027 if (MtrrType1
== MtrrType2
) {
1032 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
1033 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
1036 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
1044 Worker function will get the memory cache type of the specific address.
1046 If MtrrSetting is not NULL, gets the memory cache type from input
1047 MTRR settings buffer.
1048 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1050 @param[in] MtrrSetting A buffer holding all MTRRs content.
1051 @param[in] Address The specific address
1053 @return Memory cache type of the specific address
1056 MTRR_MEMORY_CACHE_TYPE
1057 MtrrGetMemoryAttributeByAddressWorker (
1058 IN MTRR_SETTINGS
*MtrrSetting
,
1059 IN PHYSICAL_ADDRESS Address
1062 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
1066 MTRR_MEMORY_CACHE_TYPE MtrrType
;
1067 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1068 UINT64 MtrrValidBitsMask
;
1069 UINT64 MtrrValidAddressMask
;
1070 UINT32 VariableMtrrCount
;
1071 MTRR_VARIABLE_SETTINGS VariableSettings
;
1074 // Check if MTRR is enabled, if not, return UC as attribute
1076 if (MtrrSetting
== NULL
) {
1077 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
1079 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
1082 if (DefType
.Bits
.E
== 0) {
1083 return CacheUncacheable
;
1087 // If address is less than 1M, then try to go through the fixed MTRR
1089 if (Address
< BASE_1MB
) {
1090 if (DefType
.Bits
.FE
!= 0) {
1092 // Go through the fixed MTRR
1094 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1095 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1096 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1097 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
1099 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1100 mMtrrLibFixedMtrrTable
[Index
].Length
;
1101 if (MtrrSetting
== NULL
) {
1102 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1104 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1106 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
1112 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1113 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1114 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
1116 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1117 MtrrGetMemoryAttributeInVariableMtrrWorker (
1121 MtrrValidAddressMask
,
1126 // Go through the variable MTRR
1128 MtrrType
= CacheInvalid
;
1129 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1130 if (VariableMtrr
[Index
].Valid
) {
1131 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1132 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
1133 if (MtrrType
== CacheInvalid
) {
1134 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
1136 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
1143 // If there is no MTRR which covers the Address, use the default MTRR type.
1145 if (MtrrType
== CacheInvalid
) {
1146 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
1154 This function will get the memory cache type of the specific address.
1156 This function is mainly for debug purpose.
1158 @param[in] Address The specific address
1160 @return Memory cache type of the specific address
1163 MTRR_MEMORY_CACHE_TYPE
1165 MtrrGetMemoryAttribute (
1166 IN PHYSICAL_ADDRESS Address
1169 if (!IsMtrrSupported ()) {
1170 return CacheUncacheable
;
1173 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1177 Worker function prints all MTRRs for debugging.
1179 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1181 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1183 @param MtrrSetting A buffer holding all MTRRs content.
1186 MtrrDebugPrintAllMtrrsWorker (
1187 IN MTRR_SETTINGS
*MtrrSetting
1191 MTRR_SETTINGS LocalMtrrs
;
1192 MTRR_SETTINGS
*Mtrrs
;
1195 UINTN VariableMtrrCount
;
1203 UINT64 NoRangeLimit
;
1206 UINTN PreviousMemoryType
;
1209 if (!IsMtrrSupported ()) {
1213 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1214 DEBUG((DEBUG_CACHE
, "=============\n"));
1216 if (MtrrSetting
!= NULL
) {
1217 Mtrrs
= MtrrSetting
;
1219 MtrrGetAllMtrrs (&LocalMtrrs
);
1220 Mtrrs
= &LocalMtrrs
;
1223 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1224 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1225 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1228 VariableMtrrCount
= GetVariableMtrrCount ();
1229 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1230 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1232 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1233 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1236 DEBUG((DEBUG_CACHE
, "\n"));
1237 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1238 DEBUG((DEBUG_CACHE
, "====================================\n"));
1241 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1242 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1243 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1244 for (Index1
= 0; Index1
< 8; Index1
++) {
1245 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1246 if (MemoryType
> CacheWriteBack
) {
1247 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1249 if (MemoryType
!= PreviousMemoryType
) {
1250 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1251 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1253 PreviousMemoryType
= MemoryType
;
1254 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1256 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1259 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1261 VariableMtrrCount
= GetVariableMtrrCount ();
1264 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1265 if (RegEax
>= 0x80000008) {
1266 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1267 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1270 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1272 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1273 if (MemoryType
> CacheWriteBack
) {
1274 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1277 if (MemoryType
!= PreviousMemoryType
) {
1278 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1279 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1281 PreviousMemoryType
= MemoryType
;
1282 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1285 RangeBase
= BASE_1MB
;
1286 NoRangeBase
= BASE_1MB
;
1288 NoRangeLimit
= Limit
;
1290 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1291 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1293 // If mask is not valid, then do not display range
1297 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1298 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1300 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1304 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1305 RangeBase
= MtrrBase
;
1307 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1308 RangeBase
= MtrrLimit
+ 1;
1310 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1311 RangeLimit
= MtrrBase
- 1;
1313 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1314 RangeLimit
= MtrrLimit
;
1317 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1318 NoRangeBase
= MtrrLimit
+ 1;
1320 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1321 NoRangeLimit
= MtrrBase
- 1;
1326 Base
= RangeLimit
+ 1;
1328 Base
= NoRangeLimit
+ 1;
1330 } while (Base
< Limit
);
1331 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1337 This function prints all MTRRs for debugging.
1341 MtrrDebugPrintAllMtrrs (
1345 MtrrDebugPrintAllMtrrsWorker (NULL
);
1349 Update the Ranges array to change the specified range identified by
1350 BaseAddress and Length to Type.
1352 @param Ranges Array holding memory type settings for all memory regions.
1353 @param Capacity The maximum count of memory ranges the array can hold.
1354 @param Count Return the new memory range count in the array.
1355 @param BaseAddress The base address of the memory range to change type.
1356 @param Length The length of the memory range to change type.
1357 @param Type The new type of the specified memory range.
1359 @retval RETURN_SUCCESS The type of the specified memory range is
1360 changed successfully.
1361 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1362 range exceeds capacity.
1365 MtrrLibSetMemoryType (
1366 IN MEMORY_RANGE
*Ranges
,
1368 IN OUT UINT32
*Count
,
1369 IN UINT64 BaseAddress
,
1371 IN MTRR_MEMORY_CACHE_TYPE Type
1384 Limit
= BaseAddress
+ Length
;
1385 StartIndex
= *Count
;
1387 for (Index
= 0; Index
< *Count
; Index
++) {
1388 if ((StartIndex
== *Count
) &&
1389 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1390 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1392 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1395 if ((EndIndex
== *Count
) &&
1396 (Ranges
[Index
].BaseAddress
< Limit
) &&
1397 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1399 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1404 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1405 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1406 return RETURN_SUCCESS
;
1410 // The type change may cause merging with previous range or next range.
1411 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1412 // logic doesn't need to consider merging.
1414 if (StartIndex
!= 0) {
1415 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1417 Length
+= Ranges
[StartIndex
].Length
;
1418 BaseAddress
-= Ranges
[StartIndex
].Length
;
1421 if (EndIndex
!= (*Count
) - 1) {
1422 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1424 Length
+= Ranges
[EndIndex
].Length
;
1429 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1430 // |++++++++++++++++++| 0 3 1=3-0-2 3
1431 // |+++++++| 0 1 -1=1-0-2 5
1432 // |+| 0 0 -2=0-0-2 6
1433 // |+++| 0 0 -1=0-0-2+1 5
1436 DeltaCount
= EndIndex
- StartIndex
- 2;
1437 if (LengthLeft
== 0) {
1440 if (LengthRight
== 0) {
1443 if (*Count
- DeltaCount
> Capacity
) {
1444 return RETURN_OUT_OF_RESOURCES
;
1448 // Reserve (-DeltaCount) space
1450 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1451 *Count
-= DeltaCount
;
1453 if (LengthLeft
!= 0) {
1454 Ranges
[StartIndex
].Length
= LengthLeft
;
1457 if (LengthRight
!= 0) {
1458 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1459 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1460 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1462 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1463 Ranges
[StartIndex
].Length
= Length
;
1464 Ranges
[StartIndex
].Type
= Type
;
1465 return RETURN_SUCCESS
;
1469 Allocate one or more variable MTRR to cover the range identified by
1470 BaseAddress and Length.
1472 @param Ranges Memory range array holding the memory type
1473 settings for all memory address.
1474 @param RangeCount Count of memory ranges.
1475 @param VariableMtrr Variable MTRR array.
1476 @param VariableMtrrCapacity Capacity of variable MTRR array.
1477 @param VariableMtrrCount Count of variable MTRR.
1478 @param BaseAddress Base address of the memory range.
1479 @param Length Length of the memory range.
1480 @param Type MTRR type of the memory range.
1481 @param Alignment0 Alignment of 0.
1483 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1484 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1487 MtrrLibSetMemoryAttributeInVariableMtrr (
1488 IN CONST MEMORY_RANGE
*Ranges
,
1489 IN UINT32 RangeCount
,
1490 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1491 IN UINT32 VariableMtrrCapacity
,
1492 IN OUT UINT32
*VariableMtrrCount
,
1493 IN UINT64 BaseAddress
,
1495 IN MTRR_MEMORY_CACHE_TYPE Type
,
1496 IN UINT64 Alignment0
1500 Allocate one or more variable MTRR to cover the range identified by
1501 BaseAddress and Length.
1503 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1504 to allocate variable MTRRs when the range contains several sub-ranges
1505 with different attributes.
1507 @param Ranges Memory range array holding the memory type
1508 settings for all memory address.
1509 @param RangeCount Count of memory ranges.
1510 @param VariableMtrr Variable MTRR array.
1511 @param VariableMtrrCapacity Capacity of variable MTRR array.
1512 @param VariableMtrrCount Count of variable MTRR.
1513 @param BaseAddress Base address of the memory range.
1514 @param Length Length of the memory range.
1515 @param Type MTRR type of the range.
1516 If it's CacheInvalid, the memory range may
1517 contains several sub-ranges with different
1519 @param Alignment0 Alignment of 0.
1521 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1522 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1525 MtrrLibAddVariableMtrr (
1526 IN CONST MEMORY_RANGE
*Ranges
,
1527 IN UINT32 RangeCount
,
1528 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1529 IN UINT32 VariableMtrrCapacity
,
1530 IN OUT UINT32
*VariableMtrrCount
,
1531 IN PHYSICAL_ADDRESS BaseAddress
,
1533 IN MTRR_MEMORY_CACHE_TYPE Type
,
1534 IN UINT64 Alignment0
1537 RETURN_STATUS Status
;
1541 MTRR_LIB_ASSERT_ALIGNED (BaseAddress
, Length
);
1542 if (Type
== CacheInvalid
) {
1543 ASSERT (Ranges
!= NULL
);
1544 for (Index
= 0; Index
< RangeCount
; Index
++) {
1545 if (Ranges
[Index
].BaseAddress
<= BaseAddress
&& BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1548 // Because the Length may not be aligned to BaseAddress, below code calls
1549 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1550 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1553 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= BaseAddress
+ Length
) {
1554 return MtrrLibSetMemoryAttributeInVariableMtrr (
1555 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1556 BaseAddress
, Length
, Ranges
[Index
].Type
, Alignment0
1559 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1560 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1561 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1562 BaseAddress
, SubLength
, Ranges
[Index
].Type
, Alignment0
1564 if (RETURN_ERROR (Status
)) {
1567 BaseAddress
+= SubLength
;
1568 Length
-= SubLength
;
1574 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1577 return RETURN_DEVICE_ERROR
;
1579 for (Index
= 0; Index
< *VariableMtrrCount
; Index
++) {
1580 if (VariableMtrr
[Index
].BaseAddress
== BaseAddress
&& VariableMtrr
[Index
].Length
== Length
) {
1581 ASSERT (VariableMtrr
[Index
].Type
== Type
);
1585 if (Index
== *VariableMtrrCount
) {
1586 if (*VariableMtrrCount
== VariableMtrrCapacity
) {
1587 return RETURN_OUT_OF_RESOURCES
;
1589 VariableMtrr
[Index
].BaseAddress
= BaseAddress
;
1590 VariableMtrr
[Index
].Length
= Length
;
1591 VariableMtrr
[Index
].Type
= Type
;
1592 VariableMtrr
[Index
].Valid
= TRUE
;
1593 VariableMtrr
[Index
].Used
= TRUE
;
1594 (*VariableMtrrCount
)++;
1596 return RETURN_SUCCESS
;
1601 Allocate one or more variable MTRR to cover the range identified by
1602 BaseAddress and Length.
1604 @param Ranges Memory range array holding the memory type
1605 settings for all memory address.
1606 @param RangeCount Count of memory ranges.
1607 @param VariableMtrr Variable MTRR array.
1608 @param VariableMtrrCapacity Capacity of variable MTRR array.
1609 @param VariableMtrrCount Count of variable MTRR.
1610 @param BaseAddress Base address of the memory range.
1611 @param Length Length of the memory range.
1612 @param Type MTRR type of the memory range.
1613 @param Alignment0 Alignment of 0.
1615 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1616 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1619 MtrrLibSetMemoryAttributeInVariableMtrr (
1620 IN CONST MEMORY_RANGE
*Ranges
,
1621 IN UINT32 RangeCount
,
1622 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1623 IN UINT32 VariableMtrrCapacity
,
1624 IN OUT UINT32
*VariableMtrrCount
,
1625 IN UINT64 BaseAddress
,
1627 IN MTRR_MEMORY_CACHE_TYPE Type
,
1628 IN UINT64 Alignment0
1633 UINT32 SubtractiveLeft
;
1634 UINT32 SubtractiveRight
;
1635 BOOLEAN UseLeastAlignment
;
1639 MtrrNumber
= MtrrLibGetMtrrNumber (Ranges
, RangeCount
, VariableMtrr
, *VariableMtrrCount
,
1640 BaseAddress
, Length
, Type
, Alignment0
, &SubtractiveLeft
, &SubtractiveRight
);
1642 if (MtrrNumber
+ *VariableMtrrCount
> VariableMtrrCapacity
) {
1643 return RETURN_OUT_OF_RESOURCES
;
1646 while (SubtractiveLeft
-- != 0) {
1647 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1648 ASSERT (Alignment
<= Length
);
1650 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1651 BaseAddress
- Alignment
, Alignment
, CacheInvalid
, Alignment0
);
1652 BaseAddress
-= Alignment
;
1653 Length
+= Alignment
;
1656 while (Length
!= 0) {
1657 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1658 if (Alignment
> Length
) {
1661 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1662 BaseAddress
, Alignment
, Type
, Alignment0
);
1663 BaseAddress
+= Alignment
;
1664 Length
-= Alignment
;
1667 while (SubtractiveRight
-- != 0) {
1668 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
1669 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1670 BaseAddress
+ Length
, Alignment
, CacheInvalid
, Alignment0
);
1671 Length
+= Alignment
;
1674 UseLeastAlignment
= TRUE
;
1675 while (Length
!= 0) {
1676 if (UseLeastAlignment
) {
1677 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1678 if (Alignment
> Length
) {
1679 UseLeastAlignment
= FALSE
;
1683 if (!UseLeastAlignment
) {
1684 Alignment
= GetPowerOfTwo64 (Length
);
1687 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1688 BaseAddress
, Alignment
, Type
, Alignment0
);
1689 BaseAddress
+= Alignment
;
1690 Length
-= Alignment
;
1692 return RETURN_SUCCESS
;
1696 Return an array of memory ranges holding memory type settings for all memory
1699 @param DefaultType The default memory type.
1700 @param TotalLength The total length of the memory.
1701 @param VariableMtrr The variable MTRR array.
1702 @param VariableMtrrCount The count of variable MTRRs.
1703 @param Ranges Return the memory range array holding memory type
1704 settings for all memory address.
1705 @param RangeCapacity The capacity of memory range array.
1706 @param RangeCount Return the count of memory range.
1708 @retval RETURN_SUCCESS The memory range array is returned successfully.
1709 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1712 MtrrLibGetMemoryTypes (
1713 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1714 IN UINT64 TotalLength
,
1715 IN CONST VARIABLE_MTRR
*VariableMtrr
,
1716 IN UINT32 VariableMtrrCount
,
1717 OUT MEMORY_RANGE
*Ranges
,
1718 IN UINT32 RangeCapacity
,
1719 OUT UINT32
*RangeCount
1722 RETURN_STATUS Status
;
1728 // UC > * (except WB, UC) > WB
1732 // 0. Set whole range as DefaultType
1735 Ranges
[0].BaseAddress
= 0;
1736 Ranges
[0].Length
= TotalLength
;
1737 Ranges
[0].Type
= DefaultType
;
1742 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1743 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheWriteBack
) {
1744 Status
= MtrrLibSetMemoryType (
1745 Ranges
, RangeCapacity
, RangeCount
,
1746 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1748 if (RETURN_ERROR (Status
)) {
1755 // 2. Set other types than WB or UC
1757 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1758 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
!= CacheWriteBack
&& VariableMtrr
[Index
].Type
!= CacheUncacheable
) {
1759 Status
= MtrrLibSetMemoryType (
1760 Ranges
, RangeCapacity
, RangeCount
,
1761 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1763 if (RETURN_ERROR (Status
)) {
1772 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1773 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1774 Status
= MtrrLibSetMemoryType (
1775 Ranges
, RangeCapacity
, RangeCount
,
1776 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1778 if (RETURN_ERROR (Status
)) {
1783 return RETURN_SUCCESS
;
1787 Worker function attempts to set the attributes for a memory range.
1789 If MtrrSetting is not NULL, set the attributes into the input MTRR
1791 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1793 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1794 @param[in] BaseAddress The physical address that is the start
1795 address of a memory range.
1796 @param[in] Length The size in bytes of the memory range.
1797 @param[in] Type The MTRR type to set for the memory range.
1799 @retval RETURN_SUCCESS The attributes were set for the memory
1801 @retval RETURN_INVALID_PARAMETER Length is zero.
1802 @retval RETURN_UNSUPPORTED The processor does not support one or
1803 more bytes of the memory resource range
1804 specified by BaseAddress and Length.
1805 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1806 memory resource range specified
1807 by BaseAddress and Length.
1808 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1809 modify the attributes of the memory
1814 MtrrSetMemoryAttributeWorker (
1815 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1816 IN PHYSICAL_ADDRESS BaseAddress
,
1818 IN MTRR_MEMORY_CACHE_TYPE Type
1821 RETURN_STATUS Status
;
1823 UINT32 WorkingIndex
;
1825 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1827 MEMORY_RANGE Ranges
[MTRR_NUMBER_OF_VARIABLE_MTRR
* 2 + 2];
1829 UINT64 MtrrValidBitsMask
;
1830 UINT64 MtrrValidAddressMask
;
1832 MTRR_CONTEXT MtrrContext
;
1833 BOOLEAN MtrrContextValid
;
1835 MTRR_MEMORY_CACHE_TYPE DefaultType
;
1841 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1842 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1843 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1845 UINT32 FirmwareVariableMtrrCount
;
1846 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1847 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1848 UINT32 OriginalVariableMtrrCount
;
1849 VARIABLE_MTRR OriginalVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1850 UINT32 WorkingVariableMtrrCount
;
1851 VARIABLE_MTRR WorkingVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1852 BOOLEAN VariableSettingModified
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1853 UINTN FreeVariableMtrrCount
;
1856 return RETURN_INVALID_PARAMETER
;
1859 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1860 if (((BaseAddress
& ~MtrrValidAddressMask
) != 0) || (Length
& ~MtrrValidAddressMask
) != 0) {
1861 return RETURN_UNSUPPORTED
;
1863 OriginalVariableMtrrCount
= 0;
1864 VariableSettings
= NULL
;
1866 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1867 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1868 FixedSettingsValid
[Index
] = FALSE
;
1869 FixedSettingsModified
[Index
] = FALSE
;
1873 // Check if Fixed MTRR
1875 if (BaseAddress
< BASE_1MB
) {
1876 MsrIndex
= (UINT32
)-1;
1877 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
1878 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
1879 if (RETURN_ERROR (Status
)) {
1882 if (MtrrSetting
!= NULL
) {
1883 MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] = (MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1884 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
1886 if (!FixedSettingsValid
[MsrIndex
]) {
1887 WorkingFixedSettings
.Mtrr
[MsrIndex
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrIndex
].Msr
);
1888 FixedSettingsValid
[MsrIndex
] = TRUE
;
1890 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1891 if (WorkingFixedSettings
.Mtrr
[MsrIndex
] != NewValue
) {
1892 WorkingFixedSettings
.Mtrr
[MsrIndex
] = NewValue
;
1893 FixedSettingsModified
[MsrIndex
] = TRUE
;
1900 // A Length of 0 can only make sense for fixed MTTR ranges.
1901 // Since we just handled the fixed MTRRs, we can skip the
1902 // variable MTRR section.
1909 // Read the default MTRR type
1911 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1914 // Read all variable MTRRs and convert to Ranges.
1916 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
1917 if (MtrrSetting
== NULL
) {
1918 ZeroMem (&OriginalVariableSettings
, sizeof (OriginalVariableSettings
));
1919 MtrrGetVariableMtrrWorker (NULL
, OriginalVariableMtrrCount
, &OriginalVariableSettings
);
1920 VariableSettings
= &OriginalVariableSettings
;
1922 VariableSettings
= &MtrrSetting
->Variables
;
1924 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings
, OriginalVariableMtrrCount
, MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
);
1926 Status
= MtrrLibGetMemoryTypes (
1927 DefaultType
, MtrrValidBitsMask
+ 1, OriginalVariableMtrr
, OriginalVariableMtrrCount
,
1928 Ranges
, 2 * OriginalVariableMtrrCount
+ 1, &RangeCount
1930 ASSERT (Status
== RETURN_SUCCESS
);
1932 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1933 ASSERT (RangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
1936 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1938 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, 0, SIZE_1MB
, CacheUncacheable
);
1939 ASSERT (Status
== RETURN_SUCCESS
);
1941 // Apply Type to [BaseAddress, BaseAddress + Length)
1943 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, BaseAddress
, Length
, Type
);
1944 if (RETURN_ERROR (Status
)) {
1948 Alignment0
= LShiftU64 (1, (UINTN
) HighBitSet64 (MtrrValidBitsMask
));
1949 WorkingVariableMtrrCount
= 0;
1950 ZeroMem (&WorkingVariableMtrr
, sizeof (WorkingVariableMtrr
));
1951 for (Index
= 0; Index
< RangeCount
; Index
++) {
1952 if (Ranges
[Index
].Type
!= DefaultType
) {
1954 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
1955 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
1957 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1959 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
,
1960 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
,
1961 Ranges
[Index
].Type
, Alignment0
1963 if (RETURN_ERROR (Status
)) {
1970 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
1972 if (WorkingVariableMtrr
[0].BaseAddress
== 0 && WorkingVariableMtrr
[0].Length
== SIZE_1MB
) {
1973 ASSERT (WorkingVariableMtrr
[0].Type
== CacheUncacheable
);
1974 WorkingVariableMtrrCount
--;
1975 CopyMem (&WorkingVariableMtrr
[0], &WorkingVariableMtrr
[1], WorkingVariableMtrrCount
* sizeof (VARIABLE_MTRR
));
1978 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
1979 return RETURN_OUT_OF_RESOURCES
;
1982 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
1983 VariableSettingModified
[Index
] = FALSE
;
1985 if (!OriginalVariableMtrr
[Index
].Valid
) {
1988 for (WorkingIndex
= 0; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
1989 if (OriginalVariableMtrr
[Index
].BaseAddress
== WorkingVariableMtrr
[WorkingIndex
].BaseAddress
&&
1990 OriginalVariableMtrr
[Index
].Length
== WorkingVariableMtrr
[WorkingIndex
].Length
&&
1991 OriginalVariableMtrr
[Index
].Type
== WorkingVariableMtrr
[WorkingIndex
].Type
) {
1996 if (WorkingIndex
== WorkingVariableMtrrCount
) {
1998 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2000 OriginalVariableMtrr
[Index
].Valid
= FALSE
;
2001 VariableSettingModified
[Index
] = TRUE
;
2004 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2006 WorkingVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2009 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2014 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2016 for (FreeVariableMtrrCount
= 0, WorkingIndex
= 0, Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2017 if (!OriginalVariableMtrr
[Index
].Valid
) {
2018 for (; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
2019 if (WorkingVariableMtrr
[WorkingIndex
].Valid
) {
2023 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2024 FreeVariableMtrrCount
++;
2026 CopyMem (&OriginalVariableMtrr
[Index
], &WorkingVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2027 VariableSettingModified
[Index
] = TRUE
;
2032 ASSERT (OriginalVariableMtrrCount
- FreeVariableMtrrCount
<= FirmwareVariableMtrrCount
);
2035 // Move MTRRs after the FirmwareVariableMtrrCount position to beginning
2037 if (FirmwareVariableMtrrCount
< OriginalVariableMtrrCount
) {
2038 WorkingIndex
= FirmwareVariableMtrrCount
;
2039 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
2040 if (!OriginalVariableMtrr
[Index
].Valid
) {
2042 // Found an empty MTRR in WorkingIndex position
2044 for (; WorkingIndex
< OriginalVariableMtrrCount
; WorkingIndex
++) {
2045 if (OriginalVariableMtrr
[WorkingIndex
].Valid
) {
2050 if (WorkingIndex
!= OriginalVariableMtrrCount
) {
2051 CopyMem (&OriginalVariableMtrr
[Index
], &OriginalVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2052 VariableSettingModified
[Index
] = TRUE
;
2053 VariableSettingModified
[WorkingIndex
] = TRUE
;
2054 OriginalVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2061 // Convert OriginalVariableMtrr to VariableSettings
2062 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2064 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2065 if (VariableSettingModified
[Index
]) {
2066 if (OriginalVariableMtrr
[Index
].Valid
) {
2067 VariableSettings
->Mtrr
[Index
].Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
) | (UINT8
) OriginalVariableMtrr
[Index
].Type
;
2068 VariableSettings
->Mtrr
[Index
].Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2070 VariableSettings
->Mtrr
[Index
].Base
= 0;
2071 VariableSettings
->Mtrr
[Index
].Mask
= 0;
2077 if (MtrrSetting
!= NULL
) {
2078 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2079 return RETURN_SUCCESS
;
2082 MtrrContextValid
= FALSE
;
2084 // Write fixed MTRRs that have been modified
2086 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2087 if (FixedSettingsModified
[Index
]) {
2088 if (!MtrrContextValid
) {
2089 MtrrLibPreMtrrChange (&MtrrContext
);
2090 MtrrContextValid
= TRUE
;
2093 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2094 WorkingFixedSettings
.Mtrr
[Index
]
2100 // Write variable MTRRs
2101 // When only fixed MTRRs were changed, below loop doesn't run
2102 // because OriginalVariableMtrrCount equals to 0.
2104 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2105 if (VariableSettingModified
[Index
]) {
2106 if (!MtrrContextValid
) {
2107 MtrrLibPreMtrrChange (&MtrrContext
);
2108 MtrrContextValid
= TRUE
;
2111 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2112 VariableSettings
->Mtrr
[Index
].Base
2115 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2116 VariableSettings
->Mtrr
[Index
].Mask
2120 if (MtrrContextValid
) {
2121 MtrrLibPostMtrrChange (&MtrrContext
);
2124 return RETURN_SUCCESS
;
2128 This function attempts to set the attributes for a memory range.
2130 @param[in] BaseAddress The physical address that is the start
2131 address of a memory range.
2132 @param[in] Length The size in bytes of the memory range.
2133 @param[in] Attributes The bit mask of attributes to set for the
2136 @retval RETURN_SUCCESS The attributes were set for the memory
2138 @retval RETURN_INVALID_PARAMETER Length is zero.
2139 @retval RETURN_UNSUPPORTED The processor does not support one or
2140 more bytes of the memory resource range
2141 specified by BaseAddress and Length.
2142 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2143 for the memory resource range specified
2144 by BaseAddress and Length.
2145 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2146 range specified by BaseAddress and Length
2148 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2149 modify the attributes of the memory
2155 MtrrSetMemoryAttribute (
2156 IN PHYSICAL_ADDRESS BaseAddress
,
2158 IN MTRR_MEMORY_CACHE_TYPE Attribute
2161 RETURN_STATUS Status
;
2163 if (!IsMtrrSupported ()) {
2164 return RETURN_UNSUPPORTED
;
2167 Status
= MtrrSetMemoryAttributeWorker (NULL
, BaseAddress
, Length
, Attribute
);
2168 DEBUG ((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2169 mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2171 if (!RETURN_ERROR (Status
)) {
2172 MtrrDebugPrintAllMtrrsWorker (NULL
);
2178 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2180 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2181 @param[in] BaseAddress The physical address that is the start address
2183 @param[in] Length The size in bytes of the memory range.
2184 @param[in] Attribute The bit mask of attributes to set for the
2187 @retval RETURN_SUCCESS The attributes were set for the memory range.
2188 @retval RETURN_INVALID_PARAMETER Length is zero.
2189 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2190 memory resource range specified by BaseAddress and Length.
2191 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2192 range specified by BaseAddress and Length.
2193 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2194 BaseAddress and Length cannot be modified.
2195 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2196 the memory resource range.
2201 MtrrSetMemoryAttributeInMtrrSettings (
2202 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2203 IN PHYSICAL_ADDRESS BaseAddress
,
2205 IN MTRR_MEMORY_CACHE_TYPE Attribute
2208 RETURN_STATUS Status
;
2209 Status
= MtrrSetMemoryAttributeWorker (MtrrSetting
, BaseAddress
, Length
, Attribute
);
2210 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2211 MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2213 if (!RETURN_ERROR (Status
)) {
2214 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2221 Worker function setting variable MTRRs
2223 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2227 MtrrSetVariableMtrrWorker (
2228 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2232 UINT32 VariableMtrrCount
;
2234 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2235 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
2237 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2239 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2240 VariableSettings
->Mtrr
[Index
].Base
2243 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2244 VariableSettings
->Mtrr
[Index
].Mask
2251 This function sets variable MTRRs
2253 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2255 @return The pointer of VariableSettings
2258 MTRR_VARIABLE_SETTINGS
*
2260 MtrrSetVariableMtrr (
2261 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2264 MTRR_CONTEXT MtrrContext
;
2266 if (!IsMtrrSupported ()) {
2267 return VariableSettings
;
2270 MtrrLibPreMtrrChange (&MtrrContext
);
2271 MtrrSetVariableMtrrWorker (VariableSettings
);
2272 MtrrLibPostMtrrChange (&MtrrContext
);
2273 MtrrDebugPrintAllMtrrs ();
2275 return VariableSettings
;
2279 Worker function setting fixed MTRRs
2281 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2285 MtrrSetFixedMtrrWorker (
2286 IN MTRR_FIXED_SETTINGS
*FixedSettings
2291 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2293 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2294 FixedSettings
->Mtrr
[Index
]
2301 This function sets fixed MTRRs
2303 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2305 @retval The pointer of FixedSettings
2308 MTRR_FIXED_SETTINGS
*
2311 IN MTRR_FIXED_SETTINGS
*FixedSettings
2314 MTRR_CONTEXT MtrrContext
;
2316 if (!IsMtrrSupported ()) {
2317 return FixedSettings
;
2320 MtrrLibPreMtrrChange (&MtrrContext
);
2321 MtrrSetFixedMtrrWorker (FixedSettings
);
2322 MtrrLibPostMtrrChange (&MtrrContext
);
2323 MtrrDebugPrintAllMtrrs ();
2325 return FixedSettings
;
2330 This function gets the content in all MTRRs (variable and fixed)
2332 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2334 @retval the pointer of MtrrSetting
2340 OUT MTRR_SETTINGS
*MtrrSetting
2343 if (!IsMtrrSupported ()) {
2350 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2353 // Get variable MTRRs
2355 MtrrGetVariableMtrrWorker (
2357 GetVariableMtrrCountWorker (),
2358 &MtrrSetting
->Variables
2362 // Get MTRR_DEF_TYPE value
2364 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2371 This function sets all MTRRs (variable and fixed)
2373 @param[in] MtrrSetting A buffer holding all MTRRs content.
2375 @retval The pointer of MtrrSetting
2381 IN MTRR_SETTINGS
*MtrrSetting
2384 MTRR_CONTEXT MtrrContext
;
2386 if (!IsMtrrSupported ()) {
2390 MtrrLibPreMtrrChange (&MtrrContext
);
2395 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2398 // Set variable MTRRs
2400 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2403 // Set MTRR_DEF_TYPE value
2405 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2407 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2414 Checks if MTRR is supported.
2416 @retval TRUE MTRR is supported.
2417 @retval FALSE MTRR is not supported.
2426 CPUID_VERSION_INFO_EDX Edx
;
2427 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2430 // Check CPUID(1).EDX[12] for MTRR capability
2432 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2433 if (Edx
.Bits
.MTRR
== 0) {
2438 // Check number of variable MTRRs and fixed MTRRs existence.
2439 // If number of variable MTRRs is zero, or fixed MTRRs do not
2440 // exist, return false.
2442 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2443 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {