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 biggest alignment (lowest set bit) of address.
660 The function is equivalent to: 1 << LowBitSet64 (Address).
662 @param Address The address to return the alignment.
663 @param Alignment0 The alignment to return when Address is 0.
665 @return The least alignment of the Address.
668 MtrrLibBiggestAlignment (
677 return Address
& ((~Address
) + 1);
681 Return the number of required variable MTRRs to positively cover the
684 @param BaseAddress Base address of the range.
685 @param Length Length of the range.
686 @param Alignment0 Alignment of 0.
688 @return The number of the required variable MTRRs.
691 MtrrLibGetPositiveMtrrNumber (
692 IN UINT64 BaseAddress
,
699 BOOLEAN UseLeastAlignment
;
701 UseLeastAlignment
= TRUE
;
705 // Calculate the alignment of the base address.
707 for (MtrrNumber
= 0; Length
!= 0; MtrrNumber
++) {
708 if (UseLeastAlignment
) {
709 SubLength
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
711 if (SubLength
> Length
) {
713 // Set a flag when remaining length is too small
714 // so that MtrrLibBiggestAlignment() is not called in following loops.
716 UseLeastAlignment
= FALSE
;
720 if (!UseLeastAlignment
) {
721 SubLength
= GetPowerOfTwo64 (Length
);
724 BaseAddress
+= SubLength
;
732 Return whether the left MTRR type precedes the right MTRR type.
734 The MTRR type precedence rules are:
735 1. UC precedes any other type
737 For further details, please refer the IA32 Software Developer's Manual,
738 Volume 3, Section "MTRR Precedences".
740 @param Left The left MTRR type.
741 @param Right The right MTRR type.
743 @retval TRUE Left precedes Right.
744 @retval FALSE Left doesn't precede Right.
747 MtrrLibTypeLeftPrecedeRight (
748 IN MTRR_MEMORY_CACHE_TYPE Left
,
749 IN MTRR_MEMORY_CACHE_TYPE Right
752 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
757 Return whether the type of the specified range can precede the specified type.
759 @param Ranges Memory range array holding memory type settings for all
761 @param RangeCount Count of memory ranges.
762 @param Type Type to check precedence.
763 @param SubBase Base address of the specified range.
764 @param SubLength Length of the specified range.
766 @retval TRUE The type of the specified range can precede the Type.
767 @retval FALSE The type of the specified range cannot precede the Type.
768 So the subtraction is not applicable.
771 MtrrLibSubstractable (
772 IN CONST MEMORY_RANGE
*Ranges
,
773 IN UINT32 RangeCount
,
774 IN MTRR_MEMORY_CACHE_TYPE Type
,
783 for (Index
= 0; Index
< RangeCount
; Index
++) {
784 if (Ranges
[Index
].BaseAddress
<= SubBase
&& SubBase
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
786 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= SubBase
+ SubLength
) {
787 return MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
);
790 if (!MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
)) {
794 Length
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- SubBase
;
806 Return the number of required variable MTRRs to cover the specified range.
808 The routine considers subtraction in the both side of the range to find out
809 the most optimal solution (which uses the least MTRRs).
811 @param Ranges Array holding memory type settings of all memory
813 @param RangeCount Count of memory ranges.
814 @param VariableMtrr Array holding allocated variable MTRRs.
815 @param VariableMtrrCount Count of allocated variable MTRRs.
816 @param BaseAddress Base address of the specified range.
817 @param Length Length of the specified range.
818 @param Type MTRR type of the specified range.
819 @param Alignment0 Alignment of 0.
820 @param SubLeft Return the count of left subtraction.
821 @param SubRight Return the count of right subtraction.
823 @return Number of required variable MTRRs.
826 MtrrLibGetMtrrNumber (
827 IN CONST MEMORY_RANGE
*Ranges
,
828 IN UINT32 RangeCount
,
829 IN CONST VARIABLE_MTRR
*VariableMtrr
,
830 IN UINT32 VariableMtrrCount
,
831 IN UINT64 BaseAddress
,
833 IN MTRR_MEMORY_CACHE_TYPE Type
,
834 IN UINT64 Alignment0
,
835 OUT UINT32
*SubLeft
, // subtractive from BaseAddress to get more aligned address, to save MTRR
836 OUT UINT32
*SubRight
// subtractive from BaseAddress + Length, to save MTRR
840 UINT32 LeastLeftMtrrNumber
;
841 UINT32 MiddleMtrrNumber
;
842 UINT32 LeastRightMtrrNumber
;
843 UINT32 CurrentMtrrNumber
;
844 UINT32 SubtractiveCount
;
845 UINT32 SubtractiveMtrrNumber
;
846 UINT32 LeastSubtractiveMtrrNumber
;
847 UINT64 SubtractiveBaseAddress
;
848 UINT64 SubtractiveLength
;
849 UINT64 BaseAlignment
;
851 UINT64 OriginalBaseAddress
;
852 UINT64 OriginalLength
;
856 LeastSubtractiveMtrrNumber
= 0;
860 // Get the optimal left subtraction solution.
862 if (BaseAddress
!= 0) {
864 OriginalBaseAddress
= BaseAddress
;
865 OriginalLength
= Length
;
866 SubtractiveBaseAddress
= 0;
867 SubtractiveLength
= 0;
869 // Get the MTRR number needed without left subtraction.
871 LeastLeftMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
874 // Left subtraction bit by bit, to find the optimal left subtraction solution.
876 for (SubtractiveMtrrNumber
= 0, SubtractiveCount
= 1; BaseAddress
!= 0; SubtractiveCount
++) {
877 Alignment
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
880 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
881 // IA32 Manual defines the following override rules:
885 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
- Alignment
, Alignment
)) {
889 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
890 if ((VariableMtrr
[Index
].BaseAddress
== BaseAddress
- Alignment
) &&
891 (VariableMtrr
[Index
].Length
== Alignment
)) {
895 if (Index
== VariableMtrrCount
) {
897 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
899 SubtractiveMtrrNumber
++;
902 BaseAddress
-= Alignment
;
905 CurrentMtrrNumber
= SubtractiveMtrrNumber
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
906 if (CurrentMtrrNumber
<= LeastLeftMtrrNumber
) {
907 LeastLeftMtrrNumber
= CurrentMtrrNumber
;
908 LeastSubtractiveMtrrNumber
= SubtractiveMtrrNumber
;
909 *SubLeft
= SubtractiveCount
;
910 SubtractiveBaseAddress
= BaseAddress
;
911 SubtractiveLength
= Length
;
916 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
919 BaseAddress
= SubtractiveBaseAddress
;
920 Length
= SubtractiveLength
;
922 BaseAddress
= OriginalBaseAddress
;
923 Length
= OriginalLength
;
928 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
930 MiddleMtrrNumber
= 0;
931 while (Length
!= 0) {
932 BaseAlignment
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
933 if (BaseAlignment
> Length
) {
936 BaseAddress
+= BaseAlignment
;
937 Length
-= BaseAlignment
;
943 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
;
948 // Get the optimal right subtraction solution.
952 // Get the MTRR number needed without right subtraction.
954 LeastRightMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
956 for (SubtractiveCount
= 1; Length
< BaseAlignment
; SubtractiveCount
++) {
957 Alignment
= MtrrLibBiggestAlignment (BaseAddress
+ Length
, Alignment0
);
958 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
+ Length
, Alignment
)) {
965 // SubtractiveCount = Number of MTRRs used for subtraction
967 CurrentMtrrNumber
= SubtractiveCount
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
968 if (CurrentMtrrNumber
<= LeastRightMtrrNumber
) {
969 LeastRightMtrrNumber
= CurrentMtrrNumber
;
970 *SubRight
= SubtractiveCount
;
971 SubtractiveLength
= Length
;
975 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
+ LeastRightMtrrNumber
;
979 Initializes the valid bits mask and valid address mask for MTRRs.
981 This function initializes the valid bits mask and valid address mask for MTRRs.
983 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
984 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
988 MtrrLibInitializeMtrrMask (
989 OUT UINT64
*MtrrValidBitsMask
,
990 OUT UINT64
*MtrrValidAddressMask
993 UINT32 MaxExtendedFunction
;
994 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
997 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
999 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
1000 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
1002 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
1005 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
1006 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
1011 Determines the real attribute of a memory range.
1013 This function is to arbitrate the real attribute of the memory when
1014 there are 2 MTRRs covers the same memory range. For further details,
1015 please refer the IA32 Software Developer's Manual, Volume 3,
1016 Section "MTRR Precedences".
1018 @param[in] MtrrType1 The first kind of Memory type
1019 @param[in] MtrrType2 The second kind of memory type
1022 MTRR_MEMORY_CACHE_TYPE
1024 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
1025 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
1028 if (MtrrType1
== MtrrType2
) {
1033 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
1034 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
1037 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
1045 Worker function will get the memory cache type of the specific address.
1047 If MtrrSetting is not NULL, gets the memory cache type from input
1048 MTRR settings buffer.
1049 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1051 @param[in] MtrrSetting A buffer holding all MTRRs content.
1052 @param[in] Address The specific address
1054 @return Memory cache type of the specific address
1057 MTRR_MEMORY_CACHE_TYPE
1058 MtrrGetMemoryAttributeByAddressWorker (
1059 IN MTRR_SETTINGS
*MtrrSetting
,
1060 IN PHYSICAL_ADDRESS Address
1063 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
1067 MTRR_MEMORY_CACHE_TYPE MtrrType
;
1068 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1069 UINT64 MtrrValidBitsMask
;
1070 UINT64 MtrrValidAddressMask
;
1071 UINT32 VariableMtrrCount
;
1072 MTRR_VARIABLE_SETTINGS VariableSettings
;
1075 // Check if MTRR is enabled, if not, return UC as attribute
1077 if (MtrrSetting
== NULL
) {
1078 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
1080 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
1083 if (DefType
.Bits
.E
== 0) {
1084 return CacheUncacheable
;
1088 // If address is less than 1M, then try to go through the fixed MTRR
1090 if (Address
< BASE_1MB
) {
1091 if (DefType
.Bits
.FE
!= 0) {
1093 // Go through the fixed MTRR
1095 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1096 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1097 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1098 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
1100 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1101 mMtrrLibFixedMtrrTable
[Index
].Length
;
1102 if (MtrrSetting
== NULL
) {
1103 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1105 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1107 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
1113 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1114 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1115 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
1117 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1118 MtrrGetMemoryAttributeInVariableMtrrWorker (
1122 MtrrValidAddressMask
,
1127 // Go through the variable MTRR
1129 MtrrType
= CacheInvalid
;
1130 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1131 if (VariableMtrr
[Index
].Valid
) {
1132 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1133 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
1134 if (MtrrType
== CacheInvalid
) {
1135 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
1137 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
1144 // If there is no MTRR which covers the Address, use the default MTRR type.
1146 if (MtrrType
== CacheInvalid
) {
1147 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
1155 This function will get the memory cache type of the specific address.
1157 This function is mainly for debug purpose.
1159 @param[in] Address The specific address
1161 @return Memory cache type of the specific address
1164 MTRR_MEMORY_CACHE_TYPE
1166 MtrrGetMemoryAttribute (
1167 IN PHYSICAL_ADDRESS Address
1170 if (!IsMtrrSupported ()) {
1171 return CacheUncacheable
;
1174 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1178 Worker function prints all MTRRs for debugging.
1180 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1182 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1184 @param MtrrSetting A buffer holding all MTRRs content.
1187 MtrrDebugPrintAllMtrrsWorker (
1188 IN MTRR_SETTINGS
*MtrrSetting
1192 MTRR_SETTINGS LocalMtrrs
;
1193 MTRR_SETTINGS
*Mtrrs
;
1196 UINTN VariableMtrrCount
;
1204 UINT64 NoRangeLimit
;
1207 UINTN PreviousMemoryType
;
1210 if (!IsMtrrSupported ()) {
1214 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1215 DEBUG((DEBUG_CACHE
, "=============\n"));
1217 if (MtrrSetting
!= NULL
) {
1218 Mtrrs
= MtrrSetting
;
1220 MtrrGetAllMtrrs (&LocalMtrrs
);
1221 Mtrrs
= &LocalMtrrs
;
1224 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1225 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1226 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1229 VariableMtrrCount
= GetVariableMtrrCount ();
1230 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1231 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1233 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1234 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1237 DEBUG((DEBUG_CACHE
, "\n"));
1238 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1239 DEBUG((DEBUG_CACHE
, "====================================\n"));
1242 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1243 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1244 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1245 for (Index1
= 0; Index1
< 8; Index1
++) {
1246 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1247 if (MemoryType
> CacheWriteBack
) {
1248 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1250 if (MemoryType
!= PreviousMemoryType
) {
1251 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1252 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1254 PreviousMemoryType
= MemoryType
;
1255 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1257 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1260 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1262 VariableMtrrCount
= GetVariableMtrrCount ();
1265 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1266 if (RegEax
>= 0x80000008) {
1267 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1268 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1271 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1273 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1274 if (MemoryType
> CacheWriteBack
) {
1275 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1278 if (MemoryType
!= PreviousMemoryType
) {
1279 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1280 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1282 PreviousMemoryType
= MemoryType
;
1283 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1286 RangeBase
= BASE_1MB
;
1287 NoRangeBase
= BASE_1MB
;
1289 NoRangeLimit
= Limit
;
1291 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1292 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1294 // If mask is not valid, then do not display range
1298 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1299 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1301 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1305 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1306 RangeBase
= MtrrBase
;
1308 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1309 RangeBase
= MtrrLimit
+ 1;
1311 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1312 RangeLimit
= MtrrBase
- 1;
1314 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1315 RangeLimit
= MtrrLimit
;
1318 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1319 NoRangeBase
= MtrrLimit
+ 1;
1321 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1322 NoRangeLimit
= MtrrBase
- 1;
1327 Base
= RangeLimit
+ 1;
1329 Base
= NoRangeLimit
+ 1;
1331 } while (Base
< Limit
);
1332 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1338 This function prints all MTRRs for debugging.
1342 MtrrDebugPrintAllMtrrs (
1346 MtrrDebugPrintAllMtrrsWorker (NULL
);
1350 Update the Ranges array to change the specified range identified by
1351 BaseAddress and Length to Type.
1353 @param Ranges Array holding memory type settings for all memory regions.
1354 @param Capacity The maximum count of memory ranges the array can hold.
1355 @param Count Return the new memory range count in the array.
1356 @param BaseAddress The base address of the memory range to change type.
1357 @param Length The length of the memory range to change type.
1358 @param Type The new type of the specified memory range.
1360 @retval RETURN_SUCCESS The type of the specified memory range is
1361 changed successfully.
1362 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1363 range exceeds capacity.
1366 MtrrLibSetMemoryType (
1367 IN MEMORY_RANGE
*Ranges
,
1369 IN OUT UINT32
*Count
,
1370 IN UINT64 BaseAddress
,
1372 IN MTRR_MEMORY_CACHE_TYPE Type
1385 Limit
= BaseAddress
+ Length
;
1386 StartIndex
= *Count
;
1388 for (Index
= 0; Index
< *Count
; Index
++) {
1389 if ((StartIndex
== *Count
) &&
1390 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1391 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1393 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1396 if ((EndIndex
== *Count
) &&
1397 (Ranges
[Index
].BaseAddress
< Limit
) &&
1398 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1400 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1405 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1406 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1407 return RETURN_SUCCESS
;
1411 // The type change may cause merging with previous range or next range.
1412 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1413 // logic doesn't need to consider merging.
1415 if (StartIndex
!= 0) {
1416 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1418 Length
+= Ranges
[StartIndex
].Length
;
1419 BaseAddress
-= Ranges
[StartIndex
].Length
;
1422 if (EndIndex
!= (*Count
) - 1) {
1423 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1425 Length
+= Ranges
[EndIndex
].Length
;
1430 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1431 // |++++++++++++++++++| 0 3 1=3-0-2 3
1432 // |+++++++| 0 1 -1=1-0-2 5
1433 // |+| 0 0 -2=0-0-2 6
1434 // |+++| 0 0 -1=0-0-2+1 5
1437 DeltaCount
= EndIndex
- StartIndex
- 2;
1438 if (LengthLeft
== 0) {
1441 if (LengthRight
== 0) {
1444 if (*Count
- DeltaCount
> Capacity
) {
1445 return RETURN_OUT_OF_RESOURCES
;
1449 // Reserve (-DeltaCount) space
1451 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1452 *Count
-= DeltaCount
;
1454 if (LengthLeft
!= 0) {
1455 Ranges
[StartIndex
].Length
= LengthLeft
;
1458 if (LengthRight
!= 0) {
1459 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1460 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1461 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1463 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1464 Ranges
[StartIndex
].Length
= Length
;
1465 Ranges
[StartIndex
].Type
= Type
;
1466 return RETURN_SUCCESS
;
1470 Allocate one or more variable MTRR to cover the range identified by
1471 BaseAddress and Length.
1473 @param Ranges Memory range array holding the memory type
1474 settings for all memory address.
1475 @param RangeCount Count of memory ranges.
1476 @param VariableMtrr Variable MTRR array.
1477 @param VariableMtrrCapacity Capacity of variable MTRR array.
1478 @param VariableMtrrCount Count of variable MTRR.
1479 @param BaseAddress Base address of the memory range.
1480 @param Length Length of the memory range.
1481 @param Type MTRR type of the memory range.
1482 @param Alignment0 Alignment of 0.
1484 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1485 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1488 MtrrLibSetMemoryAttributeInVariableMtrr (
1489 IN CONST MEMORY_RANGE
*Ranges
,
1490 IN UINT32 RangeCount
,
1491 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1492 IN UINT32 VariableMtrrCapacity
,
1493 IN OUT UINT32
*VariableMtrrCount
,
1494 IN UINT64 BaseAddress
,
1496 IN MTRR_MEMORY_CACHE_TYPE Type
,
1497 IN UINT64 Alignment0
1501 Allocate one or more variable MTRR to cover the range identified by
1502 BaseAddress and Length.
1504 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1505 to allocate variable MTRRs when the range contains several sub-ranges
1506 with different attributes.
1508 @param Ranges Memory range array holding the memory type
1509 settings for all memory address.
1510 @param RangeCount Count of memory ranges.
1511 @param VariableMtrr Variable MTRR array.
1512 @param VariableMtrrCapacity Capacity of variable MTRR array.
1513 @param VariableMtrrCount Count of variable MTRR.
1514 @param BaseAddress Base address of the memory range.
1515 @param Length Length of the memory range.
1516 @param Type MTRR type of the range.
1517 If it's CacheInvalid, the memory range may
1518 contains several sub-ranges with different
1520 @param Alignment0 Alignment of 0.
1522 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1523 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1526 MtrrLibAddVariableMtrr (
1527 IN CONST MEMORY_RANGE
*Ranges
,
1528 IN UINT32 RangeCount
,
1529 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1530 IN UINT32 VariableMtrrCapacity
,
1531 IN OUT UINT32
*VariableMtrrCount
,
1532 IN PHYSICAL_ADDRESS BaseAddress
,
1534 IN MTRR_MEMORY_CACHE_TYPE Type
,
1535 IN UINT64 Alignment0
1538 RETURN_STATUS Status
;
1542 MTRR_LIB_ASSERT_ALIGNED (BaseAddress
, Length
);
1543 if (Type
== CacheInvalid
) {
1544 ASSERT (Ranges
!= NULL
);
1545 for (Index
= 0; Index
< RangeCount
; Index
++) {
1546 if (Ranges
[Index
].BaseAddress
<= BaseAddress
&& BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1549 // Because the Length may not be aligned to BaseAddress, below code calls
1550 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1551 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1554 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= BaseAddress
+ Length
) {
1555 return MtrrLibSetMemoryAttributeInVariableMtrr (
1556 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1557 BaseAddress
, Length
, Ranges
[Index
].Type
, Alignment0
1560 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1561 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1562 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1563 BaseAddress
, SubLength
, Ranges
[Index
].Type
, Alignment0
1565 if (RETURN_ERROR (Status
)) {
1568 BaseAddress
+= SubLength
;
1569 Length
-= SubLength
;
1575 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1578 return RETURN_DEVICE_ERROR
;
1580 for (Index
= 0; Index
< *VariableMtrrCount
; Index
++) {
1581 if (VariableMtrr
[Index
].BaseAddress
== BaseAddress
&& VariableMtrr
[Index
].Length
== Length
) {
1582 ASSERT (VariableMtrr
[Index
].Type
== Type
);
1586 if (Index
== *VariableMtrrCount
) {
1587 if (*VariableMtrrCount
== VariableMtrrCapacity
) {
1588 return RETURN_OUT_OF_RESOURCES
;
1590 VariableMtrr
[Index
].BaseAddress
= BaseAddress
;
1591 VariableMtrr
[Index
].Length
= Length
;
1592 VariableMtrr
[Index
].Type
= Type
;
1593 VariableMtrr
[Index
].Valid
= TRUE
;
1594 VariableMtrr
[Index
].Used
= TRUE
;
1595 (*VariableMtrrCount
)++;
1597 return RETURN_SUCCESS
;
1602 Allocate one or more variable MTRR to cover the range identified by
1603 BaseAddress and Length.
1605 @param Ranges Memory range array holding the memory type
1606 settings for all memory address.
1607 @param RangeCount Count of memory ranges.
1608 @param VariableMtrr Variable MTRR array.
1609 @param VariableMtrrCapacity Capacity of variable MTRR array.
1610 @param VariableMtrrCount Count of variable MTRR.
1611 @param BaseAddress Base address of the memory range.
1612 @param Length Length of the memory range.
1613 @param Type MTRR type of the memory range.
1614 @param Alignment0 Alignment of 0.
1616 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1617 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1620 MtrrLibSetMemoryAttributeInVariableMtrr (
1621 IN CONST MEMORY_RANGE
*Ranges
,
1622 IN UINT32 RangeCount
,
1623 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1624 IN UINT32 VariableMtrrCapacity
,
1625 IN OUT UINT32
*VariableMtrrCount
,
1626 IN UINT64 BaseAddress
,
1628 IN MTRR_MEMORY_CACHE_TYPE Type
,
1629 IN UINT64 Alignment0
1634 UINT32 SubtractiveLeft
;
1635 UINT32 SubtractiveRight
;
1636 BOOLEAN UseLeastAlignment
;
1640 MtrrNumber
= MtrrLibGetMtrrNumber (Ranges
, RangeCount
, VariableMtrr
, *VariableMtrrCount
,
1641 BaseAddress
, Length
, Type
, Alignment0
, &SubtractiveLeft
, &SubtractiveRight
);
1643 if (MtrrNumber
+ *VariableMtrrCount
> VariableMtrrCapacity
) {
1644 return RETURN_OUT_OF_RESOURCES
;
1647 while (SubtractiveLeft
-- != 0) {
1648 Alignment
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
1649 ASSERT (Alignment
<= Length
);
1651 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1652 BaseAddress
- Alignment
, Alignment
, CacheInvalid
, Alignment0
);
1653 BaseAddress
-= Alignment
;
1654 Length
+= Alignment
;
1657 while (Length
!= 0) {
1658 Alignment
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
1659 if (Alignment
> Length
) {
1662 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1663 BaseAddress
, Alignment
, Type
, Alignment0
);
1664 BaseAddress
+= Alignment
;
1665 Length
-= Alignment
;
1668 while (SubtractiveRight
-- != 0) {
1669 Alignment
= MtrrLibBiggestAlignment (BaseAddress
+ Length
, Alignment0
);
1670 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1671 BaseAddress
+ Length
, Alignment
, CacheInvalid
, Alignment0
);
1672 Length
+= Alignment
;
1675 UseLeastAlignment
= TRUE
;
1676 while (Length
!= 0) {
1677 if (UseLeastAlignment
) {
1678 Alignment
= MtrrLibBiggestAlignment (BaseAddress
, Alignment0
);
1679 if (Alignment
> Length
) {
1680 UseLeastAlignment
= FALSE
;
1684 if (!UseLeastAlignment
) {
1685 Alignment
= GetPowerOfTwo64 (Length
);
1688 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1689 BaseAddress
, Alignment
, Type
, Alignment0
);
1690 BaseAddress
+= Alignment
;
1691 Length
-= Alignment
;
1693 return RETURN_SUCCESS
;
1697 Return an array of memory ranges holding memory type settings for all memory
1700 @param DefaultType The default memory type.
1701 @param TotalLength The total length of the memory.
1702 @param VariableMtrr The variable MTRR array.
1703 @param VariableMtrrCount The count of variable MTRRs.
1704 @param Ranges Return the memory range array holding memory type
1705 settings for all memory address.
1706 @param RangeCapacity The capacity of memory range array.
1707 @param RangeCount Return the count of memory range.
1709 @retval RETURN_SUCCESS The memory range array is returned successfully.
1710 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1713 MtrrLibGetMemoryTypes (
1714 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1715 IN UINT64 TotalLength
,
1716 IN CONST VARIABLE_MTRR
*VariableMtrr
,
1717 IN UINT32 VariableMtrrCount
,
1718 OUT MEMORY_RANGE
*Ranges
,
1719 IN UINT32 RangeCapacity
,
1720 OUT UINT32
*RangeCount
1723 RETURN_STATUS Status
;
1729 // UC > * (except WB, UC) > WB
1733 // 0. Set whole range as DefaultType
1736 Ranges
[0].BaseAddress
= 0;
1737 Ranges
[0].Length
= TotalLength
;
1738 Ranges
[0].Type
= DefaultType
;
1743 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1744 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheWriteBack
) {
1745 Status
= MtrrLibSetMemoryType (
1746 Ranges
, RangeCapacity
, RangeCount
,
1747 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1749 if (RETURN_ERROR (Status
)) {
1756 // 2. Set other types than WB or UC
1758 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1759 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
!= CacheWriteBack
&& VariableMtrr
[Index
].Type
!= CacheUncacheable
) {
1760 Status
= MtrrLibSetMemoryType (
1761 Ranges
, RangeCapacity
, RangeCount
,
1762 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1764 if (RETURN_ERROR (Status
)) {
1773 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1774 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1775 Status
= MtrrLibSetMemoryType (
1776 Ranges
, RangeCapacity
, RangeCount
,
1777 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1779 if (RETURN_ERROR (Status
)) {
1784 return RETURN_SUCCESS
;
1788 Worker function attempts to set the attributes for a memory range.
1790 If MtrrSetting is not NULL, set the attributes into the input MTRR
1792 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1794 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1795 @param[in] BaseAddress The physical address that is the start
1796 address of a memory range.
1797 @param[in] Length The size in bytes of the memory range.
1798 @param[in] Type The MTRR type to set for the memory range.
1800 @retval RETURN_SUCCESS The attributes were set for the memory
1802 @retval RETURN_INVALID_PARAMETER Length is zero.
1803 @retval RETURN_UNSUPPORTED The processor does not support one or
1804 more bytes of the memory resource range
1805 specified by BaseAddress and Length.
1806 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1807 memory resource range specified
1808 by BaseAddress and Length.
1809 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1810 modify the attributes of the memory
1815 MtrrSetMemoryAttributeWorker (
1816 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1817 IN PHYSICAL_ADDRESS BaseAddress
,
1819 IN MTRR_MEMORY_CACHE_TYPE Type
1822 RETURN_STATUS Status
;
1824 UINT32 WorkingIndex
;
1826 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1828 MEMORY_RANGE Ranges
[MTRR_NUMBER_OF_VARIABLE_MTRR
* 2 + 2];
1830 UINT64 MtrrValidBitsMask
;
1831 UINT64 MtrrValidAddressMask
;
1833 MTRR_CONTEXT MtrrContext
;
1834 BOOLEAN MtrrContextValid
;
1836 MTRR_MEMORY_CACHE_TYPE DefaultType
;
1842 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1843 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1844 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1846 UINT32 FirmwareVariableMtrrCount
;
1847 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1848 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1849 UINT32 OriginalVariableMtrrCount
;
1850 VARIABLE_MTRR OriginalVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1851 UINT32 WorkingVariableMtrrCount
;
1852 VARIABLE_MTRR WorkingVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1853 BOOLEAN VariableSettingModified
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1854 UINTN FreeVariableMtrrCount
;
1857 return RETURN_INVALID_PARAMETER
;
1860 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1861 if (((BaseAddress
& ~MtrrValidAddressMask
) != 0) || (Length
& ~MtrrValidAddressMask
) != 0) {
1862 return RETURN_UNSUPPORTED
;
1864 OriginalVariableMtrrCount
= 0;
1865 VariableSettings
= NULL
;
1867 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1868 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1869 FixedSettingsValid
[Index
] = FALSE
;
1870 FixedSettingsModified
[Index
] = FALSE
;
1874 // Check if Fixed MTRR
1876 if (BaseAddress
< BASE_1MB
) {
1877 MsrIndex
= (UINT32
)-1;
1878 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
1879 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
1880 if (RETURN_ERROR (Status
)) {
1883 if (MtrrSetting
!= NULL
) {
1884 MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] = (MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1885 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
1887 if (!FixedSettingsValid
[MsrIndex
]) {
1888 WorkingFixedSettings
.Mtrr
[MsrIndex
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrIndex
].Msr
);
1889 FixedSettingsValid
[MsrIndex
] = TRUE
;
1891 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1892 if (WorkingFixedSettings
.Mtrr
[MsrIndex
] != NewValue
) {
1893 WorkingFixedSettings
.Mtrr
[MsrIndex
] = NewValue
;
1894 FixedSettingsModified
[MsrIndex
] = TRUE
;
1901 // A Length of 0 can only make sense for fixed MTTR ranges.
1902 // Since we just handled the fixed MTRRs, we can skip the
1903 // variable MTRR section.
1910 // Read the default MTRR type
1912 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1915 // Read all variable MTRRs and convert to Ranges.
1917 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
1918 if (MtrrSetting
== NULL
) {
1919 ZeroMem (&OriginalVariableSettings
, sizeof (OriginalVariableSettings
));
1920 MtrrGetVariableMtrrWorker (NULL
, OriginalVariableMtrrCount
, &OriginalVariableSettings
);
1921 VariableSettings
= &OriginalVariableSettings
;
1923 VariableSettings
= &MtrrSetting
->Variables
;
1925 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings
, OriginalVariableMtrrCount
, MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
);
1927 Status
= MtrrLibGetMemoryTypes (
1928 DefaultType
, MtrrValidBitsMask
+ 1, OriginalVariableMtrr
, OriginalVariableMtrrCount
,
1929 Ranges
, 2 * OriginalVariableMtrrCount
+ 1, &RangeCount
1931 ASSERT (Status
== RETURN_SUCCESS
);
1933 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1934 ASSERT (RangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
1937 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1939 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, 0, SIZE_1MB
, CacheUncacheable
);
1940 ASSERT (Status
== RETURN_SUCCESS
);
1942 // Apply Type to [BaseAddress, BaseAddress + Length)
1944 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, BaseAddress
, Length
, Type
);
1945 if (RETURN_ERROR (Status
)) {
1949 Alignment0
= LShiftU64 (1, (UINTN
) HighBitSet64 (MtrrValidBitsMask
));
1950 WorkingVariableMtrrCount
= 0;
1951 ZeroMem (&WorkingVariableMtrr
, sizeof (WorkingVariableMtrr
));
1952 for (Index
= 0; Index
< RangeCount
; Index
++) {
1953 if (Ranges
[Index
].Type
!= DefaultType
) {
1955 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
1956 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
1958 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1960 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
,
1961 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
,
1962 Ranges
[Index
].Type
, Alignment0
1964 if (RETURN_ERROR (Status
)) {
1971 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
1973 if (WorkingVariableMtrr
[0].BaseAddress
== 0 && WorkingVariableMtrr
[0].Length
== SIZE_1MB
) {
1974 ASSERT (WorkingVariableMtrr
[0].Type
== CacheUncacheable
);
1975 WorkingVariableMtrrCount
--;
1976 CopyMem (&WorkingVariableMtrr
[0], &WorkingVariableMtrr
[1], WorkingVariableMtrrCount
* sizeof (VARIABLE_MTRR
));
1979 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
1980 return RETURN_OUT_OF_RESOURCES
;
1983 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
1984 VariableSettingModified
[Index
] = FALSE
;
1986 if (!OriginalVariableMtrr
[Index
].Valid
) {
1989 for (WorkingIndex
= 0; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
1990 if (OriginalVariableMtrr
[Index
].BaseAddress
== WorkingVariableMtrr
[WorkingIndex
].BaseAddress
&&
1991 OriginalVariableMtrr
[Index
].Length
== WorkingVariableMtrr
[WorkingIndex
].Length
&&
1992 OriginalVariableMtrr
[Index
].Type
== WorkingVariableMtrr
[WorkingIndex
].Type
) {
1997 if (WorkingIndex
== WorkingVariableMtrrCount
) {
1999 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2001 OriginalVariableMtrr
[Index
].Valid
= FALSE
;
2002 VariableSettingModified
[Index
] = TRUE
;
2005 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2007 WorkingVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2010 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2015 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2017 for (FreeVariableMtrrCount
= 0, WorkingIndex
= 0, Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2018 if (!OriginalVariableMtrr
[Index
].Valid
) {
2019 for (; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
2020 if (WorkingVariableMtrr
[WorkingIndex
].Valid
) {
2024 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2025 FreeVariableMtrrCount
++;
2027 CopyMem (&OriginalVariableMtrr
[Index
], &WorkingVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2028 VariableSettingModified
[Index
] = TRUE
;
2033 ASSERT (OriginalVariableMtrrCount
- FreeVariableMtrrCount
<= FirmwareVariableMtrrCount
);
2036 // Move MTRRs after the FirmwareVariableMtrrCount position to beginning
2038 if (FirmwareVariableMtrrCount
< OriginalVariableMtrrCount
) {
2039 WorkingIndex
= FirmwareVariableMtrrCount
;
2040 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
2041 if (!OriginalVariableMtrr
[Index
].Valid
) {
2043 // Found an empty MTRR in WorkingIndex position
2045 for (; WorkingIndex
< OriginalVariableMtrrCount
; WorkingIndex
++) {
2046 if (OriginalVariableMtrr
[WorkingIndex
].Valid
) {
2051 if (WorkingIndex
!= OriginalVariableMtrrCount
) {
2052 CopyMem (&OriginalVariableMtrr
[Index
], &OriginalVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2053 VariableSettingModified
[Index
] = TRUE
;
2054 VariableSettingModified
[WorkingIndex
] = TRUE
;
2055 OriginalVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2062 // Convert OriginalVariableMtrr to VariableSettings
2063 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2065 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2066 if (VariableSettingModified
[Index
]) {
2067 if (OriginalVariableMtrr
[Index
].Valid
) {
2068 VariableSettings
->Mtrr
[Index
].Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
) | (UINT8
) OriginalVariableMtrr
[Index
].Type
;
2069 VariableSettings
->Mtrr
[Index
].Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2071 VariableSettings
->Mtrr
[Index
].Base
= 0;
2072 VariableSettings
->Mtrr
[Index
].Mask
= 0;
2078 if (MtrrSetting
!= NULL
) {
2079 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2080 return RETURN_SUCCESS
;
2083 MtrrContextValid
= FALSE
;
2085 // Write fixed MTRRs that have been modified
2087 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2088 if (FixedSettingsModified
[Index
]) {
2089 if (!MtrrContextValid
) {
2090 MtrrLibPreMtrrChange (&MtrrContext
);
2091 MtrrContextValid
= TRUE
;
2094 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2095 WorkingFixedSettings
.Mtrr
[Index
]
2101 // Write variable MTRRs
2102 // When only fixed MTRRs were changed, below loop doesn't run
2103 // because OriginalVariableMtrrCount equals to 0.
2105 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2106 if (VariableSettingModified
[Index
]) {
2107 if (!MtrrContextValid
) {
2108 MtrrLibPreMtrrChange (&MtrrContext
);
2109 MtrrContextValid
= TRUE
;
2112 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2113 VariableSettings
->Mtrr
[Index
].Base
2116 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2117 VariableSettings
->Mtrr
[Index
].Mask
2121 if (MtrrContextValid
) {
2122 MtrrLibPostMtrrChange (&MtrrContext
);
2125 return RETURN_SUCCESS
;
2129 This function attempts to set the attributes for a memory range.
2131 @param[in] BaseAddress The physical address that is the start
2132 address of a memory range.
2133 @param[in] Length The size in bytes of the memory range.
2134 @param[in] Attributes The bit mask of attributes to set for the
2137 @retval RETURN_SUCCESS The attributes were set for the memory
2139 @retval RETURN_INVALID_PARAMETER Length is zero.
2140 @retval RETURN_UNSUPPORTED The processor does not support one or
2141 more bytes of the memory resource range
2142 specified by BaseAddress and Length.
2143 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2144 for the memory resource range specified
2145 by BaseAddress and Length.
2146 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2147 range specified by BaseAddress and Length
2149 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2150 modify the attributes of the memory
2156 MtrrSetMemoryAttribute (
2157 IN PHYSICAL_ADDRESS BaseAddress
,
2159 IN MTRR_MEMORY_CACHE_TYPE Attribute
2162 RETURN_STATUS Status
;
2164 if (!IsMtrrSupported ()) {
2165 return RETURN_UNSUPPORTED
;
2168 Status
= MtrrSetMemoryAttributeWorker (NULL
, BaseAddress
, Length
, Attribute
);
2169 DEBUG ((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2170 mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2172 if (!RETURN_ERROR (Status
)) {
2173 MtrrDebugPrintAllMtrrsWorker (NULL
);
2179 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2181 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2182 @param[in] BaseAddress The physical address that is the start address
2184 @param[in] Length The size in bytes of the memory range.
2185 @param[in] Attribute The bit mask of attributes to set for the
2188 @retval RETURN_SUCCESS The attributes were set for the memory range.
2189 @retval RETURN_INVALID_PARAMETER Length is zero.
2190 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2191 memory resource range specified by BaseAddress and Length.
2192 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2193 range specified by BaseAddress and Length.
2194 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2195 BaseAddress and Length cannot be modified.
2196 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2197 the memory resource range.
2202 MtrrSetMemoryAttributeInMtrrSettings (
2203 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2204 IN PHYSICAL_ADDRESS BaseAddress
,
2206 IN MTRR_MEMORY_CACHE_TYPE Attribute
2209 RETURN_STATUS Status
;
2210 Status
= MtrrSetMemoryAttributeWorker (MtrrSetting
, BaseAddress
, Length
, Attribute
);
2211 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2212 MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2214 if (!RETURN_ERROR (Status
)) {
2215 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2222 Worker function setting variable MTRRs
2224 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2228 MtrrSetVariableMtrrWorker (
2229 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2233 UINT32 VariableMtrrCount
;
2235 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2236 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
2238 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2240 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2241 VariableSettings
->Mtrr
[Index
].Base
2244 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2245 VariableSettings
->Mtrr
[Index
].Mask
2252 This function sets variable MTRRs
2254 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2256 @return The pointer of VariableSettings
2259 MTRR_VARIABLE_SETTINGS
*
2261 MtrrSetVariableMtrr (
2262 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2265 MTRR_CONTEXT MtrrContext
;
2267 if (!IsMtrrSupported ()) {
2268 return VariableSettings
;
2271 MtrrLibPreMtrrChange (&MtrrContext
);
2272 MtrrSetVariableMtrrWorker (VariableSettings
);
2273 MtrrLibPostMtrrChange (&MtrrContext
);
2274 MtrrDebugPrintAllMtrrs ();
2276 return VariableSettings
;
2280 Worker function setting fixed MTRRs
2282 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2286 MtrrSetFixedMtrrWorker (
2287 IN MTRR_FIXED_SETTINGS
*FixedSettings
2292 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2294 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2295 FixedSettings
->Mtrr
[Index
]
2302 This function sets fixed MTRRs
2304 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2306 @retval The pointer of FixedSettings
2309 MTRR_FIXED_SETTINGS
*
2312 IN MTRR_FIXED_SETTINGS
*FixedSettings
2315 MTRR_CONTEXT MtrrContext
;
2317 if (!IsMtrrSupported ()) {
2318 return FixedSettings
;
2321 MtrrLibPreMtrrChange (&MtrrContext
);
2322 MtrrSetFixedMtrrWorker (FixedSettings
);
2323 MtrrLibPostMtrrChange (&MtrrContext
);
2324 MtrrDebugPrintAllMtrrs ();
2326 return FixedSettings
;
2331 This function gets the content in all MTRRs (variable and fixed)
2333 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2335 @retval the pointer of MtrrSetting
2341 OUT MTRR_SETTINGS
*MtrrSetting
2344 if (!IsMtrrSupported ()) {
2351 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2354 // Get variable MTRRs
2356 MtrrGetVariableMtrrWorker (
2358 GetVariableMtrrCountWorker (),
2359 &MtrrSetting
->Variables
2363 // Get MTRR_DEF_TYPE value
2365 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2372 This function sets all MTRRs (variable and fixed)
2374 @param[in] MtrrSetting A buffer holding all MTRRs content.
2376 @retval The pointer of MtrrSetting
2382 IN MTRR_SETTINGS
*MtrrSetting
2385 MTRR_CONTEXT MtrrContext
;
2387 if (!IsMtrrSupported ()) {
2391 MtrrLibPreMtrrChange (&MtrrContext
);
2396 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2399 // Set variable MTRRs
2401 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2404 // Set MTRR_DEF_TYPE value
2406 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2408 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2415 Checks if MTRR is supported.
2417 @retval TRUE MTRR is supported.
2418 @retval FALSE MTRR is not supported.
2427 CPUID_VERSION_INFO_EDX Edx
;
2428 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2431 // Check CPUID(1).EDX[12] for MTRR capability
2433 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2434 if (Edx
.Bits
.MTRR
== 0) {
2439 // Check number of variable MTRRs and fixed MTRRs existence.
2440 // If number of variable MTRRs is zero, or fixed MTRRs do not
2441 // exist, return false.
2443 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2444 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {