5 Most of services in this library instance are suggested to be invoked by BSP only,
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
8 Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include <Register/Cpuid.h>
22 #include <Register/Msr.h>
24 #include <Library/MtrrLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/CpuLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
30 #define OR_SEED 0x0101010101010101ull
31 #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
33 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
35 // Context to save and restore when MTRRs are programmed
39 BOOLEAN InterruptState
;
45 MTRR_MEMORY_CACHE_TYPE Type
;
49 // This table defines the offset, base and length of the fixed MTRRs
51 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
53 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
58 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
63 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
68 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
73 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
78 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
83 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
88 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
93 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
98 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
103 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
110 // Lookup table used to print MTRRs
112 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
113 "UC", // CacheUncacheable
114 "WC", // CacheWriteCombining
117 "WT", // CacheWriteThrough
118 "WP", // CacheWriteProtected
119 "WB", // CacheWriteBack
124 Worker function returns the variable MTRR count for the CPU.
126 @return Variable MTRR count
130 GetVariableMtrrCountWorker (
134 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
136 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
137 ASSERT (MtrrCap
.Bits
.VCNT
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
138 return MtrrCap
.Bits
.VCNT
;
142 Returns the variable MTRR count for the CPU.
144 @return Variable MTRR count
149 GetVariableMtrrCount (
153 if (!IsMtrrSupported ()) {
156 return GetVariableMtrrCountWorker ();
160 Worker function returns the firmware usable variable MTRR count for the CPU.
162 @return Firmware usable variable MTRR count
166 GetFirmwareVariableMtrrCountWorker (
170 UINT32 VariableMtrrCount
;
171 UINT32 ReservedMtrrNumber
;
173 VariableMtrrCount
= GetVariableMtrrCountWorker ();
174 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
175 if (VariableMtrrCount
< ReservedMtrrNumber
) {
179 return VariableMtrrCount
- ReservedMtrrNumber
;
183 Returns the firmware usable variable MTRR count for the CPU.
185 @return Firmware usable variable MTRR count
190 GetFirmwareVariableMtrrCount (
194 if (!IsMtrrSupported ()) {
197 return GetFirmwareVariableMtrrCountWorker ();
201 Worker function returns the default MTRR cache type for the system.
203 If MtrrSetting is not NULL, returns the default MTRR cache type from input
204 MTRR settings buffer.
205 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
207 @param[in] MtrrSetting A buffer holding all MTRRs content.
209 @return The default MTRR cache type.
212 MTRR_MEMORY_CACHE_TYPE
213 MtrrGetDefaultMemoryTypeWorker (
214 IN MTRR_SETTINGS
*MtrrSetting
217 if (MtrrSetting
== NULL
) {
218 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
220 return (MTRR_MEMORY_CACHE_TYPE
) (MtrrSetting
->MtrrDefType
& 0x7);
226 Returns the default MTRR cache type for the system.
228 @return The default MTRR cache type.
231 MTRR_MEMORY_CACHE_TYPE
233 MtrrGetDefaultMemoryType (
237 if (!IsMtrrSupported ()) {
238 return CacheUncacheable
;
240 return MtrrGetDefaultMemoryTypeWorker (NULL
);
244 Preparation before programming MTRR.
246 This function will do some preparation for programming MTRRs:
247 disable cache, invalid cache and disable MTRR caching functionality
249 @param[out] MtrrContext Pointer to context to save
253 MtrrLibPreMtrrChange (
254 OUT MTRR_CONTEXT
*MtrrContext
258 // Disable interrupts and save current interrupt state
260 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
263 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
268 // Save original CR4 value and clear PGE flag (Bit 7)
270 MtrrContext
->Cr4
= AsmReadCr4 ();
271 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
281 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
285 Cleaning up after programming MTRRs.
287 This function will do some clean up after programming MTRRs:
288 Flush all TLBs, re-enable caching, restore CR4.
290 @param[in] MtrrContext Pointer to context to restore
294 MtrrLibPostMtrrChangeEnableCache (
295 IN MTRR_CONTEXT
*MtrrContext
304 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
309 // Restore original CR4 value
311 AsmWriteCr4 (MtrrContext
->Cr4
);
314 // Restore original interrupt state
316 SetInterruptState (MtrrContext
->InterruptState
);
320 Cleaning up after programming MTRRs.
322 This function will do some clean up after programming MTRRs:
323 enable MTRR caching functionality, and enable cache
325 @param[in] MtrrContext Pointer to context to restore
329 MtrrLibPostMtrrChange (
330 IN MTRR_CONTEXT
*MtrrContext
336 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
338 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
342 Worker function gets the content in fixed MTRRs
344 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
346 @retval The pointer of FixedSettings
350 MtrrGetFixedMtrrWorker (
351 OUT MTRR_FIXED_SETTINGS
*FixedSettings
356 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
357 FixedSettings
->Mtrr
[Index
] =
358 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
361 return FixedSettings
;
366 This function gets the content in fixed MTRRs
368 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
370 @retval The pointer of FixedSettings
376 OUT MTRR_FIXED_SETTINGS
*FixedSettings
379 if (!IsMtrrSupported ()) {
380 return FixedSettings
;
383 return MtrrGetFixedMtrrWorker (FixedSettings
);
388 Worker function will get the raw value in variable MTRRs
390 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
391 MTRR settings buffer.
392 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
394 @param[in] MtrrSetting A buffer holding all MTRRs content.
395 @param[in] VariableMtrrCount Number of variable MTRRs.
396 @param[out] VariableSettings A buffer to hold variable MTRRs content.
398 @return The VariableSettings input pointer
401 MTRR_VARIABLE_SETTINGS
*
402 MtrrGetVariableMtrrWorker (
403 IN MTRR_SETTINGS
*MtrrSetting
,
404 IN UINT32 VariableMtrrCount
,
405 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
410 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
412 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
413 if (MtrrSetting
== NULL
) {
414 VariableSettings
->Mtrr
[Index
].Base
=
415 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
416 VariableSettings
->Mtrr
[Index
].Mask
=
417 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
419 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
420 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
424 return VariableSettings
;
428 This function will get the raw value in variable MTRRs
430 @param[out] VariableSettings A buffer to hold variable MTRRs content.
432 @return The VariableSettings input pointer
435 MTRR_VARIABLE_SETTINGS
*
437 MtrrGetVariableMtrr (
438 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
441 if (!IsMtrrSupported ()) {
442 return VariableSettings
;
445 return MtrrGetVariableMtrrWorker (
447 GetVariableMtrrCountWorker (),
453 Programs fixed MTRRs registers.
455 @param[in] Type The memory type to set.
456 @param[in, out] Base The base address of memory range.
457 @param[in, out] Length The length of memory range.
458 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.
459 On return, the current index of the fixed MTRR MSR to program.
460 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
461 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
463 @retval RETURN_SUCCESS The cache type was updated successfully
464 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
469 MtrrLibProgramFixedMtrr (
470 IN MTRR_MEMORY_CACHE_TYPE Type
,
472 IN OUT UINT64
*Length
,
473 IN OUT UINT32
*LastMsrNum
,
474 OUT UINT64
*ReturnClearMask
,
475 OUT UINT64
*ReturnOrMask
479 UINT32 LeftByteShift
;
480 UINT32 RightByteShift
;
486 // Find the fixed MTRR index to be programmed
488 for (MsrNum
= *LastMsrNum
+ 1; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
489 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
492 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
493 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
501 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
502 return RETURN_UNSUPPORTED
;
506 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
508 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
)
509 / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
511 if (LeftByteShift
>= 8) {
512 return RETURN_UNSUPPORTED
;
516 // Find the end offset in fixed MTRR and calculate byte offset of right shift
518 SubLength
= mMtrrLibFixedMtrrTable
[MsrNum
].Length
* (8 - LeftByteShift
);
519 if (*Length
>= SubLength
) {
522 RightByteShift
= 8 - LeftByteShift
-
523 (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
524 if ((LeftByteShift
>= 8) ||
525 (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrNum
].Length
) != 0)
527 return RETURN_UNSUPPORTED
;
530 // Update SubLength by actual length
535 ClearMask
= CLEAR_SEED
;
536 OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
538 if (LeftByteShift
!= 0) {
540 // Clear the low bits by LeftByteShift
542 ClearMask
&= LShiftU64 (ClearMask
, LeftByteShift
* 8);
543 OrMask
&= LShiftU64 (OrMask
, LeftByteShift
* 8);
546 if (RightByteShift
!= 0) {
548 // Clear the high bits by RightByteShift
550 ClearMask
&= RShiftU64 (ClearMask
, RightByteShift
* 8);
551 OrMask
&= RShiftU64 (OrMask
, RightByteShift
* 8);
554 *Length
-= SubLength
;
557 *LastMsrNum
= MsrNum
;
558 *ReturnClearMask
= ClearMask
;
559 *ReturnOrMask
= OrMask
;
561 return RETURN_SUCCESS
;
566 Worker function gets the attribute of variable MTRRs.
568 This function shadows the content of variable MTRRs into an
569 internal array: VariableMtrr.
571 @param[in] VariableSettings The variable MTRR values to shadow
572 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware
573 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
574 @param[in] MtrrValidAddressMask The valid address mask for MTRR
575 @param[out] VariableMtrr The array to shadow variable MTRRs content
577 @return The return value of this parameter indicates the
578 number of MTRRs which has been used.
582 MtrrGetMemoryAttributeInVariableMtrrWorker (
583 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
584 IN UINTN FirmwareVariableMtrrCount
,
585 IN UINT64 MtrrValidBitsMask
,
586 IN UINT64 MtrrValidAddressMask
,
587 OUT VARIABLE_MTRR
*VariableMtrr
593 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
594 for (Index
= 0, UsedMtrr
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
595 if ((VariableSettings
->Mtrr
[Index
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
596 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
597 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
598 VariableMtrr
[Index
].Length
= ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
599 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
600 VariableMtrr
[Index
].Valid
= TRUE
;
601 VariableMtrr
[Index
].Used
= TRUE
;
610 Gets the attribute of variable MTRRs.
612 This function shadows the content of variable MTRRs into an
613 internal array: VariableMtrr.
615 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
616 @param[in] MtrrValidAddressMask The valid address mask for MTRR
617 @param[out] VariableMtrr The array to shadow variable MTRRs content
619 @return The return value of this parameter indicates the
620 number of MTRRs which has been used.
625 MtrrGetMemoryAttributeInVariableMtrr (
626 IN UINT64 MtrrValidBitsMask
,
627 IN UINT64 MtrrValidAddressMask
,
628 OUT VARIABLE_MTRR
*VariableMtrr
631 MTRR_VARIABLE_SETTINGS VariableSettings
;
633 if (!IsMtrrSupported ()) {
637 MtrrGetVariableMtrrWorker (
639 GetVariableMtrrCountWorker (),
643 return MtrrGetMemoryAttributeInVariableMtrrWorker (
645 GetFirmwareVariableMtrrCountWorker (),
647 MtrrValidAddressMask
,
653 Return the least alignment of address.
655 @param Address The address to return the alignment.
656 @param Alignment0 The alignment to return when Address is 0.
658 @return The least alignment of the Address.
661 MtrrLibLeastAlignment (
670 return LShiftU64 (1, (UINTN
) LowBitSet64 (Address
));
674 Return the number of required variable MTRRs to positively cover the
677 @param BaseAddress Base address of the range.
678 @param Length Length of the range.
679 @param Alignment0 Alignment of 0.
681 @return The number of the required variable MTRRs.
684 MtrrLibGetPositiveMtrrNumber (
685 IN UINT64 BaseAddress
,
692 BOOLEAN UseLeastAlignment
;
694 UseLeastAlignment
= TRUE
;
697 // Calculate the alignment of the base address.
699 for (MtrrNumber
= 0; Length
!= 0; MtrrNumber
++) {
700 if (UseLeastAlignment
) {
701 SubLength
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
703 if (SubLength
> Length
) {
705 // Set a flag when remaining length is too small
706 // so that MtrrLibLeastAlignment() is not called in following loops.
708 UseLeastAlignment
= FALSE
;
712 if (!UseLeastAlignment
) {
713 SubLength
= GetPowerOfTwo64 (Length
);
716 BaseAddress
+= SubLength
;
724 Return whether the left MTRR type precedes the right MTRR type.
726 The MTRR type precedence rules are:
727 1. UC precedes any other type
730 @param Left The left MTRR type.
731 @param Right The right MTRR type.
733 @retval TRUE Left precedes Right.
734 @retval FALSE Left doesn't precede Right.
737 MtrrLibTypeLeftPrecedeRight (
738 IN MTRR_MEMORY_CACHE_TYPE Left
,
739 IN MTRR_MEMORY_CACHE_TYPE Right
742 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
747 Return whether the type of the specified range can precede the specified type.
749 @param Ranges Memory range array holding memory type settings for all
751 @param RangeCount Count of memory ranges.
752 @param Type Type to check precedence.
753 @param SubBase Base address of the specified range.
754 @param SubLength Length of the specified range.
756 @retval TRUE The type of the specified range can precede the Type.
757 @retval FALSE The type of the specified range cannot precede the Type.
758 So the subtraction is not applicable.
761 MtrrLibSubstractable (
762 IN CONST MEMORY_RANGE
*Ranges
,
763 IN UINT32 RangeCount
,
764 IN MTRR_MEMORY_CACHE_TYPE Type
,
773 for (Index
= 0; Index
< RangeCount
; Index
++) {
774 if (Ranges
[Index
].BaseAddress
<= SubBase
&& SubBase
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
776 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= SubBase
+ SubLength
) {
777 return MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
);
780 if (!MtrrLibTypeLeftPrecedeRight (Ranges
[Index
].Type
, Type
)) {
784 Length
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- SubBase
;
796 Return the number of required variable MTRRs to cover the specified range.
798 The routine considers subtraction in the both side of the range to find out
799 the most optimal solution (which uses the least MTRRs).
801 @param Ranges Array holding memory type settings of all memory
803 @param RangeCount Count of memory ranges.
804 @param VariableMtrr Array holding allocated variable MTRRs.
805 @param VariableMtrrCount Count of allocated variable MTRRs.
806 @param BaseAddress Base address of the specified range.
807 @param Length Length of the specified range.
808 @param Type MTRR type of the specified range.
809 @param Alignment0 Alignment of 0.
810 @param SubLeft Return the count of left subtraction.
811 @param SubRight Return the count of right subtraction.
813 @return Number of required variable MTRRs.
816 MtrrLibGetMtrrNumber (
817 IN CONST MEMORY_RANGE
*Ranges
,
818 IN UINT32 RangeCount
,
819 IN CONST VARIABLE_MTRR
*VariableMtrr
,
820 IN UINT32 VariableMtrrCount
,
821 IN UINT64 BaseAddress
,
823 IN MTRR_MEMORY_CACHE_TYPE Type
,
824 IN UINT64 Alignment0
,
825 OUT UINT32
*SubLeft
, // subtractive from BaseAddress to get more aligned address, to save MTRR
826 OUT UINT32
*SubRight
// subtractive from BaseAddress + Length, to save MTRR
830 UINT32 LeastLeftMtrrNumber
;
831 UINT32 MiddleMtrrNumber
;
832 UINT32 LeastRightMtrrNumber
;
833 UINT32 CurrentMtrrNumber
;
834 UINT32 SubtractiveCount
;
835 UINT32 SubtractiveMtrrNumber
;
836 UINT32 LeastSubtractiveMtrrNumber
;
837 UINT64 SubtractiveBaseAddress
;
838 UINT64 SubtractiveLength
;
839 UINT64 BaseAlignment
;
844 LeastSubtractiveMtrrNumber
= 0;
847 // Get the optimal left subtraction solution.
849 if (BaseAddress
!= 0) {
851 // Get the MTRR number needed without left subtraction.
853 LeastLeftMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
856 // Left subtraction bit by bit, to find the optimal left subtraction solution.
858 for (SubtractiveMtrrNumber
= 0, SubtractiveCount
= 1; BaseAddress
!= 0; SubtractiveCount
++) {
859 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
862 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
863 // IA32 Manual defines the following override rules:
867 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
- Alignment
, Alignment
)) {
871 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
872 if ((VariableMtrr
[Index
].BaseAddress
== BaseAddress
- Alignment
) &&
873 (VariableMtrr
[Index
].Length
== Alignment
)) {
877 if (Index
== VariableMtrrCount
) {
879 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
881 SubtractiveMtrrNumber
++;
884 BaseAddress
-= Alignment
;
887 CurrentMtrrNumber
= SubtractiveMtrrNumber
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
888 if (CurrentMtrrNumber
<= LeastLeftMtrrNumber
) {
889 LeastLeftMtrrNumber
= CurrentMtrrNumber
;
890 LeastSubtractiveMtrrNumber
= SubtractiveMtrrNumber
;
891 *SubLeft
= SubtractiveCount
;
892 SubtractiveBaseAddress
= BaseAddress
;
893 SubtractiveLength
= Length
;
898 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
901 BaseAddress
= SubtractiveBaseAddress
;
902 Length
= SubtractiveLength
;
907 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
909 MiddleMtrrNumber
= 0;
910 while (Length
!= 0) {
911 BaseAlignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
912 if (BaseAlignment
> Length
) {
915 BaseAddress
+= BaseAlignment
;
916 Length
-= BaseAlignment
;
922 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
;
927 // Get the optimal right subtraction solution.
931 // Get the MTRR number needed without right subtraction.
933 LeastRightMtrrNumber
= MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
935 for (SubtractiveCount
= 1; Length
< BaseAlignment
; SubtractiveCount
++) {
936 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
937 if (!MtrrLibSubstractable (Ranges
, RangeCount
, Type
, BaseAddress
+ Length
, Alignment
)) {
944 // SubtractiveCount = Number of MTRRs used for subtraction
946 CurrentMtrrNumber
= SubtractiveCount
+ MtrrLibGetPositiveMtrrNumber (BaseAddress
, Length
, Alignment0
);
947 if (CurrentMtrrNumber
<= LeastRightMtrrNumber
) {
948 LeastRightMtrrNumber
= CurrentMtrrNumber
;
949 *SubRight
= SubtractiveCount
;
950 SubtractiveLength
= Length
;
954 return LeastSubtractiveMtrrNumber
+ MiddleMtrrNumber
+ LeastRightMtrrNumber
;
959 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
961 If MtrrSetting is not NULL, gets the default memory attribute from input
962 MTRR settings buffer.
963 If MtrrSetting is NULL, gets the default memory attribute from MSR.
965 @param[in] MtrrSetting A buffer holding all MTRRs content.
966 @param[in] MtrrType MTRR memory type
968 @return The enum item in MTRR_MEMORY_CACHE_TYPE
971 MTRR_MEMORY_CACHE_TYPE
972 GetMemoryCacheTypeFromMtrrType (
973 IN MTRR_SETTINGS
*MtrrSetting
,
978 case MTRR_CACHE_UNCACHEABLE
:
979 return CacheUncacheable
;
980 case MTRR_CACHE_WRITE_COMBINING
:
981 return CacheWriteCombining
;
982 case MTRR_CACHE_WRITE_THROUGH
:
983 return CacheWriteThrough
;
984 case MTRR_CACHE_WRITE_PROTECTED
:
985 return CacheWriteProtected
;
986 case MTRR_CACHE_WRITE_BACK
:
987 return CacheWriteBack
;
990 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
991 // no MTRR covers the range
993 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
998 Initializes the valid bits mask and valid address mask for MTRRs.
1000 This function initializes the valid bits mask and valid address mask for MTRRs.
1002 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
1003 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
1007 MtrrLibInitializeMtrrMask (
1008 OUT UINT64
*MtrrValidBitsMask
,
1009 OUT UINT64
*MtrrValidAddressMask
1012 UINT32 MaxExtendedFunction
;
1013 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
1016 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
1018 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
1019 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
1021 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
1024 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
1025 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
1030 Determines the real attribute of a memory range.
1032 This function is to arbitrate the real attribute of the memory when
1033 there are 2 MTRRs covers the same memory range. For further details,
1034 please refer the IA32 Software Developer's Manual, Volume 3,
1037 @param[in] MtrrType1 The first kind of Memory type
1038 @param[in] MtrrType2 The second kind of memory type
1043 IN UINT64 MtrrType1
,
1049 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1050 switch (MtrrType1
) {
1051 case MTRR_CACHE_UNCACHEABLE
:
1052 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
1054 case MTRR_CACHE_WRITE_COMBINING
:
1056 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
1057 MtrrType2
==MTRR_CACHE_UNCACHEABLE
1059 MtrrType
= MtrrType2
;
1062 case MTRR_CACHE_WRITE_THROUGH
:
1064 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
1065 MtrrType2
==MTRR_CACHE_WRITE_BACK
1067 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
1068 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
1069 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
1072 case MTRR_CACHE_WRITE_PROTECTED
:
1073 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
1074 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
1075 MtrrType
= MtrrType2
;
1078 case MTRR_CACHE_WRITE_BACK
:
1080 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
1081 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
1082 MtrrType2
== MTRR_CACHE_WRITE_BACK
1084 MtrrType
= MtrrType2
;
1087 case MTRR_CACHE_INVALID_TYPE
:
1088 MtrrType
= MtrrType2
;
1094 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
1095 MtrrType
= MtrrType1
;
1101 Worker function will get the memory cache type of the specific address.
1103 If MtrrSetting is not NULL, gets the memory cache type from input
1104 MTRR settings buffer.
1105 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1107 @param[in] MtrrSetting A buffer holding all MTRRs content.
1108 @param[in] Address The specific address
1110 @return Memory cache type of the specific address
1113 MTRR_MEMORY_CACHE_TYPE
1114 MtrrGetMemoryAttributeByAddressWorker (
1115 IN MTRR_SETTINGS
*MtrrSetting
,
1116 IN PHYSICAL_ADDRESS Address
1123 UINT64 TempMtrrType
;
1124 MTRR_MEMORY_CACHE_TYPE CacheType
;
1125 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1126 UINT64 MtrrValidBitsMask
;
1127 UINT64 MtrrValidAddressMask
;
1128 UINTN VariableMtrrCount
;
1129 MTRR_VARIABLE_SETTINGS VariableSettings
;
1132 // Check if MTRR is enabled, if not, return UC as attribute
1134 if (MtrrSetting
== NULL
) {
1135 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1137 TempQword
= MtrrSetting
->MtrrDefType
;
1139 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1141 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1142 return CacheUncacheable
;
1146 // If address is less than 1M, then try to go through the fixed MTRR
1148 if (Address
< BASE_1MB
) {
1149 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1151 // Go through the fixed MTRR
1153 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1154 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1156 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1157 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1161 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1162 mMtrrLibFixedMtrrTable
[Index
].Length
;
1163 if (MtrrSetting
== NULL
) {
1164 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1166 TempQword
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1168 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1169 return GetMemoryCacheTypeFromMtrrType (MtrrSetting
, MtrrType
);
1174 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1176 MtrrGetVariableMtrrWorker (
1178 GetVariableMtrrCountWorker (),
1182 MtrrGetMemoryAttributeInVariableMtrrWorker (
1184 GetFirmwareVariableMtrrCountWorker (),
1186 MtrrValidAddressMask
,
1191 // Go through the variable MTRR
1193 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1194 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1196 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1197 if (VariableMtrr
[Index
].Valid
) {
1198 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1199 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1200 TempMtrrType
= VariableMtrr
[Index
].Type
;
1201 MtrrType
= MtrrLibPrecedence (MtrrType
, TempMtrrType
);
1205 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrSetting
, MtrrType
);
1212 This function will get the memory cache type of the specific address.
1214 This function is mainly for debug purpose.
1216 @param[in] Address The specific address
1218 @return Memory cache type of the specific address
1221 MTRR_MEMORY_CACHE_TYPE
1223 MtrrGetMemoryAttribute (
1224 IN PHYSICAL_ADDRESS Address
1227 if (!IsMtrrSupported ()) {
1228 return CacheUncacheable
;
1231 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1235 Worker function prints all MTRRs for debugging.
1237 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1239 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1241 @param MtrrSetting A buffer holding all MTRRs content.
1244 MtrrDebugPrintAllMtrrsWorker (
1245 IN MTRR_SETTINGS
*MtrrSetting
1249 MTRR_SETTINGS LocalMtrrs
;
1250 MTRR_SETTINGS
*Mtrrs
;
1253 UINTN VariableMtrrCount
;
1261 UINT64 NoRangeLimit
;
1264 UINTN PreviousMemoryType
;
1267 if (!IsMtrrSupported ()) {
1271 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1272 DEBUG((DEBUG_CACHE
, "=============\n"));
1274 if (MtrrSetting
!= NULL
) {
1275 Mtrrs
= MtrrSetting
;
1277 MtrrGetAllMtrrs (&LocalMtrrs
);
1278 Mtrrs
= &LocalMtrrs
;
1281 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1282 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1283 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1286 VariableMtrrCount
= GetVariableMtrrCount ();
1287 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1288 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1290 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1291 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1294 DEBUG((DEBUG_CACHE
, "\n"));
1295 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1296 DEBUG((DEBUG_CACHE
, "====================================\n"));
1299 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1300 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1301 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1302 for (Index1
= 0; Index1
< 8; Index1
++) {
1303 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1304 if (MemoryType
> CacheWriteBack
) {
1305 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1307 if (MemoryType
!= PreviousMemoryType
) {
1308 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1309 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1311 PreviousMemoryType
= MemoryType
;
1312 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1314 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1317 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1319 VariableMtrrCount
= GetVariableMtrrCount ();
1322 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1323 if (RegEax
>= 0x80000008) {
1324 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1325 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1328 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1330 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1331 if (MemoryType
> CacheWriteBack
) {
1332 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1335 if (MemoryType
!= PreviousMemoryType
) {
1336 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1337 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1339 PreviousMemoryType
= MemoryType
;
1340 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1343 RangeBase
= BASE_1MB
;
1344 NoRangeBase
= BASE_1MB
;
1346 NoRangeLimit
= Limit
;
1348 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1349 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1351 // If mask is not valid, then do not display range
1355 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1356 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1358 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1362 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1363 RangeBase
= MtrrBase
;
1365 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1366 RangeBase
= MtrrLimit
+ 1;
1368 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1369 RangeLimit
= MtrrBase
- 1;
1371 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1372 RangeLimit
= MtrrLimit
;
1375 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1376 NoRangeBase
= MtrrLimit
+ 1;
1378 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1379 NoRangeLimit
= MtrrBase
- 1;
1384 Base
= RangeLimit
+ 1;
1386 Base
= NoRangeLimit
+ 1;
1388 } while (Base
< Limit
);
1389 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1395 This function prints all MTRRs for debugging.
1399 MtrrDebugPrintAllMtrrs (
1403 MtrrDebugPrintAllMtrrsWorker (NULL
);
1407 Update the Ranges array to change the specified range identified by
1408 BaseAddress and Length to Type.
1410 @param Ranges Array holding memory type settings for all memory regions.
1411 @param Capacity The maximum count of memory ranges the array can hold.
1412 @param Count Return the new memory range count in the array.
1413 @param BaseAddress The base address of the memory range to change type.
1414 @param Length The length of the memory range to change type.
1415 @param Type The new type of the specified memory range.
1417 @retval RETURN_SUCCESS The type of the specified memory range is
1418 changed successfully.
1419 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1420 range exceeds capacity.
1423 MtrrLibSetMemoryType (
1424 IN MEMORY_RANGE
*Ranges
,
1426 IN OUT UINT32
*Count
,
1427 IN UINT64 BaseAddress
,
1429 IN MTRR_MEMORY_CACHE_TYPE Type
1440 Limit
= BaseAddress
+ Length
;
1441 StartIndex
= *Count
;
1443 for (Index
= 0; Index
< *Count
; Index
++) {
1444 if ((StartIndex
== *Count
) &&
1445 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1446 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1448 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1451 if ((EndIndex
== *Count
) &&
1452 (Ranges
[Index
].BaseAddress
< Limit
) &&
1453 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1455 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1460 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1461 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1462 return RETURN_SUCCESS
;
1466 // The type change may cause merging with previous range or next range.
1467 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1468 // logic doesn't need to consider merging.
1470 if (StartIndex
!= 0) {
1471 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1473 Length
+= Ranges
[StartIndex
].Length
;
1474 BaseAddress
-= Ranges
[StartIndex
].Length
;
1477 if (EndIndex
!= (*Count
) - 1) {
1478 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1480 Length
+= Ranges
[EndIndex
].Length
;
1485 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1486 // |++++++++++++++++++| 0 3 1=3-0-2 3
1487 // |+++++++| 0 1 -1=1-0-2 5
1488 // |+| 0 0 -2=0-0-2 6
1489 // |+++| 0 0 -1=0-0-2+1 5
1492 DeltaCount
= EndIndex
- StartIndex
- 2;
1493 if (LengthLeft
== 0) {
1496 if (LengthRight
== 0) {
1499 if (*Count
- DeltaCount
> Capacity
) {
1500 return RETURN_OUT_OF_RESOURCES
;
1504 // Reserve (-DeltaCount) space
1506 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1507 *Count
-= DeltaCount
;
1509 if (LengthLeft
!= 0) {
1510 Ranges
[StartIndex
].Length
= LengthLeft
;
1513 if (LengthRight
!= 0) {
1514 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1515 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1516 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1518 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1519 Ranges
[StartIndex
].Length
= Length
;
1520 Ranges
[StartIndex
].Type
= Type
;
1521 return RETURN_SUCCESS
;
1525 Allocate one or more variable MTRR to cover the range identified by
1526 BaseAddress and Length.
1528 @param Ranges Memory range array holding the memory type
1529 settings for all memory address.
1530 @param RangeCount Count of memory ranges.
1531 @param VariableMtrr Variable MTRR array.
1532 @param VariableMtrrCapacity Capacity of variable MTRR array.
1533 @param VariableMtrrCount Count of variable MTRR.
1534 @param BaseAddress Base address of the memory range.
1535 @param Length Length of the memory range.
1536 @param Type MTRR type of the memory range.
1537 @param Alignment0 Alignment of 0.
1539 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1540 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1543 MtrrLibSetMemoryAttributeInVariableMtrr (
1544 IN CONST MEMORY_RANGE
*Ranges
,
1545 IN UINT32 RangeCount
,
1546 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1547 IN UINT32 VariableMtrrCapacity
,
1548 IN OUT UINT32
*VariableMtrrCount
,
1549 IN UINT64 BaseAddress
,
1551 IN MTRR_MEMORY_CACHE_TYPE Type
,
1552 IN UINT64 Alignment0
1556 Allocate one or more variable MTRR to cover the range identified by
1557 BaseAddress and Length.
1559 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1560 to allocate variable MTRRs when the range contains several sub-ranges
1561 with different attributes.
1563 @param Ranges Memory range array holding the memory type
1564 settings for all memory address.
1565 @param RangeCount Count of memory ranges.
1566 @param VariableMtrr Variable MTRR array.
1567 @param VariableMtrrCapacity Capacity of variable MTRR array.
1568 @param VariableMtrrCount Count of variable MTRR.
1569 @param BaseAddress Base address of the memory range.
1570 @param Length Length of the memory range.
1571 @param Type MTRR type of the range.
1572 If it's CacheInvalid, the memory range may
1573 contains several sub-ranges with different
1575 @param Alignment0 Alignment of 0.
1577 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1578 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1581 MtrrLibAddVariableMtrr (
1582 IN CONST MEMORY_RANGE
*Ranges
,
1583 IN UINT32 RangeCount
,
1584 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1585 IN UINT32 VariableMtrrCapacity
,
1586 IN OUT UINT32
*VariableMtrrCount
,
1587 IN PHYSICAL_ADDRESS BaseAddress
,
1589 IN MTRR_MEMORY_CACHE_TYPE Type
,
1590 IN UINT64 Alignment0
1593 RETURN_STATUS Status
;
1597 MTRR_LIB_ASSERT_ALIGNED (BaseAddress
, Length
);
1598 if (Type
== CacheInvalid
) {
1599 for (Index
= 0; Index
< RangeCount
; Index
++) {
1600 if (Ranges
[Index
].BaseAddress
<= BaseAddress
&& BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1603 // Because the Length may not be aligned to BaseAddress, below code calls
1604 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1605 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1608 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
>= BaseAddress
+ Length
) {
1609 return MtrrLibSetMemoryAttributeInVariableMtrr (
1610 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1611 BaseAddress
, Length
, Ranges
[Index
].Type
, Alignment0
1614 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1615 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
1616 Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1617 BaseAddress
, SubLength
, Ranges
[Index
].Type
, Alignment0
1619 if (RETURN_ERROR (Status
)) {
1622 BaseAddress
+= SubLength
;
1623 Length
-= SubLength
;
1629 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1632 return RETURN_DEVICE_ERROR
;
1634 for (Index
= 0; Index
< *VariableMtrrCount
; Index
++) {
1635 if (VariableMtrr
[Index
].BaseAddress
== BaseAddress
&& VariableMtrr
[Index
].Length
== Length
) {
1636 ASSERT (VariableMtrr
[Index
].Type
== Type
);
1640 if (Index
== *VariableMtrrCount
) {
1641 if (*VariableMtrrCount
== VariableMtrrCapacity
) {
1642 return RETURN_OUT_OF_RESOURCES
;
1644 VariableMtrr
[Index
].BaseAddress
= BaseAddress
;
1645 VariableMtrr
[Index
].Length
= Length
;
1646 VariableMtrr
[Index
].Type
= Type
;
1647 VariableMtrr
[Index
].Valid
= TRUE
;
1648 VariableMtrr
[Index
].Used
= TRUE
;
1649 (*VariableMtrrCount
)++;
1651 return RETURN_SUCCESS
;
1656 Allocate one or more variable MTRR to cover the range identified by
1657 BaseAddress and Length.
1659 @param Ranges Memory range array holding the memory type
1660 settings for all memory address.
1661 @param RangeCount Count of memory ranges.
1662 @param VariableMtrr Variable MTRR array.
1663 @param VariableMtrrCapacity Capacity of variable MTRR array.
1664 @param VariableMtrrCount Count of variable MTRR.
1665 @param BaseAddress Base address of the memory range.
1666 @param Length Length of the memory range.
1667 @param Type MTRR type of the memory range.
1668 @param Alignment0 Alignment of 0.
1670 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1671 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1674 MtrrLibSetMemoryAttributeInVariableMtrr (
1675 IN CONST MEMORY_RANGE
*Ranges
,
1676 IN UINT32 RangeCount
,
1677 IN OUT VARIABLE_MTRR
*VariableMtrr
,
1678 IN UINT32 VariableMtrrCapacity
,
1679 IN OUT UINT32
*VariableMtrrCount
,
1680 IN UINT64 BaseAddress
,
1682 IN MTRR_MEMORY_CACHE_TYPE Type
,
1683 IN UINT64 Alignment0
1688 UINT32 SubtractiveLeft
;
1689 UINT32 SubtractiveRight
;
1690 BOOLEAN UseLeastAlignment
;
1692 MtrrNumber
= MtrrLibGetMtrrNumber (Ranges
, RangeCount
, VariableMtrr
, *VariableMtrrCount
,
1693 BaseAddress
, Length
, Type
, Alignment0
, &SubtractiveLeft
, &SubtractiveRight
);
1695 if (MtrrNumber
+ *VariableMtrrCount
> VariableMtrrCapacity
) {
1696 return RETURN_OUT_OF_RESOURCES
;
1699 while (SubtractiveLeft
-- != 0) {
1700 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1701 ASSERT (Alignment
<= Length
);
1703 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1704 BaseAddress
- Alignment
, Alignment
, CacheInvalid
, Alignment0
);
1705 BaseAddress
-= Alignment
;
1706 Length
+= Alignment
;
1709 while (Length
!= 0) {
1710 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1711 if (Alignment
> Length
) {
1714 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1715 BaseAddress
, Alignment
, Type
, Alignment0
);
1716 BaseAddress
+= Alignment
;
1717 Length
-= Alignment
;
1720 while (SubtractiveRight
-- != 0) {
1721 Alignment
= MtrrLibLeastAlignment (BaseAddress
+ Length
, Alignment0
);
1722 MtrrLibAddVariableMtrr (Ranges
, RangeCount
, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1723 BaseAddress
+ Length
, Alignment
, CacheInvalid
, Alignment0
);
1724 Length
+= Alignment
;
1727 UseLeastAlignment
= TRUE
;
1728 while (Length
!= 0) {
1729 if (UseLeastAlignment
) {
1730 Alignment
= MtrrLibLeastAlignment (BaseAddress
, Alignment0
);
1731 if (Alignment
> Length
) {
1732 UseLeastAlignment
= FALSE
;
1736 if (!UseLeastAlignment
) {
1737 Alignment
= GetPowerOfTwo64 (Length
);
1740 MtrrLibAddVariableMtrr (NULL
, 0, VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1741 BaseAddress
, Alignment
, Type
, Alignment0
);
1742 BaseAddress
+= Alignment
;
1743 Length
-= Alignment
;
1745 return RETURN_SUCCESS
;
1749 Return an array of memory ranges holding memory type settings for all memory
1752 @param DefaultType The default memory type.
1753 @param TotalLength The total length of the memory.
1754 @param VariableMtrr The variable MTRR array.
1755 @param VariableMtrrCount The count of variable MTRRs.
1756 @param Ranges Return the memory range array holding memory type
1757 settings for all memory address.
1758 @param RangeCapacity The capacity of memory range array.
1759 @param RangeCount Return the count of memory range.
1761 @retval RETURN_SUCCESS The memory range array is returned successfully.
1762 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1765 MtrrLibGetMemoryTypes (
1766 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1767 IN UINT64 TotalLength
,
1768 IN CONST VARIABLE_MTRR
*VariableMtrr
,
1769 IN UINT32 VariableMtrrCount
,
1770 OUT MEMORY_RANGE
*Ranges
,
1771 IN UINT32 RangeCapacity
,
1772 OUT UINT32
*RangeCount
1775 RETURN_STATUS Status
;
1781 // UC > * (except WB, UC) > WB
1785 // 0. Set whole range as DefaultType
1788 Ranges
[0].BaseAddress
= 0;
1789 Ranges
[0].Length
= TotalLength
;
1790 Ranges
[0].Type
= DefaultType
;
1795 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1796 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheWriteBack
) {
1797 Status
= MtrrLibSetMemoryType (
1798 Ranges
, RangeCapacity
, RangeCount
,
1799 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1801 if (RETURN_ERROR (Status
)) {
1808 // 2. Set other types than WB or UC
1810 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1811 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
!= CacheWriteBack
&& VariableMtrr
[Index
].Type
!= CacheUncacheable
) {
1812 Status
= MtrrLibSetMemoryType (
1813 Ranges
, RangeCapacity
, RangeCount
,
1814 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1816 if (RETURN_ERROR (Status
)) {
1825 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1826 if (VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1827 Status
= MtrrLibSetMemoryType (
1828 Ranges
, RangeCapacity
, RangeCount
,
1829 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
1831 if (RETURN_ERROR (Status
)) {
1836 return RETURN_SUCCESS
;
1840 Worker function attempts to set the attributes for a memory range.
1842 If MtrrSetting is not NULL, set the attributes into the input MTRR
1844 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1846 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1847 @param[in] BaseAddress The physical address that is the start
1848 address of a memory range.
1849 @param[in] Length The size in bytes of the memory range.
1850 @param[in] Type The MTRR type to set for the memory range.
1852 @retval RETURN_SUCCESS The attributes were set for the memory
1854 @retval RETURN_INVALID_PARAMETER Length is zero.
1855 @retval RETURN_UNSUPPORTED The processor does not support one or
1856 more bytes of the memory resource range
1857 specified by BaseAddress and Length.
1858 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1859 memory resource range specified
1860 by BaseAddress and Length.
1861 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1862 modify the attributes of the memory
1867 MtrrSetMemoryAttributeWorker (
1868 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1869 IN PHYSICAL_ADDRESS BaseAddress
,
1871 IN MTRR_MEMORY_CACHE_TYPE Type
1874 RETURN_STATUS Status
;
1876 UINT32 WorkingIndex
;
1878 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1880 MEMORY_RANGE Ranges
[MTRR_NUMBER_OF_VARIABLE_MTRR
* 2 + 2];
1882 UINT64 MtrrValidBitsMask
;
1883 UINT64 MtrrValidAddressMask
;
1885 MTRR_CONTEXT MtrrContext
;
1886 BOOLEAN MtrrContextValid
;
1888 MTRR_MEMORY_CACHE_TYPE DefaultType
;
1894 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1895 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1896 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1898 UINT32 FirmwareVariableMtrrCount
;
1899 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1900 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1901 UINT32 OriginalVariableMtrrCount
;
1902 VARIABLE_MTRR OriginalVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1903 UINT32 WorkingVariableMtrrCount
;
1904 VARIABLE_MTRR WorkingVariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1905 BOOLEAN VariableSettingModified
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1906 UINTN FreeVariableMtrrCount
;
1909 return RETURN_INVALID_PARAMETER
;
1912 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1913 if (((BaseAddress
& ~MtrrValidAddressMask
) != 0) || (Length
& ~MtrrValidAddressMask
) != 0) {
1914 return RETURN_UNSUPPORTED
;
1917 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1918 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1919 FixedSettingsValid
[Index
] = FALSE
;
1920 FixedSettingsModified
[Index
] = FALSE
;
1924 // Check if Fixed MTRR
1926 if (BaseAddress
< BASE_1MB
) {
1927 MsrIndex
= (UINT32
)-1;
1928 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
1929 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
1930 if (RETURN_ERROR (Status
)) {
1933 if (MtrrSetting
!= NULL
) {
1934 MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] = (MtrrSetting
->Fixed
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1935 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
1937 if (!FixedSettingsValid
[MsrIndex
]) {
1938 WorkingFixedSettings
.Mtrr
[MsrIndex
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrIndex
].Msr
);
1939 FixedSettingsValid
[MsrIndex
] = TRUE
;
1941 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrIndex
] & ~ClearMask
) | OrMask
;
1942 if (WorkingFixedSettings
.Mtrr
[MsrIndex
] != NewValue
) {
1943 WorkingFixedSettings
.Mtrr
[MsrIndex
] = NewValue
;
1944 FixedSettingsModified
[MsrIndex
] = TRUE
;
1951 // A Length of 0 can only make sense for fixed MTTR ranges.
1952 // Since we just handled the fixed MTRRs, we can skip the
1953 // variable MTRR section.
1960 // Read the default MTRR type
1962 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1965 // Read all variable MTRRs and convert to Ranges.
1967 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
1968 if (MtrrSetting
== NULL
) {
1969 ZeroMem (&OriginalVariableSettings
, sizeof (OriginalVariableSettings
));
1970 MtrrGetVariableMtrrWorker (NULL
, OriginalVariableMtrrCount
, &OriginalVariableSettings
);
1971 VariableSettings
= &OriginalVariableSettings
;
1973 VariableSettings
= &MtrrSetting
->Variables
;
1975 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings
, OriginalVariableMtrrCount
, MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
);
1977 Status
= MtrrLibGetMemoryTypes (
1978 DefaultType
, MtrrValidBitsMask
+ 1, OriginalVariableMtrr
, OriginalVariableMtrrCount
,
1979 Ranges
, 2 * OriginalVariableMtrrCount
+ 1, &RangeCount
1981 ASSERT (Status
== RETURN_SUCCESS
);
1983 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1984 ASSERT (RangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
1987 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1989 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, 0, SIZE_1MB
, CacheUncacheable
);
1990 ASSERT (Status
== RETURN_SUCCESS
);
1992 // Apply Type to [BaseAddress, BaseAddress + Length)
1994 Status
= MtrrLibSetMemoryType (Ranges
, 2 * FirmwareVariableMtrrCount
+ 2, &RangeCount
, BaseAddress
, Length
, Type
);
1995 if (RETURN_ERROR (Status
)) {
1999 Alignment0
= LShiftU64 (1, (UINTN
) HighBitSet64 (MtrrValidBitsMask
));
2000 WorkingVariableMtrrCount
= 0;
2001 ZeroMem (&WorkingVariableMtrr
, sizeof (WorkingVariableMtrr
));
2002 for (Index
= 0; Index
< RangeCount
; Index
++) {
2003 if (Ranges
[Index
].Type
!= DefaultType
) {
2005 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
2006 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
2008 Status
= MtrrLibSetMemoryAttributeInVariableMtrr (
2010 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
,
2011 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
,
2012 Ranges
[Index
].Type
, Alignment0
2014 if (RETURN_ERROR (Status
)) {
2021 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2023 if (WorkingVariableMtrr
[0].BaseAddress
== 0 && WorkingVariableMtrr
[0].Length
== SIZE_1MB
) {
2024 ASSERT (WorkingVariableMtrr
[0].Type
== CacheUncacheable
);
2025 WorkingVariableMtrrCount
--;
2026 CopyMem (&WorkingVariableMtrr
[0], &WorkingVariableMtrr
[1], WorkingVariableMtrrCount
* sizeof (VARIABLE_MTRR
));
2029 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
2030 return RETURN_OUT_OF_RESOURCES
;
2033 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2034 VariableSettingModified
[Index
] = FALSE
;
2036 if (!OriginalVariableMtrr
[Index
].Valid
) {
2039 for (WorkingIndex
= 0; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
2040 if (OriginalVariableMtrr
[Index
].BaseAddress
== WorkingVariableMtrr
[WorkingIndex
].BaseAddress
&&
2041 OriginalVariableMtrr
[Index
].Length
== WorkingVariableMtrr
[WorkingIndex
].Length
&&
2042 OriginalVariableMtrr
[Index
].Type
== WorkingVariableMtrr
[WorkingIndex
].Type
) {
2047 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2049 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2051 OriginalVariableMtrr
[Index
].Valid
= FALSE
;
2052 VariableSettingModified
[Index
] = TRUE
;
2055 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2057 WorkingVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2060 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2065 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2067 for (FreeVariableMtrrCount
= 0, WorkingIndex
= 0, Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2068 if (!OriginalVariableMtrr
[Index
].Valid
) {
2069 for (; WorkingIndex
< WorkingVariableMtrrCount
; WorkingIndex
++) {
2070 if (WorkingVariableMtrr
[WorkingIndex
].Valid
) {
2074 if (WorkingIndex
== WorkingVariableMtrrCount
) {
2075 FreeVariableMtrrCount
++;
2077 CopyMem (&OriginalVariableMtrr
[Index
], &WorkingVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2078 VariableSettingModified
[Index
] = TRUE
;
2083 ASSERT (OriginalVariableMtrrCount
- FreeVariableMtrrCount
<= FirmwareVariableMtrrCount
);
2086 // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning
2088 WorkingIndex
= FirmwareVariableMtrrCount
;
2089 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
2090 if (!OriginalVariableMtrr
[Index
].Valid
) {
2092 // Found an empty MTRR in WorkingIndex position
2094 for (; WorkingIndex
< OriginalVariableMtrrCount
; WorkingIndex
++) {
2095 if (OriginalVariableMtrr
[WorkingIndex
].Valid
) {
2100 if (WorkingIndex
!= OriginalVariableMtrrCount
) {
2101 CopyMem (&OriginalVariableMtrr
[Index
], &OriginalVariableMtrr
[WorkingIndex
], sizeof (VARIABLE_MTRR
));
2102 VariableSettingModified
[Index
] = TRUE
;
2103 VariableSettingModified
[WorkingIndex
] = TRUE
;
2104 OriginalVariableMtrr
[WorkingIndex
].Valid
= FALSE
;
2110 // Convert OriginalVariableMtrr to VariableSettings
2111 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2113 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2114 if (VariableSettingModified
[Index
]) {
2115 if (OriginalVariableMtrr
[Index
].Valid
) {
2116 VariableSettings
->Mtrr
[Index
].Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
) | (UINT8
) OriginalVariableMtrr
[Index
].Type
;
2117 VariableSettings
->Mtrr
[Index
].Mask
= (~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
| BIT11
;
2119 VariableSettings
->Mtrr
[Index
].Base
= 0;
2120 VariableSettings
->Mtrr
[Index
].Mask
= 0;
2126 if (MtrrSetting
!= NULL
) {
2127 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*) &MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2128 return RETURN_SUCCESS
;
2131 MtrrContextValid
= FALSE
;
2133 // Write fixed MTRRs that have been modified
2135 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2136 if (FixedSettingsModified
[Index
]) {
2137 if (!MtrrContextValid
) {
2138 MtrrLibPreMtrrChange (&MtrrContext
);
2139 MtrrContextValid
= TRUE
;
2142 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2143 WorkingFixedSettings
.Mtrr
[Index
]
2149 // Write variable MTRRs
2151 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2152 if (VariableSettingModified
[Index
]) {
2153 if (!MtrrContextValid
) {
2154 MtrrLibPreMtrrChange (&MtrrContext
);
2155 MtrrContextValid
= TRUE
;
2158 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2159 VariableSettings
->Mtrr
[Index
].Base
2162 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2163 VariableSettings
->Mtrr
[Index
].Mask
2167 if (MtrrContextValid
) {
2168 MtrrLibPostMtrrChange (&MtrrContext
);
2175 This function attempts to set the attributes for a memory range.
2177 @param[in] BaseAddress The physical address that is the start
2178 address of a memory range.
2179 @param[in] Length The size in bytes of the memory range.
2180 @param[in] Attributes The bit mask of attributes to set for the
2183 @retval RETURN_SUCCESS The attributes were set for the memory
2185 @retval RETURN_INVALID_PARAMETER Length is zero.
2186 @retval RETURN_UNSUPPORTED The processor does not support one or
2187 more bytes of the memory resource range
2188 specified by BaseAddress and Length.
2189 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2190 for the memory resource range specified
2191 by BaseAddress and Length.
2192 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2193 range specified by BaseAddress and Length
2195 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2196 modify the attributes of the memory
2202 MtrrSetMemoryAttribute (
2203 IN PHYSICAL_ADDRESS BaseAddress
,
2205 IN MTRR_MEMORY_CACHE_TYPE Attribute
2208 RETURN_STATUS Status
;
2210 if (!IsMtrrSupported ()) {
2211 return RETURN_UNSUPPORTED
;
2214 Status
= MtrrSetMemoryAttributeWorker (NULL
, BaseAddress
, Length
, Attribute
);
2215 DEBUG ((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2216 mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2218 if (!RETURN_ERROR (Status
)) {
2219 MtrrDebugPrintAllMtrrsWorker (NULL
);
2225 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2227 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2228 @param[in] BaseAddress The physical address that is the start address
2230 @param[in] Length The size in bytes of the memory range.
2231 @param[in] Attribute The bit mask of attributes to set for the
2234 @retval RETURN_SUCCESS The attributes were set for the memory range.
2235 @retval RETURN_INVALID_PARAMETER Length is zero.
2236 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2237 memory resource range specified by BaseAddress and Length.
2238 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2239 range specified by BaseAddress and Length.
2240 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2241 BaseAddress and Length cannot be modified.
2242 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2243 the memory resource range.
2248 MtrrSetMemoryAttributeInMtrrSettings (
2249 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2250 IN PHYSICAL_ADDRESS BaseAddress
,
2252 IN MTRR_MEMORY_CACHE_TYPE Attribute
2255 RETURN_STATUS Status
;
2256 Status
= MtrrSetMemoryAttributeWorker (MtrrSetting
, BaseAddress
, Length
, Attribute
);
2257 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2258 MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, BaseAddress
+ Length
, Status
));
2260 if (!RETURN_ERROR (Status
)) {
2261 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2268 Worker function setting variable MTRRs
2270 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2274 MtrrSetVariableMtrrWorker (
2275 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2279 UINT32 VariableMtrrCount
;
2281 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2282 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
2284 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2286 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
2287 VariableSettings
->Mtrr
[Index
].Base
2290 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
2291 VariableSettings
->Mtrr
[Index
].Mask
2298 This function sets variable MTRRs
2300 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2302 @return The pointer of VariableSettings
2305 MTRR_VARIABLE_SETTINGS
*
2307 MtrrSetVariableMtrr (
2308 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2311 MTRR_CONTEXT MtrrContext
;
2313 if (!IsMtrrSupported ()) {
2314 return VariableSettings
;
2317 MtrrLibPreMtrrChange (&MtrrContext
);
2318 MtrrSetVariableMtrrWorker (VariableSettings
);
2319 MtrrLibPostMtrrChange (&MtrrContext
);
2320 MtrrDebugPrintAllMtrrs ();
2322 return VariableSettings
;
2326 Worker function setting fixed MTRRs
2328 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2332 MtrrSetFixedMtrrWorker (
2333 IN MTRR_FIXED_SETTINGS
*FixedSettings
2338 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2340 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2341 FixedSettings
->Mtrr
[Index
]
2348 This function sets fixed MTRRs
2350 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2352 @retval The pointer of FixedSettings
2355 MTRR_FIXED_SETTINGS
*
2358 IN MTRR_FIXED_SETTINGS
*FixedSettings
2361 MTRR_CONTEXT MtrrContext
;
2363 if (!IsMtrrSupported ()) {
2364 return FixedSettings
;
2367 MtrrLibPreMtrrChange (&MtrrContext
);
2368 MtrrSetFixedMtrrWorker (FixedSettings
);
2369 MtrrLibPostMtrrChange (&MtrrContext
);
2370 MtrrDebugPrintAllMtrrs ();
2372 return FixedSettings
;
2377 This function gets the content in all MTRRs (variable and fixed)
2379 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2381 @retval the pointer of MtrrSetting
2387 OUT MTRR_SETTINGS
*MtrrSetting
2390 if (!IsMtrrSupported ()) {
2397 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2400 // Get variable MTRRs
2402 MtrrGetVariableMtrrWorker (
2404 GetVariableMtrrCountWorker (),
2405 &MtrrSetting
->Variables
2409 // Get MTRR_DEF_TYPE value
2411 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
2418 This function sets all MTRRs (variable and fixed)
2420 @param[in] MtrrSetting A buffer holding all MTRRs content.
2422 @retval The pointer of MtrrSetting
2428 IN MTRR_SETTINGS
*MtrrSetting
2431 MTRR_CONTEXT MtrrContext
;
2433 if (!IsMtrrSupported ()) {
2437 MtrrLibPreMtrrChange (&MtrrContext
);
2442 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2445 // Set variable MTRRs
2447 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2450 // Set MTRR_DEF_TYPE value
2452 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2454 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2461 Checks if MTRR is supported.
2463 @retval TRUE MTRR is supported.
2464 @retval FALSE MTRR is not supported.
2473 CPUID_VERSION_INFO_EDX Edx
;
2474 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2477 // Check CPUID(1).EDX[12] for MTRR capability
2479 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2480 if (Edx
.Bits
.MTRR
== 0) {
2485 // Check number of variable MTRRs and fixed MTRRs existence.
2486 // If number of variable MTRRs is zero, or fixed MTRRs do not
2487 // exist, return false.
2489 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2490 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {