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] LastMsrNum 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] ReturnClearMask The bits to clear in the fixed MTRR MSR.
472 @param[out] ReturnOrMask 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
*LastMsrNum
,
485 OUT UINT64
*ReturnClearMask
,
486 OUT UINT64
*ReturnOrMask
490 UINT32 LeftByteShift
;
491 UINT32 RightByteShift
;
497 // Find the fixed MTRR index to be programmed
499 for (MsrNum
= *LastMsrNum
+ 1; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
500 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
503 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
504 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
512 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
513 return RETURN_UNSUPPORTED
;
517 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
519 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
)
520 / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
522 if (LeftByteShift
>= 8) {
523 return RETURN_UNSUPPORTED
;
527 // Find the end offset in fixed MTRR and calculate byte offset of right shift
529 SubLength
= mMtrrLibFixedMtrrTable
[MsrNum
].Length
* (8 - LeftByteShift
);
530 if (*Length
>= SubLength
) {
533 RightByteShift
= 8 - LeftByteShift
-
534 (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
535 if ((LeftByteShift
>= 8) ||
536 (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrNum
].Length
) != 0)
538 return RETURN_UNSUPPORTED
;
541 // Update SubLength by actual length
546 ClearMask
= CLEAR_SEED
;
547 OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
549 if (LeftByteShift
!= 0) {
551 // Clear the low bits by LeftByteShift
553 ClearMask
&= LShiftU64 (ClearMask
, LeftByteShift
* 8);
554 OrMask
&= LShiftU64 (OrMask
, LeftByteShift
* 8);
557 if (RightByteShift
!= 0) {
559 // Clear the high bits by RightByteShift
561 ClearMask
&= RShiftU64 (ClearMask
, RightByteShift
* 8);
562 OrMask
&= RShiftU64 (OrMask
, RightByteShift
* 8);
565 *Length
-= SubLength
;
568 *LastMsrNum
= MsrNum
;
569 *ReturnClearMask
= ClearMask
;
570 *ReturnOrMask
= OrMask
;
572 return RETURN_SUCCESS
;
577 Worker function gets the attribute of variable MTRRs.
579 This function shadows the content of variable MTRRs into an
580 internal array: VariableMtrr.
582 @param[in] VariableSettings The variable MTRR values to shadow
583 @param[in] VariableMtrrCount The number of variable MTRRs
584 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
585 @param[in] MtrrValidAddressMask The valid address mask for MTRR
586 @param[out] VariableMtrr The array to shadow variable MTRRs content
588 @return Number of MTRRs which has been used.
592 MtrrGetMemoryAttributeInVariableMtrrWorker (
593 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
594 IN UINTN VariableMtrrCount
,
595 IN UINT64 MtrrValidBitsMask
,
596 IN UINT64 MtrrValidAddressMask
,
597 OUT VARIABLE_MTRR
*VariableMtrr
603 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
604 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
605 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
606 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
607 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
608 VariableMtrr
[Index
].Length
= ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
609 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
610 VariableMtrr
[Index
].Valid
= TRUE
;
611 VariableMtrr
[Index
].Used
= TRUE
;
620 Gets the attribute of variable MTRRs.
622 This function shadows the content of variable MTRRs into an
623 internal array: VariableMtrr.
625 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
626 @param[in] MtrrValidAddressMask The valid address mask for MTRR
627 @param[out] VariableMtrr The array to shadow variable MTRRs content
629 @return The return value of this parameter indicates the
630 number of MTRRs which has been used.
635 MtrrGetMemoryAttributeInVariableMtrr (
636 IN UINT64 MtrrValidBitsMask
,
637 IN UINT64 MtrrValidAddressMask
,
638 OUT VARIABLE_MTRR
*VariableMtrr
641 MTRR_VARIABLE_SETTINGS VariableSettings
;
643 if (!IsMtrrSupported ()) {
647 MtrrGetVariableMtrrWorker (
649 GetVariableMtrrCountWorker (),
653 return MtrrGetMemoryAttributeInVariableMtrrWorker (
655 GetFirmwareVariableMtrrCountWorker (),
657 MtrrValidAddressMask
,
663 Return the least alignment of address.
665 @param Address The address to return the alignment.
666 @param Alignment0 The alignment to return when Address is 0.
668 @return The least alignment of the Address.
671 MtrrLibLeastAlignment (
680 return LShiftU64 (1, (UINTN
) LowBitSet64 (Address
));
684 Return the number of required variable MTRRs to positively cover the
687 @param BaseAddress Base address of the range.
688 @param Length Length of the range.
689 @param Alignment0 Alignment of 0.
691 @return The number of the required variable MTRRs.
694 MtrrLibGetPositiveMtrrNumber (
695 IN UINT64 BaseAddress
,
702 BOOLEAN UseLeastAlignment
;
704 UseLeastAlignment
= TRUE
;
708 // Calculate the alignment of the base address.
710 for (MtrrNumber
= 0; Length
!= 0; MtrrNumber
++) {
711 if (UseLeastAlignment
) {
712 SubLength
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
714 if (SubLength
> Length
) {
716 // Set a flag when remaining length is too small
717 // so that MtrrLibLeastAlignment() is not called in following loops.
719 UseLeastAlignment
= FALSE
;
723 if (!UseLeastAlignment
) {
724 SubLength
= GetPowerOfTwo64 (Length
);
727 BaseAddress
+= SubLength
;
735 Return whether the left MTRR type precedes the right MTRR type.
737 The MTRR type precedence rules are:
738 1. UC precedes any other type
740 For further details, please refer the IA32 Software Developer's Manual,
741 Volume 3, Section "MTRR Precedences".
743 @param Left The left MTRR type.
744 @param Right The right MTRR type.
746 @retval TRUE Left precedes Right.
747 @retval FALSE Left doesn't precede Right.
750 MtrrLibTypeLeftPrecedeRight (
751 IN MTRR_MEMORY_CACHE_TYPE Left
,
752 IN MTRR_MEMORY_CACHE_TYPE Right
755 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
760 Return whether the type of the specified range can precede the specified type.
762 @param Ranges Memory range array holding memory type settings for all
764 @param RangeCount Count of memory ranges.
765 @param Type Type to check precedence.
766 @param SubBase Base address of the specified range.
767 @param SubLength Length of the specified range.
769 @retval TRUE The type of the specified range can precede the Type.
770 @retval FALSE The type of the specified range cannot precede the Type.
771 So the subtraction is not applicable.
774 MtrrLibSubstractable (
775 IN CONST MEMORY_RANGE
*Ranges
,
776 IN UINT32 RangeCount
,
777 IN MTRR_MEMORY_CACHE_TYPE Type
,
786 for (Index
= 0; Index
< RangeCount
; Index
++) {
787 if (Ranges
[Index
].BaseAddress
<= SubBase
&& SubBase
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
789 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= SubBase
+ SubLength
) {
790 return MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
);
793 if (!MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
)) {
797 Length
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- SubBase
;
809 Return the number of required variable MTRRs to cover the specified range.
811 The routine considers subtraction in the both side of the range to find out
812 the most optimal solution (which uses the least MTRRs).
814 @param Ranges Array holding memory type settings of all memory
816 @param RangeCount Count of memory ranges.
817 @param VariableMtrr Array holding allocated variable MTRRs.
818 @param VariableMtrrCount Count of allocated variable MTRRs.
819 @param BaseAddress Base address of the specified range.
820 @param Length Length of the specified range.
821 @param Type MTRR type of the specified range.
822 @param Alignment0 Alignment of 0.
823 @param SubLeft Return the count of left subtraction.
824 @param SubRight Return the count of right subtraction.
826 @return Number of required variable MTRRs.
829 MtrrLibGetMtrrNumber (
830 IN CONST MEMORY_RANGE
*Ranges
,
831 IN UINT32 RangeCount
,
832 IN CONST VARIABLE_MTRR
*VariableMtrr
,
833 IN UINT32 VariableMtrrCount
,
834 IN UINT64 BaseAddress
,
836 IN MTRR_MEMORY_CACHE_TYPE Type
,
837 IN UINT64 Alignment0
,
838 OUT UINT32
*SubLeft
, // subtractive from BaseAddress to get more aligned address, to save MTRR
839 OUT UINT32
*SubRight
// subtractive from BaseAddress + Length, to save MTRR
843 UINT32 LeastLeftMtrrNumber
;
844 UINT32 MiddleMtrrNumber
;
845 UINT32 LeastRightMtrrNumber
;
846 UINT32 CurrentMtrrNumber
;
847 UINT32 SubtractiveCount
;
848 UINT32 SubtractiveMtrrNumber
;
849 UINT32 LeastSubtractiveMtrrNumber
;
850 UINT64 SubtractiveBaseAddress
;
851 UINT64 SubtractiveLength
;
852 UINT64 BaseAlignment
;
854 UINT64 OriginalBaseAddress
;
855 UINT64 OriginalLength
;
859 LeastSubtractiveMtrrNumber
= 0;
863 // Get the optimal left subtraction solution.
865 if (BaseAddress
!= 0) {
867 OriginalBaseAddress
= BaseAddress
;
868 OriginalLength
= Length
;
869 SubtractiveBaseAddress
= 0;
870 SubtractiveLength
= 0;
872 // Get the MTRR number needed without left subtraction.
874 LeastLeftMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
877 // Left subtraction bit by bit, to find the optimal left subtraction solution.
879 for (SubtractiveMtrrNumber
= 0, SubtractiveCount
= 1; BaseAddress
!= 0; SubtractiveCount
++) {
880 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
883 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
884 // IA32 Manual defines the following override rules:
888 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
- Alignment
, Alignment
)) {
892 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
893 if ((VariableMtrr
[Index
].BaseAddress
== BaseAddress
- Alignment
) &&
894 (VariableMtrr
[Index
].Length
== Alignment
)) {
898 if (Index
== VariableMtrrCount
) {
900 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
902 SubtractiveMtrrNumber
++;
905 BaseAddress
-= Alignment
;
908 CurrentMtrrNumber
= SubtractiveMtrrNumber
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
909 if (CurrentMtrrNumber
<= LeastLeftMtrrNumber
) {
910 LeastLeftMtrrNumber
= CurrentMtrrNumber
;
911 LeastSubtractiveMtrrNumber
= SubtractiveMtrrNumber
;
912 *SubLeft
= SubtractiveCount
;
913 SubtractiveBaseAddress
= BaseAddress
;
914 SubtractiveLength
= Length
;
919 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
922 BaseAddress
= SubtractiveBaseAddress
;
923 Length
= SubtractiveLength
;
925 BaseAddress
= OriginalBaseAddress
;
926 Length
= OriginalLength
;
931 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
933 MiddleMtrrNumber
= 0;
934 while (Length
!= 0) {
935 BaseAlignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
936 if (BaseAlignment
> Length
) {
939 BaseAddress
+= BaseAlignment
;
940 Length
-= BaseAlignment
;
946 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
;
951 // Get the optimal right subtraction solution.
955 // Get the MTRR number needed without right subtraction.
957 LeastRightMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
959 for (SubtractiveCount
= 1; Length
< BaseAlignment
; SubtractiveCount
++) {
960 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
961 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
+ Length
, Alignment
)) {
968 // SubtractiveCount = Number of MTRRs used for subtraction
970 CurrentMtrrNumber
= SubtractiveCount
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
971 if (CurrentMtrrNumber
<= LeastRightMtrrNumber
) {
972 LeastRightMtrrNumber
= CurrentMtrrNumber
;
973 *SubRight
= SubtractiveCount
;
974 SubtractiveLength
= Length
;
978 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
+ LeastRightMtrrNumber
;
982 Initializes the valid bits mask and valid address mask for MTRRs.
984 This function initializes the valid bits mask and valid address mask for MTRRs.
986 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
987 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
991 MtrrLibInitializeMtrrMask (
992 OUT UINT64
*MtrrValidBitsMask
,
993 OUT UINT64
*MtrrValidAddressMask
996 UINT32 MaxExtendedFunction
;
997 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
1000 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
1002 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
1003 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
1005 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
1008 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
1009 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
1014 Determines the real attribute of a memory range.
1016 This function is to arbitrate the real attribute of the memory when
1017 there are 2 MTRRs covers the same memory range. For further details,
1018 please refer the IA32 Software Developer's Manual, Volume 3,
1019 Section "MTRR Precedences".
1021 @param[in] MtrrType1 The first kind of Memory type
1022 @param[in] MtrrType2 The second kind of memory type
1025 MTRR_MEMORY_CACHE_TYPE
1027 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
1028 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
1031 if (MtrrType1
== MtrrType2
) {
1036 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
1037 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
1040 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
1048 Worker function will get the memory cache type of the specific address.
1050 If MtrrSetting is not NULL, gets the memory cache type from input
1051 MTRR settings buffer.
1052 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1054 @param[in] MtrrSetting A buffer holding all MTRRs content.
1055 @param[in] Address The specific address
1057 @return Memory cache type of the specific address
1060 MTRR_MEMORY_CACHE_TYPE
1061 MtrrGetMemoryAttributeByAddressWorker (
1062 IN MTRR_SETTINGS
*MtrrSetting
,
1063 IN PHYSICAL_ADDRESS Address
1066 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
1070 MTRR_MEMORY_CACHE_TYPE MtrrType
;
1071 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1072 UINT64 MtrrValidBitsMask
;
1073 UINT64 MtrrValidAddressMask
;
1074 UINT32 VariableMtrrCount
;
1075 MTRR_VARIABLE_SETTINGS VariableSettings
;
1078 // Check if MTRR is enabled, if not, return UC as attribute
1080 if (MtrrSetting
== NULL
) {
1081 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
1083 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
1086 if (DefType
.Bits
.E
== 0) {
1087 return CacheUncacheable
;
1091 // If address is less than 1M, then try to go through the fixed MTRR
1093 if (Address
< BASE_1MB
) {
1094 if (DefType
.Bits
.FE
!= 0) {
1096 // Go through the fixed MTRR
1098 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1099 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1100 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1101 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
1103 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1104 mMtrrLibFixedMtrrTable
[Index
].Length
;
1105 if (MtrrSetting
== NULL
) {
1106 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1108 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1110 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
1116 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1117 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1118 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
1120 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1121 MtrrGetMemoryAttributeInVariableMtrrWorker (
1125 MtrrValidAddressMask
,
1130 // Go through the variable MTRR
1132 MtrrType
= CacheInvalid
;
1133 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1134 if (VariableMtrr
[Index
].Valid
) {
1135 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1136 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
1137 if (MtrrType
== CacheInvalid
) {
1138 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
1140 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
1147 // If there is no MTRR which covers the Address, use the default MTRR type.
1149 if (MtrrType
== CacheInvalid
) {
1150 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
1158 This function will get the memory cache type of the specific address.
1160 This function is mainly for debug purpose.
1162 @param[in] Address The specific address
1164 @return Memory cache type of the specific address
1167 MTRR_MEMORY_CACHE_TYPE
1169 MtrrGetMemoryAttribute (
1170 IN PHYSICAL_ADDRESS Address
1173 if (!IsMtrrSupported ()) {
1174 return CacheUncacheable
;
1177 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1181 Worker function prints all MTRRs for debugging.
1183 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1185 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1187 @param MtrrSetting A buffer holding all MTRRs content.
1190 MtrrDebugPrintAllMtrrsWorker (
1191 IN MTRR_SETTINGS
*MtrrSetting
1195 MTRR_SETTINGS LocalMtrrs
;
1196 MTRR_SETTINGS
*Mtrrs
;
1199 UINTN VariableMtrrCount
;
1207 UINT64 NoRangeLimit
;
1210 UINTN PreviousMemoryType
;
1213 if (!IsMtrrSupported ()) {
1217 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1218 DEBUG((DEBUG_CACHE
, "=============\n"));
1220 if (MtrrSetting
!= NULL
) {
1221 Mtrrs
= MtrrSetting
;
1223 MtrrGetAllMtrrs (&LocalMtrrs
);
1224 Mtrrs
= &LocalMtrrs
;
1227 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1228 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1229 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1232 VariableMtrrCount
= GetVariableMtrrCount ();
1233 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1234 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1236 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1237 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1240 DEBUG((DEBUG_CACHE
, "\n"));
1241 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1242 DEBUG((DEBUG_CACHE
, "====================================\n"));
1245 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1246 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1247 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1248 for (Index1
= 0; Index1
< 8; Index1
++) {
1249 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1250 if (MemoryType
> CacheWriteBack
) {
1251 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1253 if (MemoryType
!= PreviousMemoryType
) {
1254 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1255 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1257 PreviousMemoryType
= MemoryType
;
1258 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1260 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1263 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1265 VariableMtrrCount
= GetVariableMtrrCount ();
1268 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1269 if (RegEax
>= 0x80000008) {
1270 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1271 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1274 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1276 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1277 if (MemoryType
> CacheWriteBack
) {
1278 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1281 if (MemoryType
!= PreviousMemoryType
) {
1282 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1283 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1285 PreviousMemoryType
= MemoryType
;
1286 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1289 RangeBase
= BASE_1MB
;
1290 NoRangeBase
= BASE_1MB
;
1292 NoRangeLimit
= Limit
;
1294 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1295 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1297 // If mask is not valid, then do not display range
1301 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1302 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1304 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1308 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1309 RangeBase
= MtrrBase
;
1311 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1312 RangeBase
= MtrrLimit
+ 1;
1314 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1315 RangeLimit
= MtrrBase
- 1;
1317 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1318 RangeLimit
= MtrrLimit
;
1321 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1322 NoRangeBase
= MtrrLimit
+ 1;
1324 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1325 NoRangeLimit
= MtrrBase
- 1;
1330 Base
= RangeLimit
+ 1;
1332 Base
= NoRangeLimit
+ 1;
1334 } while (Base
< Limit
);
1335 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1341 This function prints all MTRRs for debugging.
1345 MtrrDebugPrintAllMtrrs (
1349 MtrrDebugPrintAllMtrrsWorker (NULL
);
1353 Update the Ranges array to change the specified range identified by
1354 BaseAddress and Length to Type.
1356 @param Ranges Array holding memory type settings for all memory regions.
1357 @param Capacity The maximum count of memory ranges the array can hold.
1358 @param Count Return the new memory range count in the array.
1359 @param BaseAddress The base address of the memory range to change type.
1360 @param Length The length of the memory range to change type.
1361 @param Type The new type of the specified memory range.
1363 @retval RETURN_SUCCESS The type of the specified memory range is
1364 changed successfully.
1365 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1366 range exceeds capacity.
1369 MtrrLibSetMemoryType (
1370 IN MEMORY_RANGE
*Ranges
,
1372 IN OUT UINT32
*Count
,
1373 IN UINT64 BaseAddress
,
1375 IN MTRR_MEMORY_CACHE_TYPE Type
1388 Limit
= BaseAddress
+ Length
;
1389 StartIndex
= *Count
;
1391 for (Index
= 0; Index
< *Count
; Index
++) {
1392 if ((StartIndex
== *Count
) &&
1393 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1394 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1396 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1399 if ((EndIndex
== *Count
) &&
1400 (Ranges
[Index
].BaseAddress
< Limit
) &&
1401 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1403 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1408 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1409 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1410 return RETURN_SUCCESS
;
1414 // The type change may cause merging with previous range or next range.
1415 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1416 // logic doesn't need to consider merging.
1418 if (StartIndex
!= 0) {
1419 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1421 Length
+= Ranges
[StartIndex
].Length
;
1422 BaseAddress
-= Ranges
[StartIndex
].Length
;
1425 if (EndIndex
!= (*Count
) - 1) {
1426 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1428 Length
+= Ranges
[EndIndex
].Length
;
1433 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1434 // |++++++++++++++++++| 0 3 1=3-0-2 3
1435 // |+++++++| 0 1 -1=1-0-2 5
1436 // |+| 0 0 -2=0-0-2 6
1437 // |+++| 0 0 -1=0-0-2+1 5
1440 DeltaCount
= EndIndex
- StartIndex
- 2;
1441 if (LengthLeft
== 0) {
1444 if (LengthRight
== 0) {
1447 if (*Count
- DeltaCount
> Capacity
) {
1448 return RETURN_OUT_OF_RESOURCES
;
1452 // Reserve (-DeltaCount) space
1454 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1455 *Count
-= DeltaCount
;
1457 if (LengthLeft
!= 0) {
1458 Ranges
[StartIndex
].Length
= LengthLeft
;
1461 if (LengthRight
!= 0) {
1462 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1463 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1464 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1466 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1467 Ranges
[StartIndex
].Length
= Length
;
1468 Ranges
[StartIndex
].Type
= Type
;
1469 return RETURN_SUCCESS
;
1473 Allocate one or more variable MTRR to cover the range identified by
1474 BaseAddress and Length.
1476 @param Ranges Memory range array holding the memory type
1477 settings for all memory address.
1478 @param RangeCount Count of memory ranges.
1479 @param VariableMtrr Variable MTRR array.
1480 @param VariableMtrrCapacity Capacity of variable MTRR array.
1481 @param VariableMtrrCount Count of variable MTRR.
1482 @param BaseAddress Base address of the memory range.
1483 @param Length Length of the memory range.
1484 @param Type MTRR type of the memory range.
1485 @param Alignment0 Alignment of 0.
1487 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1488 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1491 MtrrLibSetMemoryAttributeInVariableMtrr (
1492 IN CONST MEMORY_RANGE
*Ranges
,
1493 IN UINT32 RangeCount
,
1494 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1495 IN UINT32 VariableMtrrCapacity
,
1496 IN OUT UINT32
*VariableMtrrCount
,
1497 IN UINT64 BaseAddress
,
1499 IN MTRR_MEMORY_CACHE_TYPE Type
,
1500 IN UINT64 Alignment0
1504 Allocate one or more variable MTRR to cover the range identified by
1505 BaseAddress and Length.
1507 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1508 to allocate variable MTRRs when the range contains several sub-ranges
1509 with different attributes.
1511 @param Ranges Memory range array holding the memory type
1512 settings for all memory address.
1513 @param RangeCount Count of memory ranges.
1514 @param VariableMtrr Variable MTRR array.
1515 @param VariableMtrrCapacity Capacity of variable MTRR array.
1516 @param VariableMtrrCount Count of variable MTRR.
1517 @param BaseAddress Base address of the memory range.
1518 @param Length Length of the memory range.
1519 @param Type MTRR type of the range.
1520 If it's CacheInvalid, the memory range may
1521 contains several sub-ranges with different
1523 @param Alignment0 Alignment of 0.
1525 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1526 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1529 MtrrLibAddVariableMtrr (
1530 IN CONST MEMORY_RANGE
*Ranges
,
1531 IN UINT32 RangeCount
,
1532 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1533 IN UINT32 VariableMtrrCapacity
,
1534 IN OUT UINT32
*VariableMtrrCount
,
1535 IN PHYSICAL_ADDRESS BaseAddress
,
1537 IN MTRR_MEMORY_CACHE_TYPE Type
,
1538 IN UINT64 Alignment0
1541 RETURN_STATUS Status
;
1545 MTRR_LIB_ASSERT_ALIGNED (BaseAddress
, Length
);
1546 if (Type
== CacheInvalid
) {
1547 ASSERT (Ranges
!= NULL
);
1548 for (Index
= 0; Index
< RangeCount
; Index
++) {
1549 if (Ranges
[Index
].BaseAddress
<= BaseAddress
&& BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1552 // Because the Length may not be aligned to BaseAddress, below code calls
1553 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1554 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1557 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= BaseAddress
+ Length
) {
1558 return MtrrLibSetMemoryAttributeInVariableMtrr (
1559 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1560 BaseAddress
, Length
, Ranges
[Index
].Type
, Alignment0
1563 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1564 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1565 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1566 BaseAddress
, SubLength
, Ranges
[Index
].Type
, Alignment0
1568 if (RETURN_ERROR (Status
)) {
1571 BaseAddress
+= SubLength
;
1572 Length
-= SubLength
;
1578 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1581 return RETURN_DEVICE_ERROR
;
1583 for (Index
= 0; Index
< *VariableMtrrCount
; Index
++) {
1584 if (VariableMtrr
[Index
].BaseAddress
== BaseAddress
&& VariableMtrr
[Index
].Length
== Length
) {
1585 ASSERT (VariableMtrr
[Index
].Type
== Type
);
1589 if (Index
== *VariableMtrrCount
) {
1590 if (*VariableMtrrCount
== VariableMtrrCapacity
) {
1591 return RETURN_OUT_OF_RESOURCES
;
1593 VariableMtrr
[Index
].BaseAddress
= BaseAddress
;
1594 VariableMtrr
[Index
].Length
= Length
;
1595 VariableMtrr
[Index
].Type
= Type
;
1596 VariableMtrr
[Index
].Valid
= TRUE
;
1597 VariableMtrr
[Index
].Used
= TRUE
;
1598 (*VariableMtrrCount
)++;
1600 return RETURN_SUCCESS
;
1605 Allocate one or more variable MTRR to cover the range identified by
1606 BaseAddress and Length.
1608 @param Ranges Memory range array holding the memory type
1609 settings for all memory address.
1610 @param RangeCount Count of memory ranges.
1611 @param VariableMtrr Variable MTRR array.
1612 @param VariableMtrrCapacity Capacity of variable MTRR array.
1613 @param VariableMtrrCount Count of variable MTRR.
1614 @param BaseAddress Base address of the memory range.
1615 @param Length Length of the memory range.
1616 @param Type MTRR type of the memory range.
1617 @param Alignment0 Alignment of 0.
1619 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1620 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1623 MtrrLibSetMemoryAttributeInVariableMtrr (
1624 IN CONST MEMORY_RANGE
*Ranges
,
1625 IN UINT32 RangeCount
,
1626 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1627 IN UINT32 VariableMtrrCapacity
,
1628 IN OUT UINT32
*VariableMtrrCount
,
1629 IN UINT64 BaseAddress
,
1631 IN MTRR_MEMORY_CACHE_TYPE Type
,
1632 IN UINT64 Alignment0
1637 UINT32 SubtractiveLeft
;
1638 UINT32 SubtractiveRight
;
1639 BOOLEAN UseLeastAlignment
;
1643 MtrrNumber
= MtrrLibGetMtrrNumber (Ranges
, RangeCount
, VariableMtrr
, *VariableMtrrCount
,
1644 BaseAddress
, Length
, Type
, Alignment0
, &SubtractiveLeft
, &SubtractiveRight
);
1646 if (MtrrNumber
+ *VariableMtrrCount
> VariableMtrrCapacity
) {
1647 return RETURN_OUT_OF_RESOURCES
;
1650 while (SubtractiveLeft
-- != 0) {
1651 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1652 ASSERT (Alignment
<= Length
);
1654 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1655 BaseAddress
- Alignment
, Alignment
, CacheInvalid
, Alignment0
);
1656 BaseAddress
-= Alignment
;
1657 Length
+= Alignment
;
1660 while (Length
!= 0) {
1661 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1662 if (Alignment
> Length
) {
1665 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1666 BaseAddress
, Alignment
, Type
, Alignment0
);
1667 BaseAddress
+= Alignment
;
1668 Length
-= Alignment
;
1671 while (SubtractiveRight
-- != 0) {
1672 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
1673 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1674 BaseAddress
+ Length
, Alignment
, CacheInvalid
, Alignment0
);
1675 Length
+= Alignment
;
1678 UseLeastAlignment
= TRUE
;
1679 while (Length
!= 0) {
1680 if (UseLeastAlignment
) {
1681 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1682 if (Alignment
> Length
) {
1683 UseLeastAlignment
= FALSE
;
1687 if (!UseLeastAlignment
) {
1688 Alignment
= GetPowerOfTwo64 (Length
);
1691 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1692 BaseAddress
, Alignment
, Type
, Alignment0
);
1693 BaseAddress
+= Alignment
;
1694 Length
-= Alignment
;
1696 return RETURN_SUCCESS
;
1700 Return an array of memory ranges holding memory type settings for all memory
1703 @param DefaultType The default memory type.
1704 @param TotalLength The total length of the memory.
1705 @param VariableMtrr The variable MTRR array.
1706 @param VariableMtrrCount The count of variable MTRRs.
1707 @param Ranges Return the memory range array holding memory type
1708 settings for all memory address.
1709 @param RangeCapacity The capacity of memory range array.
1710 @param RangeCount Return the count of memory range.
1712 @retval RETURN_SUCCESS The memory range array is returned successfully.
1713 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1716 MtrrLibGetMemoryTypes (
1717 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1718 IN UINT64 TotalLength
,
1719 IN CONST VARIABLE_MTRR
*VariableMtrr
,
1720 IN UINT32 VariableMtrrCount
,
1721 OUT MEMORY_RANGE
*Ranges
,
1722 IN UINT32 RangeCapacity
,
1723 OUT UINT32
*RangeCount
1726 RETURN_STATUS Status
;
1732 // UC > * (except WB, UC) > WB
1736 // 0. Set whole range as DefaultType
1739 Ranges
[0].BaseAddress
= 0;
1740 Ranges
[0].Length
= TotalLength
;
1741 Ranges
[0].Type
= DefaultType
;
1746 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1747 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheWriteBack
) {
1748 Status
= MtrrLibSetMemoryType (
1749 Ranges
, RangeCapacity
, RangeCount
,
1750 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1752 if (RETURN_ERROR (Status
)) {
1759 // 2. Set other types than WB or UC
1761 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1762 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
!= CacheWriteBack
&& VariableMtrr
[Index
].Type
!= CacheUncacheable
) {
1763 Status
= MtrrLibSetMemoryType (
1764 Ranges
, RangeCapacity
, RangeCount
,
1765 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1767 if (RETURN_ERROR (Status
)) {
1776 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1777 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1778 Status
= MtrrLibSetMemoryType (
1779 Ranges
, RangeCapacity
, RangeCount
,
1780 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1782 if (RETURN_ERROR (Status
)) {
1787 return RETURN_SUCCESS
;
1791 Worker function attempts to set the attributes for a memory range.
1793 If MtrrSetting is not NULL, set the attributes into the input MTRR
1795 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1797 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1798 @param[in] BaseAddress The physical address that is the start
1799 address of a memory range.
1800 @param[in] Length The size in bytes of the memory range.
1801 @param[in] Type The MTRR type to set for the memory range.
1803 @retval RETURN_SUCCESS The attributes were set for the memory
1805 @retval RETURN_INVALID_PARAMETER Length is zero.
1806 @retval RETURN_UNSUPPORTED The processor does not support one or
1807 more bytes of the memory resource range
1808 specified by BaseAddress and Length.
1809 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1810 memory resource range specified
1811 by BaseAddress and Length.
1812 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1813 modify the attributes of the memory
1818 MtrrSetMemoryAttributeWorker (
1819 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1820 IN PHYSICAL_ADDRESS BaseAddress
,
1822 IN MTRR_MEMORY_CACHE_TYPE Type
1825 RETURN_STATUS Status
;
1827 UINT32 WorkingIndex
;
1829 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1831 MEMORY_RANGE Ranges
[MTRR_NUMBER_OF_VARIABLE_MTRR
* 2 + 2];
1833 UINT64 MtrrValidBitsMask
;
1834 UINT64 MtrrValidAddressMask
;
1836 MTRR_CONTEXT MtrrContext
;
1837 BOOLEAN MtrrContextValid
;
1839 MTRR_MEMORY_CACHE_TYPE DefaultType
;
1845 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1846 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1847 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1849 UINT32 FirmwareVariableMtrrCount
;
1850 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1851 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1852 UINT32 OriginalVariableMtrrCount
;
1853 VARIABLE_MTRR OriginalVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1854 UINT32 WorkingVariableMtrrCount
;
1855 VARIABLE_MTRR WorkingVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1856 BOOLEAN VariableSettingModified
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1857 UINTN FreeVariableMtrrCount
;
1860 return RETURN_INVALID_PARAMETER
;
1863 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1864 if (((BaseAddress
& ~MtrrValidAddressMask
) != 0) || (Length
& ~MtrrValidAddressMask
) != 0) {
1865 return RETURN_UNSUPPORTED
;
1867 OriginalVariableMtrrCount
= 0;
1868 VariableSettings
= NULL
;
1870 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1871 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1872 FixedSettingsValid
[Index
] = FALSE
;
1873 FixedSettingsModified
[Index
] = FALSE
;
1877 // Check if Fixed MTRR
1879 if (BaseAddress
< BASE_1MB
) {
1880 MsrIndex
= (UINT32
)-1;
1881 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
1882 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
1883 if (RETURN_ERROR (Status
)) {
1886 if (MtrrSetting
!= NULL
) {
1887 MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] = (MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1888 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
1890 if (!FixedSettingsValid
[MsrIndex
]) {
1891 WorkingFixedSettings
.Mtrr
[MsrIndex
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrIndex
].Msr
);
1892 FixedSettingsValid
[MsrIndex
] = TRUE
;
1894 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1895 if (WorkingFixedSettings
.Mtrr
[MsrIndex
] != NewValue
) {
1896 WorkingFixedSettings
.Mtrr
[MsrIndex
] = NewValue
;
1897 FixedSettingsModified
[MsrIndex
] = TRUE
;
1904 // A Length of 0 can only make sense for fixed MTTR ranges.
1905 // Since we just handled the fixed MTRRs, we can skip the
1906 // variable MTRR section.
1913 // Read the default MTRR type
1915 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1918 // Read all variable MTRRs and convert to Ranges.
1920 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
1921 if (MtrrSetting
== NULL
) {
1922 ZeroMem (&OriginalVariableSettings
, sizeof (OriginalVariableSettings
));
1923 MtrrGetVariableMtrrWorker (NULL
, OriginalVariableMtrrCount
, &OriginalVariableSettings
);
1924 VariableSettings
= &OriginalVariableSettings
;
1926 VariableSettings
= &MtrrSetting
->Variables
;
1928 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings
, OriginalVariableMtrrCount
, MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
);
1930 Status
= MtrrLibGetMemoryTypes (
1931 DefaultType
, MtrrValidBitsMask
+ 1, OriginalVariableMtrr
, OriginalVariableMtrrCount
,
1932 Ranges
, 2 * OriginalVariableMtrrCount
+ 1, &RangeCount
1934 ASSERT (Status
== RETURN_SUCCESS
);
1936 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1937 ASSERT (RangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
1940 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1942 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, 0, SIZE_1MB
, CacheUncacheable
);
1943 ASSERT (Status
== RETURN_SUCCESS
);
1945 // Apply Type to [BaseAddress, BaseAddress + Length)
1947 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, BaseAddress
, Length
, Type
);
1948 if (RETURN_ERROR (Status
)) {
1952 Alignment0
= LShiftU64 (1, (UINTN
) HighBitSet64 (MtrrValidBitsMask
));
1953 WorkingVariableMtrrCount
= 0;
1954 ZeroMem (&WorkingVariableMtrr
, sizeof (WorkingVariableMtrr
));
1955 for (Index
= 0; Index
< RangeCount
; Index
++) {
1956 if (Ranges
[Index
].Type
!= DefaultType
) {
1958 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
1959 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
1961 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1963 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
,
1964 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
,
1965 Ranges
[Index
].Type
, Alignment0
1967 if (RETURN_ERROR (Status
)) {
1974 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
1976 if (WorkingVariableMtrr
[0].BaseAddress
== 0 && WorkingVariableMtrr
[0].Length
== SIZE_1MB
) {
1977 ASSERT (WorkingVariableMtrr
[0].Type
== CacheUncacheable
);
1978 WorkingVariableMtrrCount
--;
1979 CopyMem (&WorkingVariableMtrr
[0], &WorkingVariableMtrr
[1], WorkingVariableMtrrCount
* sizeof (VARIABLE_MTRR
));
1982 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
1983 return RETURN_OUT_OF_RESOURCES
;
1986 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
1987 VariableSettingModified
[Index
] = FALSE
;
1989 if (!OriginalVariableMtrr
[Index
].Valid
) {
1992 for (WorkingIndex
= 0; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
1993 if (OriginalVariableMtrr
[Index
].BaseAddress
== WorkingVariableMtrr
[WorkingIndex
].BaseAddress
&&
1994 OriginalVariableMtrr
[Index
].Length
== WorkingVariableMtrr
[WorkingIndex
].Length
&&
1995 OriginalVariableMtrr
[Index
].Type
== WorkingVariableMtrr
[WorkingIndex
].Type
) {
2000 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2002 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2004 OriginalVariableMtrr
[Index
].Valid
= FALSE
;
2005 VariableSettingModified
[Index
] = TRUE
;
2008 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2010 WorkingVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2013 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2018 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2020 for (FreeVariableMtrrCount
= 0, WorkingIndex
= 0, Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2021 if (!OriginalVariableMtrr
[Index
].Valid
) {
2022 for (; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
2023 if (WorkingVariableMtrr
[WorkingIndex
].Valid
) {
2027 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2028 FreeVariableMtrrCount
++;
2030 CopyMem (&OriginalVariableMtrr
[Index
], &WorkingVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2031 VariableSettingModified
[Index
] = TRUE
;
2036 ASSERT (OriginalVariableMtrrCount
- FreeVariableMtrrCount
<= FirmwareVariableMtrrCount
);
2039 // Move MTRRs after the FirmwareVariableMtrrCount position to beginning
2041 if (FirmwareVariableMtrrCount
< OriginalVariableMtrrCount
) {
2042 WorkingIndex
= FirmwareVariableMtrrCount
;
2043 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
2044 if (!OriginalVariableMtrr
[Index
].Valid
) {
2046 // Found an empty MTRR in WorkingIndex position
2048 for (; WorkingIndex
< OriginalVariableMtrrCount
; WorkingIndex
++) {
2049 if (OriginalVariableMtrr
[WorkingIndex
].Valid
) {
2054 if (WorkingIndex
!= OriginalVariableMtrrCount
) {
2055 CopyMem (&OriginalVariableMtrr
[Index
], &OriginalVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2056 VariableSettingModified
[Index
] = TRUE
;
2057 VariableSettingModified
[WorkingIndex
] = TRUE
;
2058 OriginalVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2065 // Convert OriginalVariableMtrr to VariableSettings
2066 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2068 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2069 if (VariableSettingModified
[Index
]) {
2070 if (OriginalVariableMtrr
[Index
].Valid
) {
2071 VariableSettings
->Mtrr
[Index
].Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
) | (UINT8
) OriginalVariableMtrr
[Index
].Type
;
2072 VariableSettings
->Mtrr
[Index
].Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2074 VariableSettings
->Mtrr
[Index
].Base
= 0;
2075 VariableSettings
->Mtrr
[Index
].Mask
= 0;
2081 if (MtrrSetting
!= NULL
) {
2082 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2083 return RETURN_SUCCESS
;
2086 MtrrContextValid
= FALSE
;
2088 // Write fixed MTRRs that have been modified
2090 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2091 if (FixedSettingsModified
[Index
]) {
2092 if (!MtrrContextValid
) {
2093 MtrrLibPreMtrrChange (&MtrrContext
);
2094 MtrrContextValid
= TRUE
;
2097 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2098 WorkingFixedSettings
.Mtrr
[Index
]
2104 // Write variable MTRRs
2105 // When only fixed MTRRs were changed, below loop doesn't run
2106 // because OriginalVariableMtrrCount equals to 0.
2108 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2109 if (VariableSettingModified
[Index
]) {
2110 if (!MtrrContextValid
) {
2111 MtrrLibPreMtrrChange (&MtrrContext
);
2112 MtrrContextValid
= TRUE
;
2115 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2116 VariableSettings
->Mtrr
[Index
].Base
2119 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2120 VariableSettings
->Mtrr
[Index
].Mask
2124 if (MtrrContextValid
) {
2125 MtrrLibPostMtrrChange (&MtrrContext
);
2128 return RETURN_SUCCESS
;
2132 This function attempts to set the attributes for a memory range.
2134 @param[in] BaseAddress The physical address that is the start
2135 address of a memory range.
2136 @param[in] Length The size in bytes of the memory range.
2137 @param[in] Attributes The bit mask of attributes to set for the
2140 @retval RETURN_SUCCESS The attributes were set for the memory
2142 @retval RETURN_INVALID_PARAMETER Length is zero.
2143 @retval RETURN_UNSUPPORTED The processor does not support one or
2144 more bytes of the memory resource range
2145 specified by BaseAddress and Length.
2146 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2147 for the memory resource range specified
2148 by BaseAddress and Length.
2149 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2150 range specified by BaseAddress and Length
2152 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2153 modify the attributes of the memory
2159 MtrrSetMemoryAttribute (
2160 IN PHYSICAL_ADDRESS BaseAddress
,
2162 IN MTRR_MEMORY_CACHE_TYPE Attribute
2165 RETURN_STATUS Status
;
2167 if (!IsMtrrSupported ()) {
2168 return RETURN_UNSUPPORTED
;
2171 Status
= MtrrSetMemoryAttributeWorker (NULL
, BaseAddress
, Length
, Attribute
);
2172 DEBUG ((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2173 mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2175 if (!RETURN_ERROR (Status
)) {
2176 MtrrDebugPrintAllMtrrsWorker (NULL
);
2182 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2184 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2185 @param[in] BaseAddress The physical address that is the start address
2187 @param[in] Length The size in bytes of the memory range.
2188 @param[in] Attribute The bit mask of attributes to set for the
2191 @retval RETURN_SUCCESS The attributes were set for the memory range.
2192 @retval RETURN_INVALID_PARAMETER Length is zero.
2193 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2194 memory resource range specified by BaseAddress and Length.
2195 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2196 range specified by BaseAddress and Length.
2197 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2198 BaseAddress and Length cannot be modified.
2199 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2200 the memory resource range.
2205 MtrrSetMemoryAttributeInMtrrSettings (
2206 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2207 IN PHYSICAL_ADDRESS BaseAddress
,
2209 IN MTRR_MEMORY_CACHE_TYPE Attribute
2212 RETURN_STATUS Status
;
2213 Status
= MtrrSetMemoryAttributeWorker (MtrrSetting
, BaseAddress
, Length
, Attribute
);
2214 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2215 MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2217 if (!RETURN_ERROR (Status
)) {
2218 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2225 Worker function setting variable MTRRs
2227 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2231 MtrrSetVariableMtrrWorker (
2232 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2236 UINT32 VariableMtrrCount
;
2238 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2239 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
2241 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2243 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2244 VariableSettings
->Mtrr
[Index
].Base
2247 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2248 VariableSettings
->Mtrr
[Index
].Mask
2255 This function sets variable MTRRs
2257 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2259 @return The pointer of VariableSettings
2262 MTRR_VARIABLE_SETTINGS
*
2264 MtrrSetVariableMtrr (
2265 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2268 MTRR_CONTEXT MtrrContext
;
2270 if (!IsMtrrSupported ()) {
2271 return VariableSettings
;
2274 MtrrLibPreMtrrChange (&MtrrContext
);
2275 MtrrSetVariableMtrrWorker (VariableSettings
);
2276 MtrrLibPostMtrrChange (&MtrrContext
);
2277 MtrrDebugPrintAllMtrrs ();
2279 return VariableSettings
;
2283 Worker function setting fixed MTRRs
2285 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2289 MtrrSetFixedMtrrWorker (
2290 IN MTRR_FIXED_SETTINGS
*FixedSettings
2295 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2297 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2298 FixedSettings
->Mtrr
[Index
]
2305 This function sets fixed MTRRs
2307 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2309 @retval The pointer of FixedSettings
2312 MTRR_FIXED_SETTINGS
*
2315 IN MTRR_FIXED_SETTINGS
*FixedSettings
2318 MTRR_CONTEXT MtrrContext
;
2320 if (!IsMtrrSupported ()) {
2321 return FixedSettings
;
2324 MtrrLibPreMtrrChange (&MtrrContext
);
2325 MtrrSetFixedMtrrWorker (FixedSettings
);
2326 MtrrLibPostMtrrChange (&MtrrContext
);
2327 MtrrDebugPrintAllMtrrs ();
2329 return FixedSettings
;
2334 This function gets the content in all MTRRs (variable and fixed)
2336 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2338 @retval the pointer of MtrrSetting
2344 OUT MTRR_SETTINGS
*MtrrSetting
2347 if (!IsMtrrSupported ()) {
2354 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2357 // Get variable MTRRs
2359 MtrrGetVariableMtrrWorker (
2361 GetVariableMtrrCountWorker (),
2362 &MtrrSetting
->Variables
2366 // Get MTRR_DEF_TYPE value
2368 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2375 This function sets all MTRRs (variable and fixed)
2377 @param[in] MtrrSetting A buffer holding all MTRRs content.
2379 @retval The pointer of MtrrSetting
2385 IN MTRR_SETTINGS
*MtrrSetting
2388 MTRR_CONTEXT MtrrContext
;
2390 if (!IsMtrrSupported ()) {
2394 MtrrLibPreMtrrChange (&MtrrContext
);
2399 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2402 // Set variable MTRRs
2404 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2407 // Set MTRR_DEF_TYPE value
2409 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2411 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2418 Checks if MTRR is supported.
2420 @retval TRUE MTRR is supported.
2421 @retval FALSE MTRR is not supported.
2430 CPUID_VERSION_INFO_EDX Edx
;
2431 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2434 // Check CPUID(1).EDX[12] for MTRR capability
2436 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2437 if (Edx
.Bits
.MTRR
== 0) {
2442 // Check number of variable MTRRs and fixed MTRRs existence.
2443 // If number of variable MTRRs is zero, or fixed MTRRs do not
2444 // exist, return false.
2446 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2447 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {