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 - 2020, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #include <Register/Intel/Cpuid.h>
15 #include <Register/Intel/Msr.h>
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
23 #define OR_SEED 0x0101010101010101ull
24 #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
25 #define MAX_WEIGHT MAX_UINT8
26 #define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)
27 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
29 #define M(x, y) ((x) * VertexCount + (y))
30 #define O(x, y) ((y) * VertexCount + (x))
33 // Context to save and restore when MTRRs are programmed
37 BOOLEAN InterruptState
;
44 MTRR_MEMORY_CACHE_TYPE Type
: 7;
47 // Temprary use for calculating the best MTRR settings.
55 // This table defines the offset, base and length of the fixed MTRRs
57 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
59 MSR_IA32_MTRR_FIX64K_00000
,
64 MSR_IA32_MTRR_FIX16K_80000
,
69 MSR_IA32_MTRR_FIX16K_A0000
,
74 MSR_IA32_MTRR_FIX4K_C0000
,
79 MSR_IA32_MTRR_FIX4K_C8000
,
84 MSR_IA32_MTRR_FIX4K_D0000
,
89 MSR_IA32_MTRR_FIX4K_D8000
,
94 MSR_IA32_MTRR_FIX4K_E0000
,
99 MSR_IA32_MTRR_FIX4K_E8000
,
104 MSR_IA32_MTRR_FIX4K_F0000
,
109 MSR_IA32_MTRR_FIX4K_F8000
,
116 // Lookup table used to print MTRRs
118 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
119 "UC", // CacheUncacheable
120 "WC", // CacheWriteCombining
123 "WT", // CacheWriteThrough
124 "WP", // CacheWriteProtected
125 "WB", // CacheWriteBack
130 Worker function prints all MTRRs for debugging.
132 If MtrrSetting is not NULL, print MTRR settings from input MTRR
134 If MtrrSetting is NULL, print MTRR settings from MTRRs.
136 @param MtrrSetting A buffer holding all MTRRs content.
139 MtrrDebugPrintAllMtrrsWorker (
140 IN MTRR_SETTINGS
*MtrrSetting
144 Worker function returns the variable MTRR count for the CPU.
146 @return Variable MTRR count
150 GetVariableMtrrCountWorker (
154 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
156 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
157 ASSERT (MtrrCap
.Bits
.VCNT
<= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS
*)0)->Mtrr
));
158 return MtrrCap
.Bits
.VCNT
;
162 Returns the variable MTRR count for the CPU.
164 @return Variable MTRR count
169 GetVariableMtrrCount (
173 if (!IsMtrrSupported ()) {
177 return GetVariableMtrrCountWorker ();
181 Worker function returns the firmware usable variable MTRR count for the CPU.
183 @return Firmware usable variable MTRR count
187 GetFirmwareVariableMtrrCountWorker (
191 UINT32 VariableMtrrCount
;
192 UINT32 ReservedMtrrNumber
;
194 VariableMtrrCount
= GetVariableMtrrCountWorker ();
195 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
196 if (VariableMtrrCount
< ReservedMtrrNumber
) {
200 return VariableMtrrCount
- ReservedMtrrNumber
;
204 Returns the firmware usable variable MTRR count for the CPU.
206 @return Firmware usable variable MTRR count
211 GetFirmwareVariableMtrrCount (
215 if (!IsMtrrSupported ()) {
219 return GetFirmwareVariableMtrrCountWorker ();
223 Worker function returns the default MTRR cache type for the system.
225 If MtrrSetting is not NULL, returns the default MTRR cache type from input
226 MTRR settings buffer.
227 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
229 @param[in] MtrrSetting A buffer holding all MTRRs content.
231 @return The default MTRR cache type.
234 MTRR_MEMORY_CACHE_TYPE
235 MtrrGetDefaultMemoryTypeWorker (
236 IN MTRR_SETTINGS
*MtrrSetting
239 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
241 if (MtrrSetting
== NULL
) {
242 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
244 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
247 return (MTRR_MEMORY_CACHE_TYPE
)DefType
.Bits
.Type
;
251 Returns the default MTRR cache type for the system.
253 @return The default MTRR cache type.
256 MTRR_MEMORY_CACHE_TYPE
258 MtrrGetDefaultMemoryType (
262 if (!IsMtrrSupported ()) {
263 return CacheUncacheable
;
266 return MtrrGetDefaultMemoryTypeWorker (NULL
);
270 Preparation before programming MTRR.
272 This function will do some preparation for programming MTRRs:
273 disable cache, invalid cache and disable MTRR caching functionality
275 @param[out] MtrrContext Pointer to context to save
279 MtrrLibPreMtrrChange (
280 OUT MTRR_CONTEXT
*MtrrContext
283 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
286 // Disable interrupts and save current interrupt state
288 MtrrContext
->InterruptState
= SaveAndDisableInterrupts ();
291 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
296 // Save original CR4 value and clear PGE flag (Bit 7)
298 MtrrContext
->Cr4
= AsmReadCr4 ();
299 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
309 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
311 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
315 Cleaning up after programming MTRRs.
317 This function will do some clean up after programming MTRRs:
318 Flush all TLBs, re-enable caching, restore CR4.
320 @param[in] MtrrContext Pointer to context to restore
324 MtrrLibPostMtrrChangeEnableCache (
325 IN MTRR_CONTEXT
*MtrrContext
334 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
339 // Restore original CR4 value
341 AsmWriteCr4 (MtrrContext
->Cr4
);
344 // Restore original interrupt state
346 SetInterruptState (MtrrContext
->InterruptState
);
350 Cleaning up after programming MTRRs.
352 This function will do some clean up after programming MTRRs:
353 enable MTRR caching functionality, and enable cache
355 @param[in] MtrrContext Pointer to context to restore
359 MtrrLibPostMtrrChange (
360 IN MTRR_CONTEXT
*MtrrContext
363 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
368 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
371 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
373 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
377 Worker function gets the content in fixed MTRRs
379 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
381 @retval The pointer of FixedSettings
384 MTRR_FIXED_SETTINGS
*
385 MtrrGetFixedMtrrWorker (
386 OUT MTRR_FIXED_SETTINGS
*FixedSettings
391 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
392 FixedSettings
->Mtrr
[Index
] =
393 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
396 return FixedSettings
;
400 This function gets the content in fixed MTRRs
402 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
404 @retval The pointer of FixedSettings
407 MTRR_FIXED_SETTINGS
*
410 OUT MTRR_FIXED_SETTINGS
*FixedSettings
413 if (!IsMtrrSupported ()) {
414 return FixedSettings
;
417 return MtrrGetFixedMtrrWorker (FixedSettings
);
421 Worker function will get the raw value in variable MTRRs
423 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
424 MTRR settings buffer.
425 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
427 @param[in] MtrrSetting A buffer holding all MTRRs content.
428 @param[in] VariableMtrrCount Number of variable MTRRs.
429 @param[out] VariableSettings A buffer to hold variable MTRRs content.
431 @return The VariableSettings input pointer
434 MTRR_VARIABLE_SETTINGS
*
435 MtrrGetVariableMtrrWorker (
436 IN MTRR_SETTINGS
*MtrrSetting
,
437 IN UINT32 VariableMtrrCount
,
438 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
443 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
445 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
446 if (MtrrSetting
== NULL
) {
447 VariableSettings
->Mtrr
[Index
].Base
=
448 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1));
449 VariableSettings
->Mtrr
[Index
].Mask
=
450 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1));
452 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
453 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
457 return VariableSettings
;
461 Programs fixed MTRRs registers.
463 @param[in] Type The memory type to set.
464 @param[in, out] Base The base address of memory range.
465 @param[in, out] Length The length of memory range.
466 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
467 On return, the current index of the fixed MTRR MSR to program.
468 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
469 @param[out] OrMask The bits to set in the fixed MTRR MSR.
471 @retval RETURN_SUCCESS The cache type was updated successfully
472 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
477 MtrrLibProgramFixedMtrr (
478 IN MTRR_MEMORY_CACHE_TYPE Type
,
480 IN OUT UINT64
*Length
,
481 IN OUT UINT32
*LastMsrIndex
,
482 OUT UINT64
*ClearMask
,
487 UINT32 LeftByteShift
;
488 UINT32 RightByteShift
;
492 // Find the fixed MTRR index to be programmed
494 for (MsrIndex
= *LastMsrIndex
+ 1; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
495 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) &&
498 mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
+
499 (8 * mMtrrLibFixedMtrrTable
[MsrIndex
].Length
)
508 ASSERT (MsrIndex
!= ARRAY_SIZE (mMtrrLibFixedMtrrTable
));
511 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
513 if ((((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
515 // Base address should be aligned to the begin of a certain Fixed MTRR range.
517 return RETURN_UNSUPPORTED
;
520 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
521 ASSERT (LeftByteShift
< 8);
524 // Find the end offset in fixed MTRR and calculate byte offset of right shift
526 SubLength
= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
* (8 - LeftByteShift
);
527 if (*Length
>= SubLength
) {
530 if (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
532 // Length should be aligned to the end of a certain Fixed MTRR range.
534 return RETURN_UNSUPPORTED
;
537 RightByteShift
= 8 - LeftByteShift
- (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
539 // Update SubLength by actual length
544 *ClearMask
= CLEAR_SEED
;
545 *OrMask
= MultU64x32 (OR_SEED
, (UINT32
)Type
);
547 if (LeftByteShift
!= 0) {
549 // Clear the low bits by LeftByteShift
551 *ClearMask
&= LShiftU64 (*ClearMask
, LeftByteShift
* 8);
552 *OrMask
&= LShiftU64 (*OrMask
, LeftByteShift
* 8);
555 if (RightByteShift
!= 0) {
557 // Clear the high bits by RightByteShift
559 *ClearMask
&= RShiftU64 (*ClearMask
, RightByteShift
* 8);
560 *OrMask
&= RShiftU64 (*OrMask
, RightByteShift
* 8);
563 *Length
-= SubLength
;
566 *LastMsrIndex
= MsrIndex
;
568 return RETURN_SUCCESS
;
572 Worker function gets the attribute of variable MTRRs.
574 This function shadows the content of variable MTRRs into an
575 internal array: VariableMtrr.
577 @param[in] VariableSettings The variable MTRR values to shadow
578 @param[in] VariableMtrrCount The number of variable MTRRs
579 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
580 @param[in] MtrrValidAddressMask The valid address mask for MTRR
581 @param[out] VariableMtrr The array to shadow variable MTRRs content
583 @return Number of MTRRs which has been used.
587 MtrrGetMemoryAttributeInVariableMtrrWorker (
588 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
589 IN UINTN VariableMtrrCount
,
590 IN UINT64 MtrrValidBitsMask
,
591 IN UINT64 MtrrValidAddressMask
,
592 OUT VARIABLE_MTRR
*VariableMtrr
598 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
599 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
600 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*)&VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
601 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
602 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
603 VariableMtrr
[Index
].Length
=
604 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
605 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
606 VariableMtrr
[Index
].Valid
= TRUE
;
607 VariableMtrr
[Index
].Used
= TRUE
;
616 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
617 One MTRR_MEMORY_RANGE element is created for each MTRR setting.
618 The routine doesn't remove the overlap or combine the near-by region.
620 @param[in] VariableSettings The variable MTRR values to shadow
621 @param[in] VariableMtrrCount The number of variable MTRRs
622 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
623 @param[in] MtrrValidAddressMask The valid address mask for MTRR
624 @param[out] VariableMtrr The array to shadow variable MTRRs content
626 @return Number of MTRRs which has been used.
630 MtrrLibGetRawVariableRanges (
631 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
632 IN UINTN VariableMtrrCount
,
633 IN UINT64 MtrrValidBitsMask
,
634 IN UINT64 MtrrValidAddressMask
,
635 OUT MTRR_MEMORY_RANGE
*VariableMtrr
641 ZeroMem (VariableMtrr
, sizeof (MTRR_MEMORY_RANGE
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
642 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
643 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*)&VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
644 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
645 VariableMtrr
[Index
].Length
=
646 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
647 VariableMtrr
[Index
].Type
= (MTRR_MEMORY_CACHE_TYPE
)(VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
656 Gets the attribute of variable MTRRs.
658 This function shadows the content of variable MTRRs into an
659 internal array: VariableMtrr.
661 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
662 @param[in] MtrrValidAddressMask The valid address mask for MTRR
663 @param[out] VariableMtrr The array to shadow variable MTRRs content
665 @return The return value of this parameter indicates the
666 number of MTRRs which has been used.
671 MtrrGetMemoryAttributeInVariableMtrr (
672 IN UINT64 MtrrValidBitsMask
,
673 IN UINT64 MtrrValidAddressMask
,
674 OUT VARIABLE_MTRR
*VariableMtrr
677 MTRR_VARIABLE_SETTINGS VariableSettings
;
679 if (!IsMtrrSupported ()) {
683 MtrrGetVariableMtrrWorker (
685 GetVariableMtrrCountWorker (),
689 return MtrrGetMemoryAttributeInVariableMtrrWorker (
691 GetFirmwareVariableMtrrCountWorker (),
693 MtrrValidAddressMask
,
699 Return the biggest alignment (lowest set bit) of address.
700 The function is equivalent to: 1 << LowBitSet64 (Address).
702 @param Address The address to return the alignment.
703 @param Alignment0 The alignment to return when Address is 0.
705 @return The least alignment of the Address.
708 MtrrLibBiggestAlignment (
717 return Address
& ((~Address
) + 1);
721 Return whether the left MTRR type precedes the right MTRR type.
723 The MTRR type precedence rules are:
724 1. UC precedes any other type
726 For further details, please refer the IA32 Software Developer's Manual,
727 Volume 3, Section "MTRR Precedences".
729 @param Left The left MTRR type.
730 @param Right The right MTRR type.
732 @retval TRUE Left precedes Right.
733 @retval FALSE Left doesn't precede Right.
736 MtrrLibTypeLeftPrecedeRight (
737 IN MTRR_MEMORY_CACHE_TYPE Left
,
738 IN MTRR_MEMORY_CACHE_TYPE Right
741 return (BOOLEAN
)(Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
745 Initializes the valid bits mask and valid address mask for MTRRs.
747 This function initializes the valid bits mask and valid address mask for MTRRs.
749 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
750 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
754 MtrrLibInitializeMtrrMask (
755 OUT UINT64
*MtrrValidBitsMask
,
756 OUT UINT64
*MtrrValidAddressMask
759 UINT32 MaxExtendedFunction
;
760 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
762 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
764 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
765 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
767 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
770 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
771 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
775 Determines the real attribute of a memory range.
777 This function is to arbitrate the real attribute of the memory when
778 there are 2 MTRRs covers the same memory range. For further details,
779 please refer the IA32 Software Developer's Manual, Volume 3,
780 Section "MTRR Precedences".
782 @param[in] MtrrType1 The first kind of Memory type
783 @param[in] MtrrType2 The second kind of memory type
786 MTRR_MEMORY_CACHE_TYPE
788 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
789 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
792 if (MtrrType1
== MtrrType2
) {
797 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
798 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
801 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
809 Worker function will get the memory cache type of the specific address.
811 If MtrrSetting is not NULL, gets the memory cache type from input
812 MTRR settings buffer.
813 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
815 @param[in] MtrrSetting A buffer holding all MTRRs content.
816 @param[in] Address The specific address
818 @return Memory cache type of the specific address
821 MTRR_MEMORY_CACHE_TYPE
822 MtrrGetMemoryAttributeByAddressWorker (
823 IN MTRR_SETTINGS
*MtrrSetting
,
824 IN PHYSICAL_ADDRESS Address
827 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
831 MTRR_MEMORY_CACHE_TYPE MtrrType
;
832 MTRR_MEMORY_RANGE VariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
833 UINT64 MtrrValidBitsMask
;
834 UINT64 MtrrValidAddressMask
;
835 UINT32 VariableMtrrCount
;
836 MTRR_VARIABLE_SETTINGS VariableSettings
;
839 // Check if MTRR is enabled, if not, return UC as attribute
841 if (MtrrSetting
== NULL
) {
842 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
844 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
847 if (DefType
.Bits
.E
== 0) {
848 return CacheUncacheable
;
852 // If address is less than 1M, then try to go through the fixed MTRR
854 if (Address
< BASE_1MB
) {
855 if (DefType
.Bits
.FE
!= 0) {
857 // Go through the fixed MTRR
859 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
860 if ((Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) &&
861 (Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
862 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)))
865 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
866 mMtrrLibFixedMtrrTable
[Index
].Length
;
867 if (MtrrSetting
== NULL
) {
868 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
870 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
873 return (MTRR_MEMORY_CACHE_TYPE
)(RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
879 VariableMtrrCount
= GetVariableMtrrCountWorker ();
880 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
));
881 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
883 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
884 MtrrLibGetRawVariableRanges (
888 MtrrValidAddressMask
,
893 // Go through the variable MTRR
895 MtrrType
= CacheInvalid
;
896 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
897 if (VariableMtrr
[Index
].Length
!= 0) {
898 if ((Address
>= VariableMtrr
[Index
].BaseAddress
) &&
899 (Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
))
901 if (MtrrType
== CacheInvalid
) {
902 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
)VariableMtrr
[Index
].Type
;
904 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
)VariableMtrr
[Index
].Type
);
911 // If there is no MTRR which covers the Address, use the default MTRR type.
913 if (MtrrType
== CacheInvalid
) {
914 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
)DefType
.Bits
.Type
;
921 This function will get the memory cache type of the specific address.
923 This function is mainly for debug purpose.
925 @param[in] Address The specific address
927 @return Memory cache type of the specific address
930 MTRR_MEMORY_CACHE_TYPE
932 MtrrGetMemoryAttribute (
933 IN PHYSICAL_ADDRESS Address
936 if (!IsMtrrSupported ()) {
937 return CacheUncacheable
;
940 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
944 Update the Ranges array to change the specified range identified by
945 BaseAddress and Length to Type.
947 @param Ranges Array holding memory type settings for all memory regions.
948 @param Capacity The maximum count of memory ranges the array can hold.
949 @param Count Return the new memory range count in the array.
950 @param BaseAddress The base address of the memory range to change type.
951 @param Length The length of the memory range to change type.
952 @param Type The new type of the specified memory range.
954 @retval RETURN_SUCCESS The type of the specified memory range is
955 changed successfully.
956 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
958 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
959 range exceeds capacity.
962 MtrrLibSetMemoryType (
963 IN MTRR_MEMORY_RANGE
*Ranges
,
966 IN UINT64 BaseAddress
,
968 IN MTRR_MEMORY_CACHE_TYPE Type
981 Limit
= BaseAddress
+ Length
;
984 for (Index
= 0; Index
< *Count
; Index
++) {
985 if ((StartIndex
== *Count
) &&
986 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
987 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
))
990 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
993 if ((EndIndex
== *Count
) &&
994 (Ranges
[Index
].BaseAddress
< Limit
) &&
995 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
))
998 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1003 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1004 if ((StartIndex
== EndIndex
) && (Ranges
[StartIndex
].Type
== Type
)) {
1005 return RETURN_ALREADY_STARTED
;
1009 // The type change may cause merging with previous range or next range.
1010 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1011 // logic doesn't need to consider merging.
1013 if (StartIndex
!= 0) {
1014 if ((LengthLeft
== 0) && (Ranges
[StartIndex
- 1].Type
== Type
)) {
1016 Length
+= Ranges
[StartIndex
].Length
;
1017 BaseAddress
-= Ranges
[StartIndex
].Length
;
1021 if (EndIndex
!= (*Count
) - 1) {
1022 if ((LengthRight
== 0) && (Ranges
[EndIndex
+ 1].Type
== Type
)) {
1024 Length
+= Ranges
[EndIndex
].Length
;
1029 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1030 // |++++++++++++++++++| 0 3 1=3-0-2 3
1031 // |+++++++| 0 1 -1=1-0-2 5
1032 // |+| 0 0 -2=0-0-2 6
1033 // |+++| 0 0 -1=0-0-2+1 5
1036 DeltaCount
= EndIndex
- StartIndex
- 2;
1037 if (LengthLeft
== 0) {
1041 if (LengthRight
== 0) {
1045 if (*Count
- DeltaCount
> Capacity
) {
1046 return RETURN_OUT_OF_RESOURCES
;
1050 // Reserve (-DeltaCount) space
1052 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1053 *Count
-= DeltaCount
;
1055 if (LengthLeft
!= 0) {
1056 Ranges
[StartIndex
].Length
= LengthLeft
;
1060 if (LengthRight
!= 0) {
1061 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1062 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1063 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1066 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1067 Ranges
[StartIndex
].Length
= Length
;
1068 Ranges
[StartIndex
].Type
= Type
;
1069 return RETURN_SUCCESS
;
1073 Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1075 @param Ranges Array holding memory type settings for all memory regions.
1076 @param RangeCount The count of memory ranges the array holds.
1077 @param BaseAddress Base address.
1078 @param Length Length.
1079 @param Types Return bit mask to indicate all memory types in the specified range.
1081 @retval Number of memory types.
1084 MtrrLibGetNumberOfTypes (
1085 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1086 IN UINTN RangeCount
,
1087 IN UINT64 BaseAddress
,
1089 IN OUT UINT8
*Types OPTIONAL
1098 for (Index
= 0; Index
< RangeCount
; Index
++) {
1099 if ((Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1100 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)
1103 if ((LocalTypes
& (1 << Ranges
[Index
].Type
)) == 0) {
1104 LocalTypes
|= (UINT8
)(1 << Ranges
[Index
].Type
);
1108 if (BaseAddress
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1109 Length
-= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1110 BaseAddress
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
;
1117 if (Types
!= NULL
) {
1118 *Types
= LocalTypes
;
1125 Calculate the least MTRR number from vertex Start to Stop and update
1126 the Previous of all vertices from Start to Stop is updated to reflect
1127 how the memory range is covered by MTRR.
1129 @param VertexCount The count of vertices in the graph.
1130 @param Vertices Array holding all vertices.
1131 @param Weight 2-dimention array holding weights between vertices.
1132 @param Start Start vertex.
1133 @param Stop Stop vertex.
1134 @param IncludeOptional TRUE to count the optional weight.
1137 MtrrLibCalculateLeastMtrrs (
1138 IN UINT16 VertexCount
,
1139 IN MTRR_LIB_ADDRESS
*Vertices
,
1140 IN OUT CONST UINT8
*Weight
,
1143 IN BOOLEAN IncludeOptional
1152 for (Index
= Start
; Index
<= Stop
; Index
++) {
1153 Vertices
[Index
].Visited
= FALSE
;
1154 Mandatory
= Weight
[M (Start
, Index
)];
1155 Vertices
[Index
].Weight
= Mandatory
;
1156 if (Mandatory
!= MAX_WEIGHT
) {
1157 Optional
= IncludeOptional
? Weight
[O (Start
, Index
)] : 0;
1158 Vertices
[Index
].Weight
+= Optional
;
1159 ASSERT (Vertices
[Index
].Weight
>= Optional
);
1165 while (!Vertices
[Stop
].Visited
) {
1167 // Update the weight from the shortest vertex to other unvisited vertices
1169 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1170 if (!Vertices
[Index
].Visited
) {
1171 Mandatory
= Weight
[M (MinI
, Index
)];
1172 if (Mandatory
!= MAX_WEIGHT
) {
1173 Optional
= IncludeOptional
? Weight
[O (MinI
, Index
)] : 0;
1174 if (MinWeight
+ Mandatory
+ Optional
<= Vertices
[Index
].Weight
) {
1175 Vertices
[Index
].Weight
= MinWeight
+ Mandatory
+ Optional
;
1176 Vertices
[Index
].Previous
= MinI
; // Previous is Start based.
1183 // Find the shortest vertex from Start
1186 MinWeight
= MAX_WEIGHT
;
1187 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1188 if (!Vertices
[Index
].Visited
&& (MinWeight
> Vertices
[Index
].Weight
)) {
1190 MinWeight
= Vertices
[Index
].Weight
;
1195 // Mark the shortest vertex from Start as visited
1197 Vertices
[MinI
].Visited
= TRUE
;
1202 Append the MTRR setting to MTRR setting array.
1204 @param Mtrrs Array holding all MTRR settings.
1205 @param MtrrCapacity Capacity of the MTRR array.
1206 @param MtrrCount The count of MTRR settings in array.
1207 @param BaseAddress Base address.
1208 @param Length Length.
1209 @param Type Memory type.
1211 @retval RETURN_SUCCESS MTRR setting is appended to array.
1212 @retval RETURN_OUT_OF_RESOURCES Array is full.
1215 MtrrLibAppendVariableMtrr (
1216 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1217 IN UINT32 MtrrCapacity
,
1218 IN OUT UINT32
*MtrrCount
,
1219 IN UINT64 BaseAddress
,
1221 IN MTRR_MEMORY_CACHE_TYPE Type
1224 if (*MtrrCount
== MtrrCapacity
) {
1225 return RETURN_OUT_OF_RESOURCES
;
1228 Mtrrs
[*MtrrCount
].BaseAddress
= BaseAddress
;
1229 Mtrrs
[*MtrrCount
].Length
= Length
;
1230 Mtrrs
[*MtrrCount
].Type
= Type
;
1232 return RETURN_SUCCESS
;
1236 Return the memory type that has the least precedence.
1238 @param TypeBits Bit mask of memory type.
1240 @retval Memory type that has the least precedence.
1242 MTRR_MEMORY_CACHE_TYPE
1249 ASSERT (TypeBits
!= 0);
1250 for (Type
= 7; (INT8
)TypeBits
> 0; Type
--, TypeBits
<<= 1) {
1253 return (MTRR_MEMORY_CACHE_TYPE
)Type
;
1257 Return TRUE when the Operand is exactly power of 2.
1259 @retval TRUE Operand is exactly power of 2.
1260 @retval FALSE Operand is not power of 2.
1263 MtrrLibIsPowerOfTwo (
1267 ASSERT (Operand
!= 0);
1268 return (BOOLEAN
)((Operand
& (Operand
- 1)) == 0);
1272 Calculate the subtractive path from vertex Start to Stop.
1274 @param DefaultType Default memory type.
1275 @param A0 Alignment to use when base address is 0.
1276 @param Ranges Array holding memory type settings for all memory regions.
1277 @param RangeCount The count of memory ranges the array holds.
1278 @param VertexCount The count of vertices in the graph.
1279 @param Vertices Array holding all vertices.
1280 @param Weight 2-dimention array holding weights between vertices.
1281 @param Start Start vertex.
1282 @param Stop Stop vertex.
1283 @param Types Type bit mask of memory range from Start to Stop.
1284 @param TypeCount Number of different memory types from Start to Stop.
1285 @param Mtrrs Array holding all MTRR settings.
1286 @param MtrrCapacity Capacity of the MTRR array.
1287 @param MtrrCount The count of MTRR settings in array.
1289 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1290 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1294 MtrrLibCalculateSubtractivePath (
1295 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1297 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1298 IN UINTN RangeCount
,
1299 IN UINT16 VertexCount
,
1300 IN MTRR_LIB_ADDRESS
*Vertices
,
1301 IN OUT UINT8
*Weight
,
1306 IN OUT MTRR_MEMORY_RANGE
*Mtrrs OPTIONAL
,
1307 IN UINT32 MtrrCapacity OPTIONAL
,
1308 IN OUT UINT32
*MtrrCount OPTIONAL
1311 RETURN_STATUS Status
;
1314 UINT8 PrecedentTypes
;
1323 MTRR_MEMORY_CACHE_TYPE LowestType
;
1324 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType
;
1326 Base
= Vertices
[Start
].Address
;
1327 Length
= Vertices
[Stop
].Address
- Base
;
1329 LowestType
= MtrrLibLowestType (Types
);
1332 // Clear the lowest type (highest bit) to get the precedent types
1334 PrecedentTypes
= ~(1 << LowestType
) & Types
;
1335 LowestPrecedentType
= MtrrLibLowestType (PrecedentTypes
);
1337 if (Mtrrs
== NULL
) {
1338 Weight
[M (Start
, Stop
)] = ((LowestType
== DefaultType
) ? 0 : 1);
1339 Weight
[O (Start
, Stop
)] = ((LowestType
== DefaultType
) ? 1 : 0);
1342 // Add all high level ranges
1345 for (Index
= 0; Index
< RangeCount
; Index
++) {
1350 if ((Base
< Ranges
[Index
].BaseAddress
) || (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
<= Base
)) {
1355 // Base is in the Range[Index]
1357 if (Base
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1358 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Base
;
1363 if (((1 << Ranges
[Index
].Type
) & PrecedentTypes
) != 0) {
1365 // Meet a range whose types take precedence.
1366 // Update the [HBase, HBase + HLength) to include the range,
1367 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1369 if (HBase
== MAX_UINT64
) {
1373 HLength
+= SubLength
;
1377 Length
-= SubLength
;
1383 if ((Ranges
[Index
].Type
== LowestType
) || (Length
== 0)) {
1384 // meet low type or end
1387 // Add the MTRRs for each high priority type range
1388 // the range[HBase, HBase + HLength) contains only two types.
1389 // We might use positive or subtractive, depending on which way uses less MTRR
1391 for (SubStart
= Start
; SubStart
<= Stop
; SubStart
++) {
1392 if (Vertices
[SubStart
].Address
== HBase
) {
1397 for (SubStop
= SubStart
; SubStop
<= Stop
; SubStop
++) {
1398 if (Vertices
[SubStop
].Address
== HBase
+ HLength
) {
1403 ASSERT (Vertices
[SubStart
].Address
== HBase
);
1404 ASSERT (Vertices
[SubStop
].Address
== HBase
+ HLength
);
1406 if ((TypeCount
== 2) || (SubStart
== SubStop
- 1)) {
1408 // add subtractive MTRRs for [HBase, HBase + HLength)
1409 // [HBase, HBase + HLength) contains only one type.
1410 // while - loop is to split the range to MTRR - compliant aligned range.
1412 if (Mtrrs
== NULL
) {
1413 Weight
[M (Start
, Stop
)] += (UINT8
)(SubStop
- SubStart
);
1415 while (SubStart
!= SubStop
) {
1416 Status
= MtrrLibAppendVariableMtrr (
1420 Vertices
[SubStart
].Address
,
1421 Vertices
[SubStart
].Length
,
1422 Vertices
[SubStart
].Type
1424 if (RETURN_ERROR (Status
)) {
1432 ASSERT (TypeCount
== 3);
1433 MtrrLibCalculateLeastMtrrs (VertexCount
, Vertices
, Weight
, SubStart
, SubStop
, TRUE
);
1435 if (Mtrrs
== NULL
) {
1436 Weight
[M (Start
, Stop
)] += Vertices
[SubStop
].Weight
;
1438 // When we need to collect the optimal path from SubStart to SubStop
1439 while (SubStop
!= SubStart
) {
1441 Pre
= Vertices
[Cur
].Previous
;
1444 if (Weight
[M (Pre
, Cur
)] + Weight
[O (Pre
, Cur
)] != 0) {
1445 Status
= MtrrLibAppendVariableMtrr (
1449 Vertices
[Pre
].Address
,
1450 Vertices
[Cur
].Address
- Vertices
[Pre
].Address
,
1451 (Pre
!= Cur
- 1) ? LowestPrecedentType
: Vertices
[Pre
].Type
1453 if (RETURN_ERROR (Status
)) {
1458 if (Pre
!= Cur
- 1) {
1459 Status
= MtrrLibCalculateSubtractivePath (
1475 if (RETURN_ERROR (Status
)) {
1484 // Reset HBase, HLength
1491 return RETURN_SUCCESS
;
1495 Calculate MTRR settings to cover the specified memory ranges.
1497 @param DefaultType Default memory type.
1498 @param A0 Alignment to use when base address is 0.
1499 @param Ranges Memory range array holding the memory type
1500 settings for all memory address.
1501 @param RangeCount Count of memory ranges.
1502 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1503 This is an optional parameter that may be NULL.
1504 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1505 It may be updated to the actual required size when the calculation
1506 needs more scratch buffer.
1507 @param Mtrrs Array holding all MTRR settings.
1508 @param MtrrCapacity Capacity of the MTRR array.
1509 @param MtrrCount The count of MTRR settings in array.
1511 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1512 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1513 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1516 MtrrLibCalculateMtrrs (
1517 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1519 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1520 IN UINTN RangeCount
,
1522 IN OUT UINTN
*ScratchSize
,
1523 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1524 IN UINT32 MtrrCapacity
,
1525 IN OUT UINT32
*MtrrCount
1535 MTRR_LIB_ADDRESS
*Vertices
;
1539 UINTN RequiredScratchSize
;
1544 RETURN_STATUS Status
;
1546 Base0
= Ranges
[0].BaseAddress
;
1547 Base1
= Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
;
1548 MTRR_LIB_ASSERT_ALIGNED (Base0
, Base1
- Base0
);
1551 // Count the number of vertices.
1553 Vertices
= (MTRR_LIB_ADDRESS
*)Scratch
;
1554 for (VertexIndex
= 0, Index
= 0; Index
< RangeCount
; Index
++) {
1555 Base
= Ranges
[Index
].BaseAddress
;
1556 Length
= Ranges
[Index
].Length
;
1557 while (Length
!= 0) {
1558 Alignment
= MtrrLibBiggestAlignment (Base
, A0
);
1559 SubLength
= Alignment
;
1560 if (SubLength
> Length
) {
1561 SubLength
= GetPowerOfTwo64 (Length
);
1564 if (VertexIndex
< *ScratchSize
/ sizeof (*Vertices
)) {
1565 Vertices
[VertexIndex
].Address
= Base
;
1566 Vertices
[VertexIndex
].Alignment
= Alignment
;
1567 Vertices
[VertexIndex
].Type
= Ranges
[Index
].Type
;
1568 Vertices
[VertexIndex
].Length
= SubLength
;
1572 Length
-= SubLength
;
1578 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1580 VertexCount
= VertexIndex
+ 1;
1583 " Count of vertices (%016llx - %016llx) = %d\n",
1584 Ranges
[0].BaseAddress
,
1585 Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
,
1588 ASSERT (VertexCount
< MAX_UINT16
);
1590 RequiredScratchSize
= VertexCount
* sizeof (*Vertices
) + VertexCount
* VertexCount
* sizeof (*Weight
);
1591 if (*ScratchSize
< RequiredScratchSize
) {
1592 *ScratchSize
= RequiredScratchSize
;
1593 return RETURN_BUFFER_TOO_SMALL
;
1596 Vertices
[VertexCount
- 1].Address
= Base1
;
1598 Weight
= (UINT8
*)&Vertices
[VertexCount
];
1599 for (VertexIndex
= 0; VertexIndex
< VertexCount
; VertexIndex
++) {
1601 // Set optional weight between vertices and self->self to 0
1603 SetMem (&Weight
[M (VertexIndex
, 0)], VertexIndex
+ 1, 0);
1605 // Set mandatory weight between vertices to MAX_WEIGHT
1607 SetMem (&Weight
[M (VertexIndex
, VertexIndex
+ 1)], VertexCount
- VertexIndex
- 1, MAX_WEIGHT
);
1609 // Final result looks like:
1617 // Set mandatory weight and optional weight for adjacent vertices
1619 for (VertexIndex
= 0; VertexIndex
< VertexCount
- 1; VertexIndex
++) {
1620 if (Vertices
[VertexIndex
].Type
!= DefaultType
) {
1621 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 1;
1622 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 0;
1624 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 0;
1625 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 1;
1629 for (TypeCount
= 2; TypeCount
<= 3; TypeCount
++) {
1630 for (Start
= 0; Start
< VertexCount
; Start
++) {
1631 for (Stop
= Start
+ 2; Stop
< VertexCount
; Stop
++) {
1632 ASSERT (Vertices
[Stop
].Address
> Vertices
[Start
].Address
);
1633 Length
= Vertices
[Stop
].Address
- Vertices
[Start
].Address
;
1634 if (Length
> Vertices
[Start
].Alignment
) {
1636 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1641 if ((Weight
[M (Start
, Stop
)] == MAX_WEIGHT
) && MtrrLibIsPowerOfTwo (Length
)) {
1642 if (MtrrLibGetNumberOfTypes (
1645 Vertices
[Start
].Address
,
1646 Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1651 // Update the Weight[Start, Stop] using subtractive path.
1653 MtrrLibCalculateSubtractivePath (
1658 (UINT16
)VertexCount
,
1669 } else if (TypeCount
== 2) {
1671 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1672 // Because no matter how Stop is increased, we always meet 3-type range.
1681 Status
= RETURN_SUCCESS
;
1682 MtrrLibCalculateLeastMtrrs ((UINT16
)VertexCount
, Vertices
, Weight
, 0, (UINT16
)VertexCount
- 1, FALSE
);
1683 Stop
= (UINT16
)VertexCount
- 1;
1685 Start
= Vertices
[Stop
].Previous
;
1686 TypeCount
= MAX_UINT8
;
1688 if (Weight
[M (Start
, Stop
)] != 0) {
1689 TypeCount
= MtrrLibGetNumberOfTypes (Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
);
1690 Status
= MtrrLibAppendVariableMtrr (
1694 Vertices
[Start
].Address
,
1695 Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1696 MtrrLibLowestType (Type
)
1698 if (RETURN_ERROR (Status
)) {
1703 if (Start
!= Stop
- 1) {
1705 // substractive path
1707 if (TypeCount
== MAX_UINT8
) {
1708 TypeCount
= MtrrLibGetNumberOfTypes (
1711 Vertices
[Start
].Address
,
1712 Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1717 Status
= MtrrLibCalculateSubtractivePath (
1722 (UINT16
)VertexCount
,
1733 if (RETURN_ERROR (Status
)) {
1745 Apply the fixed MTRR settings to memory range array.
1747 @param Fixed The fixed MTRR settings.
1748 @param Ranges Return the memory range array holding memory type
1749 settings for all memory address.
1750 @param RangeCapacity The capacity of memory range array.
1751 @param RangeCount Return the count of memory range.
1753 @retval RETURN_SUCCESS The memory range array is returned successfully.
1754 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1757 MtrrLibApplyFixedMtrrs (
1758 IN MTRR_FIXED_SETTINGS
*Fixed
,
1759 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1760 IN UINTN RangeCapacity
,
1761 IN OUT UINTN
*RangeCount
1764 RETURN_STATUS Status
;
1767 MTRR_MEMORY_CACHE_TYPE MemoryType
;
1771 for (MsrIndex
= 0; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
1772 ASSERT (Base
== mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
);
1773 for (Index
= 0; Index
< sizeof (UINT64
); Index
++) {
1774 MemoryType
= (MTRR_MEMORY_CACHE_TYPE
)((UINT8
*)(&Fixed
->Mtrr
[MsrIndex
]))[Index
];
1775 Status
= MtrrLibSetMemoryType (
1780 mMtrrLibFixedMtrrTable
[MsrIndex
].Length
,
1783 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1787 Base
+= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
1791 ASSERT (Base
== BASE_1MB
);
1792 return RETURN_SUCCESS
;
1796 Apply the variable MTRR settings to memory range array.
1798 @param VariableMtrr The variable MTRR array.
1799 @param VariableMtrrCount The count of variable MTRRs.
1800 @param Ranges Return the memory range array with new MTRR settings applied.
1801 @param RangeCapacity The capacity of memory range array.
1802 @param RangeCount Return the count of memory range.
1804 @retval RETURN_SUCCESS The memory range array is returned successfully.
1805 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1808 MtrrLibApplyVariableMtrrs (
1809 IN CONST MTRR_MEMORY_RANGE
*VariableMtrr
,
1810 IN UINT32 VariableMtrrCount
,
1811 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1812 IN UINTN RangeCapacity
,
1813 IN OUT UINTN
*RangeCount
1816 RETURN_STATUS Status
;
1822 // UC > * (except WB, UC) > WB
1828 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1829 if ((VariableMtrr
[Index
].Length
!= 0) && (VariableMtrr
[Index
].Type
== CacheWriteBack
)) {
1830 Status
= MtrrLibSetMemoryType (
1834 VariableMtrr
[Index
].BaseAddress
,
1835 VariableMtrr
[Index
].Length
,
1836 VariableMtrr
[Index
].Type
1838 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1845 // 2. Set other types than WB or UC
1847 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1848 if ((VariableMtrr
[Index
].Length
!= 0) &&
1849 (VariableMtrr
[Index
].Type
!= CacheWriteBack
) && (VariableMtrr
[Index
].Type
!= CacheUncacheable
))
1851 Status
= MtrrLibSetMemoryType (
1855 VariableMtrr
[Index
].BaseAddress
,
1856 VariableMtrr
[Index
].Length
,
1857 VariableMtrr
[Index
].Type
1859 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1868 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1869 if ((VariableMtrr
[Index
].Length
!= 0) && (VariableMtrr
[Index
].Type
== CacheUncacheable
)) {
1870 Status
= MtrrLibSetMemoryType (
1874 VariableMtrr
[Index
].BaseAddress
,
1875 VariableMtrr
[Index
].Length
,
1876 VariableMtrr
[Index
].Type
1878 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1884 return RETURN_SUCCESS
;
1888 Return the memory type bit mask that's compatible to first type in the Ranges.
1890 @param Ranges Memory range array holding the memory type
1891 settings for all memory address.
1892 @param RangeCount Count of memory ranges.
1894 @return Compatible memory type bit mask.
1897 MtrrLibGetCompatibleTypes (
1898 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1902 ASSERT (RangeCount
!= 0);
1904 switch (Ranges
[0].Type
) {
1905 case CacheWriteBack
:
1906 case CacheWriteThrough
:
1907 return (1 << CacheWriteBack
) | (1 << CacheWriteThrough
) | (1 << CacheUncacheable
);
1910 case CacheWriteCombining
:
1911 case CacheWriteProtected
:
1912 return (1 << Ranges
[0].Type
) | (1 << CacheUncacheable
);
1915 case CacheUncacheable
:
1916 if (RangeCount
== 1) {
1917 return (1 << CacheUncacheable
);
1920 return MtrrLibGetCompatibleTypes (&Ranges
[1], RangeCount
- 1);
1933 Overwrite the destination MTRR settings with the source MTRR settings.
1934 This routine is to make sure the modification to destination MTRR settings
1935 is as small as possible.
1937 @param DstMtrrs Destination MTRR settings.
1938 @param DstMtrrCount Count of destination MTRR settings.
1939 @param SrcMtrrs Source MTRR settings.
1940 @param SrcMtrrCount Count of source MTRR settings.
1941 @param Modified Flag array to indicate which destination MTRR setting is modified.
1944 MtrrLibMergeVariableMtrr (
1945 MTRR_MEMORY_RANGE
*DstMtrrs
,
1946 UINT32 DstMtrrCount
,
1947 MTRR_MEMORY_RANGE
*SrcMtrrs
,
1948 UINT32 SrcMtrrCount
,
1955 ASSERT (SrcMtrrCount
<= DstMtrrCount
);
1957 for (DstIndex
= 0; DstIndex
< DstMtrrCount
; DstIndex
++) {
1958 Modified
[DstIndex
] = FALSE
;
1960 if (DstMtrrs
[DstIndex
].Length
== 0) {
1964 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1965 if ((DstMtrrs
[DstIndex
].BaseAddress
== SrcMtrrs
[SrcIndex
].BaseAddress
) &&
1966 (DstMtrrs
[DstIndex
].Length
== SrcMtrrs
[SrcIndex
].Length
) &&
1967 (DstMtrrs
[DstIndex
].Type
== SrcMtrrs
[SrcIndex
].Type
))
1973 if (SrcIndex
== SrcMtrrCount
) {
1975 // Remove the one from DstMtrrs which is not in SrcMtrrs
1977 DstMtrrs
[DstIndex
].Length
= 0;
1978 Modified
[DstIndex
] = TRUE
;
1981 // Remove the one from SrcMtrrs which is also in DstMtrrs
1983 SrcMtrrs
[SrcIndex
].Length
= 0;
1988 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1989 // Merge MTRRs from SrcMtrrs to DstMtrrs
1992 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1993 if (SrcMtrrs
[SrcIndex
].Length
!= 0) {
1995 // Find the empty slot in DstMtrrs
1997 while (DstIndex
< DstMtrrCount
) {
1998 if (DstMtrrs
[DstIndex
].Length
== 0) {
2005 ASSERT (DstIndex
< DstMtrrCount
);
2006 CopyMem (&DstMtrrs
[DstIndex
], &SrcMtrrs
[SrcIndex
], sizeof (SrcMtrrs
[0]));
2007 Modified
[DstIndex
] = TRUE
;
2013 Calculate the variable MTRR settings for all memory ranges.
2015 @param DefaultType Default memory type.
2016 @param A0 Alignment to use when base address is 0.
2017 @param Ranges Memory range array holding the memory type
2018 settings for all memory address.
2019 @param RangeCount Count of memory ranges.
2020 @param Scratch Scratch buffer to be used in MTRR calculation.
2021 @param ScratchSize Pointer to the size of scratch buffer.
2022 @param VariableMtrr Array holding all MTRR settings.
2023 @param VariableMtrrCapacity Capacity of the MTRR array.
2024 @param VariableMtrrCount The count of MTRR settings in array.
2026 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
2027 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
2028 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2029 The required scratch buffer size is returned through ScratchSize.
2032 MtrrLibSetMemoryRanges (
2033 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
2035 IN MTRR_MEMORY_RANGE
*Ranges
,
2036 IN UINTN RangeCount
,
2038 IN OUT UINTN
*ScratchSize
,
2039 OUT MTRR_MEMORY_RANGE
*VariableMtrr
,
2040 IN UINT32 VariableMtrrCapacity
,
2041 OUT UINT32
*VariableMtrrCount
2044 RETURN_STATUS Status
;
2049 UINT8 CompatibleTypes
;
2052 UINTN ActualScratchSize
;
2053 UINTN BiggestScratchSize
;
2055 *VariableMtrrCount
= 0;
2058 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
2059 // Each call needs different scratch buffer size.
2060 // When the provided scratch buffer size is not sufficient in any call,
2061 // set the GetActualScratchSize to TRUE, and following calls will only
2062 // calculate the actual scratch size for the caller.
2064 BiggestScratchSize
= 0;
2066 for (Index
= 0; Index
< RangeCount
;) {
2067 Base0
= Ranges
[Index
].BaseAddress
;
2070 // Full step is optimal
2072 while (Index
< RangeCount
) {
2073 ASSERT (Ranges
[Index
].BaseAddress
== Base0
);
2074 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2075 while (Base0
+ Alignment
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
2076 if ((BiggestScratchSize
<= *ScratchSize
) && (Ranges
[Index
].Type
!= DefaultType
)) {
2077 Status
= MtrrLibAppendVariableMtrr (
2079 VariableMtrrCapacity
,
2085 if (RETURN_ERROR (Status
)) {
2091 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2095 // Remove the above range from Ranges[Index]
2097 Ranges
[Index
].Length
-= Base0
- Ranges
[Index
].BaseAddress
;
2098 Ranges
[Index
].BaseAddress
= Base0
;
2099 if (Ranges
[Index
].Length
!= 0) {
2106 if (Index
== RangeCount
) {
2111 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2112 // Per SDM, the compatible types between[B0, B1) are:
2117 CompatibleTypes
= MtrrLibGetCompatibleTypes (&Ranges
[Index
], RangeCount
- Index
);
2119 End
= Index
; // End points to last one that matches the CompatibleTypes.
2120 while (End
+ 1 < RangeCount
) {
2121 if (((1 << Ranges
[End
+ 1].Type
) & CompatibleTypes
) == 0) {
2128 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2129 Length
= GetPowerOfTwo64 (Ranges
[End
].BaseAddress
+ Ranges
[End
].Length
- Base0
);
2130 Base1
= Base0
+ MIN (Alignment
, Length
);
2133 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2136 while (End
+ 1 < RangeCount
) {
2137 if (Base1
<= Ranges
[End
+ 1].BaseAddress
) {
2144 Length
= Ranges
[End
].Length
;
2145 Ranges
[End
].Length
= Base1
- Ranges
[End
].BaseAddress
;
2146 ActualScratchSize
= *ScratchSize
;
2147 Status
= MtrrLibCalculateMtrrs (
2155 VariableMtrrCapacity
,
2158 if (Status
== RETURN_BUFFER_TOO_SMALL
) {
2159 BiggestScratchSize
= MAX (BiggestScratchSize
, ActualScratchSize
);
2161 // Ignore this error, because we need to calculate the biggest
2162 // scratch buffer size.
2164 Status
= RETURN_SUCCESS
;
2167 if (RETURN_ERROR (Status
)) {
2171 if (Length
!= Ranges
[End
].Length
) {
2172 Ranges
[End
].BaseAddress
= Base1
;
2173 Ranges
[End
].Length
= Length
- Ranges
[End
].Length
;
2180 if (*ScratchSize
< BiggestScratchSize
) {
2181 *ScratchSize
= BiggestScratchSize
;
2182 return RETURN_BUFFER_TOO_SMALL
;
2185 return RETURN_SUCCESS
;
2189 Set the below-1MB memory attribute to fixed MTRR buffer.
2190 Modified flag array indicates which fixed MTRR is modified.
2192 @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
2193 @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
2194 @param [in] BaseAddress Base address.
2195 @param [in] Length Length.
2196 @param [in] Type Memory type.
2198 @retval RETURN_SUCCESS The memory attribute is set successfully.
2199 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2200 for the fixed MTRRs.
2203 MtrrLibSetBelow1MBMemoryAttribute (
2204 IN OUT UINT64
*ClearMasks
,
2205 IN OUT UINT64
*OrMasks
,
2206 IN PHYSICAL_ADDRESS BaseAddress
,
2208 IN MTRR_MEMORY_CACHE_TYPE Type
2211 RETURN_STATUS Status
;
2216 ASSERT (BaseAddress
< BASE_1MB
);
2218 MsrIndex
= (UINT32
)-1;
2219 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
2220 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
2221 if (RETURN_ERROR (Status
)) {
2225 ClearMasks
[MsrIndex
] = ClearMasks
[MsrIndex
] | ClearMask
;
2226 OrMasks
[MsrIndex
] = (OrMasks
[MsrIndex
] & ~ClearMask
) | OrMask
;
2229 return RETURN_SUCCESS
;
2233 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2235 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2236 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2237 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2238 It may be updated to the actual required size when the calculation
2239 needs more scratch buffer.
2240 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2241 When range overlap happens, the last one takes higher priority.
2242 When the function returns, either all the attributes are set successfully,
2243 or none of them is set.
2244 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2246 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2247 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2248 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2249 memory resource range specified by BaseAddress and Length in any range.
2250 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2251 range specified by BaseAddress and Length in any range.
2252 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2253 the memory resource ranges.
2254 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2255 BaseAddress and Length cannot be modified.
2256 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2260 MtrrSetMemoryAttributesInMtrrSettings (
2261 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2263 IN OUT UINTN
*ScratchSize
,
2264 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
2268 RETURN_STATUS Status
;
2272 BOOLEAN Above1MbExist
;
2274 UINT64 MtrrValidBitsMask
;
2275 UINT64 MtrrValidAddressMask
;
2276 MTRR_MEMORY_CACHE_TYPE DefaultType
;
2277 MTRR_VARIABLE_SETTINGS VariableSettings
;
2278 MTRR_MEMORY_RANGE WorkingRanges
[2 * ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
) + 2];
2279 UINTN WorkingRangeCount
;
2281 MTRR_VARIABLE_SETTING VariableSetting
;
2282 UINT32 OriginalVariableMtrrCount
;
2283 UINT32 FirmwareVariableMtrrCount
;
2284 UINT32 WorkingVariableMtrrCount
;
2285 MTRR_MEMORY_RANGE OriginalVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2286 MTRR_MEMORY_RANGE WorkingVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2287 BOOLEAN VariableSettingModified
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2289 UINT64 ClearMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2290 UINT64 OrMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2292 MTRR_CONTEXT MtrrContext
;
2293 BOOLEAN MtrrContextValid
;
2295 Status
= RETURN_SUCCESS
;
2296 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2299 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2301 SetMem (VariableSettingModified
, ARRAY_SIZE (VariableSettingModified
), FALSE
);
2304 // TRUE indicating the caller requests to set variable MTRRs.
2306 Above1MbExist
= FALSE
;
2307 OriginalVariableMtrrCount
= 0;
2310 // 0. Dump the requests.
2312 DEBUG_CODE_BEGIN ();
2315 "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2316 (MtrrSetting
== NULL
) ? "Hardware" : "Buffer",
2318 (RangeCount
<= 1) ? "," : "\n"
2320 for (Index
= 0; Index
< RangeCount
; Index
++) {
2323 " %a: [%016lx, %016lx)\n",
2324 mMtrrMemoryCacheTypeShortName
[MIN (Ranges
[Index
].Type
, CacheInvalid
)],
2325 Ranges
[Index
].BaseAddress
,
2326 Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
2333 // 1. Validate the parameters.
2335 if (!IsMtrrSupported ()) {
2336 Status
= RETURN_UNSUPPORTED
;
2340 for (Index
= 0; Index
< RangeCount
; Index
++) {
2341 if (Ranges
[Index
].Length
== 0) {
2342 Status
= RETURN_INVALID_PARAMETER
;
2346 if (((Ranges
[Index
].BaseAddress
& ~MtrrValidAddressMask
) != 0) ||
2347 ((((Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) & ~MtrrValidAddressMask
) != 0) &&
2348 ((Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) != MtrrValidBitsMask
+ 1))
2352 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2353 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2355 Status
= RETURN_UNSUPPORTED
;
2359 if ((Ranges
[Index
].Type
!= CacheUncacheable
) &&
2360 (Ranges
[Index
].Type
!= CacheWriteCombining
) &&
2361 (Ranges
[Index
].Type
!= CacheWriteThrough
) &&
2362 (Ranges
[Index
].Type
!= CacheWriteProtected
) &&
2363 (Ranges
[Index
].Type
!= CacheWriteBack
))
2365 Status
= RETURN_INVALID_PARAMETER
;
2369 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
> BASE_1MB
) {
2370 Above1MbExist
= TRUE
;
2375 // 2. Apply the above-1MB memory attribute settings.
2377 if (Above1MbExist
) {
2379 // 2.1. Read all variable MTRRs and convert to Ranges.
2381 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
2382 MtrrGetVariableMtrrWorker (MtrrSetting
, OriginalVariableMtrrCount
, &VariableSettings
);
2383 MtrrLibGetRawVariableRanges (
2385 OriginalVariableMtrrCount
,
2387 MtrrValidAddressMask
,
2388 OriginalVariableMtrr
2391 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
2392 WorkingRangeCount
= 1;
2393 WorkingRanges
[0].BaseAddress
= 0;
2394 WorkingRanges
[0].Length
= MtrrValidBitsMask
+ 1;
2395 WorkingRanges
[0].Type
= DefaultType
;
2397 Status
= MtrrLibApplyVariableMtrrs (
2398 OriginalVariableMtrr
,
2399 OriginalVariableMtrrCount
,
2401 ARRAY_SIZE (WorkingRanges
),
2404 ASSERT_RETURN_ERROR (Status
);
2406 ASSERT (OriginalVariableMtrrCount
>= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
));
2407 FirmwareVariableMtrrCount
= OriginalVariableMtrrCount
- PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
2408 ASSERT (WorkingRangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
2411 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2413 Status
= MtrrLibSetMemoryType (
2415 ARRAY_SIZE (WorkingRanges
),
2421 ASSERT (Status
!= RETURN_OUT_OF_RESOURCES
);
2424 // 2.3. Apply the new memory attribute settings to Ranges.
2427 for (Index
= 0; Index
< RangeCount
; Index
++) {
2428 BaseAddress
= Ranges
[Index
].BaseAddress
;
2429 Length
= Ranges
[Index
].Length
;
2430 if (BaseAddress
< BASE_1MB
) {
2431 if (Length
<= BASE_1MB
- BaseAddress
) {
2435 Length
-= BASE_1MB
- BaseAddress
;
2436 BaseAddress
= BASE_1MB
;
2439 Status
= MtrrLibSetMemoryType (
2441 ARRAY_SIZE (WorkingRanges
),
2447 if (Status
== RETURN_ALREADY_STARTED
) {
2448 Status
= RETURN_SUCCESS
;
2449 } else if (Status
== RETURN_OUT_OF_RESOURCES
) {
2452 ASSERT_RETURN_ERROR (Status
);
2459 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2460 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2462 Status
= MtrrLibSetMemoryRanges (
2464 LShiftU64 (1, (UINTN
)HighBitSet64 (MtrrValidBitsMask
)),
2469 WorkingVariableMtrr
,
2470 FirmwareVariableMtrrCount
+ 1,
2471 &WorkingVariableMtrrCount
2473 if (RETURN_ERROR (Status
)) {
2478 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2480 for (Index
= 0; Index
< WorkingVariableMtrrCount
; Index
++) {
2481 if ((WorkingVariableMtrr
[Index
].BaseAddress
== 0) && (WorkingVariableMtrr
[Index
].Length
== SIZE_1MB
)) {
2482 ASSERT (WorkingVariableMtrr
[Index
].Type
== CacheUncacheable
);
2483 WorkingVariableMtrrCount
--;
2485 &WorkingVariableMtrr
[Index
],
2486 &WorkingVariableMtrr
[Index
+ 1],
2487 (WorkingVariableMtrrCount
- Index
) * sizeof (WorkingVariableMtrr
[0])
2493 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
2494 Status
= RETURN_OUT_OF_RESOURCES
;
2499 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2500 // Make sure least modification is made to OriginalVariableMtrr.
2502 MtrrLibMergeVariableMtrr (
2503 OriginalVariableMtrr
,
2504 OriginalVariableMtrrCount
,
2505 WorkingVariableMtrr
,
2506 WorkingVariableMtrrCount
,
2507 VariableSettingModified
2513 // 3. Apply the below-1MB memory attribute settings.
2515 // (Value & ~0 | 0) still equals to (Value)
2517 ZeroMem (ClearMasks
, sizeof (ClearMasks
));
2518 ZeroMem (OrMasks
, sizeof (OrMasks
));
2519 for (Index
= 0; Index
< RangeCount
; Index
++) {
2520 if (Ranges
[Index
].BaseAddress
>= BASE_1MB
) {
2524 Status
= MtrrLibSetBelow1MBMemoryAttribute (
2527 Ranges
[Index
].BaseAddress
,
2528 Ranges
[Index
].Length
,
2531 if (RETURN_ERROR (Status
)) {
2536 MtrrContextValid
= FALSE
;
2538 // 4. Write fixed MTRRs that have been modified
2540 for (Index
= 0; Index
< ARRAY_SIZE (ClearMasks
); Index
++) {
2541 if (ClearMasks
[Index
] != 0) {
2542 if (MtrrSetting
!= NULL
) {
2543 MtrrSetting
->Fixed
.Mtrr
[Index
] = (MtrrSetting
->Fixed
.Mtrr
[Index
] & ~ClearMasks
[Index
]) | OrMasks
[Index
];
2545 if (!MtrrContextValid
) {
2546 MtrrLibPreMtrrChange (&MtrrContext
);
2547 MtrrContextValid
= TRUE
;
2550 AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
, ~ClearMasks
[Index
], OrMasks
[Index
]);
2556 // 5. Write variable MTRRs that have been modified
2558 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2559 if (VariableSettingModified
[Index
]) {
2560 if (OriginalVariableMtrr
[Index
].Length
!= 0) {
2561 VariableSetting
.Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
)
2562 | (UINT8
)OriginalVariableMtrr
[Index
].Type
;
2563 VariableSetting
.Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2565 VariableSetting
.Base
= 0;
2566 VariableSetting
.Mask
= 0;
2569 if (MtrrSetting
!= NULL
) {
2570 CopyMem (&MtrrSetting
->Variables
.Mtrr
[Index
], &VariableSetting
, sizeof (VariableSetting
));
2572 if (!MtrrContextValid
) {
2573 MtrrLibPreMtrrChange (&MtrrContext
);
2574 MtrrContextValid
= TRUE
;
2578 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2579 VariableSetting
.Base
2582 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2583 VariableSetting
.Mask
2589 if (MtrrSetting
!= NULL
) {
2590 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2591 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
2593 if (MtrrContextValid
) {
2594 MtrrLibPostMtrrChange (&MtrrContext
);
2599 DEBUG ((DEBUG_CACHE
, " Result = %r\n", Status
));
2600 if (!RETURN_ERROR (Status
)) {
2601 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2608 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2610 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2611 @param[in] BaseAddress The physical address that is the start address
2613 @param[in] Length The size in bytes of the memory range.
2614 @param[in] Attribute The bit mask of attributes to set for the
2617 @retval RETURN_SUCCESS The attributes were set for the memory range.
2618 @retval RETURN_INVALID_PARAMETER Length is zero.
2619 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2620 memory resource range specified by BaseAddress and Length.
2621 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2622 range specified by BaseAddress and Length.
2623 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2624 BaseAddress and Length cannot be modified.
2625 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2626 the memory resource range.
2627 Multiple memory range attributes setting by calling this API multiple
2628 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2629 the number of CPU MTRRs are too small to set such memory attributes.
2630 Pass the multiple memory range attributes to one call of
2631 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2632 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2633 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2634 external scratch buffer.
2638 MtrrSetMemoryAttributeInMtrrSettings (
2639 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2640 IN PHYSICAL_ADDRESS BaseAddress
,
2642 IN MTRR_MEMORY_CACHE_TYPE Attribute
2645 UINT8 Scratch
[SCRATCH_BUFFER_SIZE
];
2647 MTRR_MEMORY_RANGE Range
;
2649 Range
.BaseAddress
= BaseAddress
;
2650 Range
.Length
= Length
;
2651 Range
.Type
= Attribute
;
2652 ScratchSize
= sizeof (Scratch
);
2653 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting
, Scratch
, &ScratchSize
, &Range
, 1);
2657 This function attempts to set the attributes for a memory range.
2659 @param[in] BaseAddress The physical address that is the start
2660 address of a memory range.
2661 @param[in] Length The size in bytes of the memory range.
2662 @param[in] Attributes The bit mask of attributes to set for the
2665 @retval RETURN_SUCCESS The attributes were set for the memory
2667 @retval RETURN_INVALID_PARAMETER Length is zero.
2668 @retval RETURN_UNSUPPORTED The processor does not support one or
2669 more bytes of the memory resource range
2670 specified by BaseAddress and Length.
2671 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2672 for the memory resource range specified
2673 by BaseAddress and Length.
2674 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2675 range specified by BaseAddress and Length
2677 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2678 modify the attributes of the memory
2680 Multiple memory range attributes setting by calling this API multiple
2681 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2682 the number of CPU MTRRs are too small to set such memory attributes.
2683 Pass the multiple memory range attributes to one call of
2684 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2685 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2686 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2687 external scratch buffer.
2691 MtrrSetMemoryAttribute (
2692 IN PHYSICAL_ADDRESS BaseAddress
,
2694 IN MTRR_MEMORY_CACHE_TYPE Attribute
2697 return MtrrSetMemoryAttributeInMtrrSettings (NULL
, BaseAddress
, Length
, Attribute
);
2701 Worker function setting variable MTRRs
2703 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2707 MtrrSetVariableMtrrWorker (
2708 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2712 UINT32 VariableMtrrCount
;
2714 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2715 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
2717 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2719 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2720 VariableSettings
->Mtrr
[Index
].Base
2723 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2724 VariableSettings
->Mtrr
[Index
].Mask
2730 Worker function setting fixed MTRRs
2732 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2736 MtrrSetFixedMtrrWorker (
2737 IN MTRR_FIXED_SETTINGS
*FixedSettings
2742 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2744 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2745 FixedSettings
->Mtrr
[Index
]
2751 This function gets the content in all MTRRs (variable and fixed)
2753 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2755 @retval the pointer of MtrrSetting
2761 OUT MTRR_SETTINGS
*MtrrSetting
2764 if (!IsMtrrSupported ()) {
2771 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2774 // Get variable MTRRs
2776 MtrrGetVariableMtrrWorker (
2778 GetVariableMtrrCountWorker (),
2779 &MtrrSetting
->Variables
2783 // Get MTRR_DEF_TYPE value
2785 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2791 This function sets all MTRRs (variable and fixed)
2793 @param[in] MtrrSetting A buffer holding all MTRRs content.
2795 @retval The pointer of MtrrSetting
2801 IN MTRR_SETTINGS
*MtrrSetting
2804 MTRR_CONTEXT MtrrContext
;
2806 if (!IsMtrrSupported ()) {
2810 MtrrLibPreMtrrChange (&MtrrContext
);
2815 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2818 // Set variable MTRRs
2820 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2823 // Set MTRR_DEF_TYPE value
2825 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2827 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2833 Checks if MTRR is supported.
2835 @retval TRUE MTRR is supported.
2836 @retval FALSE MTRR is not supported.
2845 CPUID_VERSION_INFO_EDX Edx
;
2846 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2849 // Check CPUID(1).EDX[12] for MTRR capability
2851 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2852 if (Edx
.Bits
.MTRR
== 0) {
2857 // Check number of variable MTRRs and fixed MTRRs existence.
2858 // If number of variable MTRRs is zero, or fixed MTRRs do not
2859 // exist, return false.
2861 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2862 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {
2870 Worker function prints all MTRRs for debugging.
2872 If MtrrSetting is not NULL, print MTRR settings from input MTRR
2874 If MtrrSetting is NULL, print MTRR settings from MTRRs.
2876 @param MtrrSetting A buffer holding all MTRRs content.
2879 MtrrDebugPrintAllMtrrsWorker (
2880 IN MTRR_SETTINGS
*MtrrSetting
2883 DEBUG_CODE_BEGIN ();
2884 MTRR_SETTINGS LocalMtrrs
;
2885 MTRR_SETTINGS
*Mtrrs
;
2888 UINT64 MtrrValidBitsMask
;
2889 UINT64 MtrrValidAddressMask
;
2890 UINT32 VariableMtrrCount
;
2891 BOOLEAN ContainVariableMtrr
;
2892 MTRR_MEMORY_RANGE Ranges
[
2893 ARRAY_SIZE (mMtrrLibFixedMtrrTable
) * sizeof (UINT64
) + 2 * ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
) + 1
2895 MTRR_MEMORY_RANGE RawVariableRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
2897 if (!IsMtrrSupported ()) {
2901 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2903 if (MtrrSetting
!= NULL
) {
2904 Mtrrs
= MtrrSetting
;
2906 MtrrGetAllMtrrs (&LocalMtrrs
);
2907 Mtrrs
= &LocalMtrrs
;
2911 // Dump RAW MTRR contents
2913 DEBUG ((DEBUG_CACHE
, "MTRR Settings:\n"));
2914 DEBUG ((DEBUG_CACHE
, "=============\n"));
2915 DEBUG ((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
2916 for (Index
= 0; Index
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); Index
++) {
2917 DEBUG ((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
2920 ContainVariableMtrr
= FALSE
;
2921 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2922 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
2924 // If mask is not valid, then do not display range
2929 ContainVariableMtrr
= TRUE
;
2932 "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2934 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
2935 Mtrrs
->Variables
.Mtrr
[Index
].Mask
2939 if (!ContainVariableMtrr
) {
2940 DEBUG ((DEBUG_CACHE
, "Variable MTRR : None.\n"));
2943 DEBUG ((DEBUG_CACHE
, "\n"));
2946 // Dump MTRR setting in ranges
2948 DEBUG ((DEBUG_CACHE
, "Memory Ranges:\n"));
2949 DEBUG ((DEBUG_CACHE
, "====================================\n"));
2950 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2951 Ranges
[0].BaseAddress
= 0;
2952 Ranges
[0].Length
= MtrrValidBitsMask
+ 1;
2953 Ranges
[0].Type
= MtrrGetDefaultMemoryTypeWorker (Mtrrs
);
2956 MtrrLibGetRawVariableRanges (
2960 MtrrValidAddressMask
,
2963 MtrrLibApplyVariableMtrrs (
2967 ARRAY_SIZE (Ranges
),
2971 MtrrLibApplyFixedMtrrs (&Mtrrs
->Fixed
, Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
);
2973 for (Index
= 0; Index
< RangeCount
; Index
++) {
2976 "%a:%016lx-%016lx\n",
2977 mMtrrMemoryCacheTypeShortName
[Ranges
[Index
].Type
],
2978 Ranges
[Index
].BaseAddress
,
2979 Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- 1
2987 This function prints all MTRRs for debugging.
2991 MtrrDebugPrintAllMtrrs (
2995 MtrrDebugPrintAllMtrrsWorker (NULL
);