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
131 Worker function prints all MTRRs for debugging.
133 If MtrrSetting is not NULL, print MTRR settings from input MTRR
135 If MtrrSetting is NULL, print MTRR settings from MTRRs.
137 @param MtrrSetting A buffer holding all MTRRs content.
140 MtrrDebugPrintAllMtrrsWorker (
141 IN MTRR_SETTINGS
*MtrrSetting
145 Worker function returns the variable MTRR count for the CPU.
147 @return Variable MTRR count
151 GetVariableMtrrCountWorker (
155 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
157 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
158 ASSERT (MtrrCap
.Bits
.VCNT
<= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS
*) 0)->Mtrr
));
159 return MtrrCap
.Bits
.VCNT
;
163 Returns the variable MTRR count for the CPU.
165 @return Variable MTRR count
170 GetVariableMtrrCount (
174 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 ()) {
218 return GetFirmwareVariableMtrrCountWorker ();
222 Worker function returns the default MTRR cache type for the system.
224 If MtrrSetting is not NULL, returns the default MTRR cache type from input
225 MTRR settings buffer.
226 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
228 @param[in] MtrrSetting A buffer holding all MTRRs content.
230 @return The default MTRR cache type.
233 MTRR_MEMORY_CACHE_TYPE
234 MtrrGetDefaultMemoryTypeWorker (
235 IN MTRR_SETTINGS
*MtrrSetting
238 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
240 if (MtrrSetting
== NULL
) {
241 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
243 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
246 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
;
265 return MtrrGetDefaultMemoryTypeWorker (NULL
);
269 Preparation before programming MTRR.
271 This function will do some preparation for programming MTRRs:
272 disable cache, invalid cache and disable MTRR caching functionality
274 @param[out] MtrrContext Pointer to context to save
278 MtrrLibPreMtrrChange (
279 OUT MTRR_CONTEXT
*MtrrContext
282 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
284 // Disable interrupts and save current interrupt state
286 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
289 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
294 // Save original CR4 value and clear PGE flag (Bit 7)
296 MtrrContext
->Cr4
= AsmReadCr4 ();
297 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
307 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
309 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
313 Cleaning up after programming MTRRs.
315 This function will do some clean up after programming MTRRs:
316 Flush all TLBs, re-enable caching, restore CR4.
318 @param[in] MtrrContext Pointer to context to restore
322 MtrrLibPostMtrrChangeEnableCache (
323 IN MTRR_CONTEXT
*MtrrContext
332 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
337 // Restore original CR4 value
339 AsmWriteCr4 (MtrrContext
->Cr4
);
342 // Restore original interrupt state
344 SetInterruptState (MtrrContext
->InterruptState
);
348 Cleaning up after programming MTRRs.
350 This function will do some clean up after programming MTRRs:
351 enable MTRR caching functionality, and enable cache
353 @param[in] MtrrContext Pointer to context to restore
357 MtrrLibPostMtrrChange (
358 IN MTRR_CONTEXT
*MtrrContext
361 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
365 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
368 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
370 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
374 Worker function gets the content in fixed MTRRs
376 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
378 @retval The pointer of FixedSettings
382 MtrrGetFixedMtrrWorker (
383 OUT MTRR_FIXED_SETTINGS
*FixedSettings
388 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
389 FixedSettings
->Mtrr
[Index
] =
390 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
393 return FixedSettings
;
398 This function gets the content in fixed MTRRs
400 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
402 @retval The pointer of FixedSettings
408 OUT MTRR_FIXED_SETTINGS
*FixedSettings
411 if (!IsMtrrSupported ()) {
412 return FixedSettings
;
415 return MtrrGetFixedMtrrWorker (FixedSettings
);
420 Worker function will get the raw value in variable MTRRs
422 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
423 MTRR settings buffer.
424 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
426 @param[in] MtrrSetting A buffer holding all MTRRs content.
427 @param[in] VariableMtrrCount Number of variable MTRRs.
428 @param[out] VariableSettings A buffer to hold variable MTRRs content.
430 @return The VariableSettings input pointer
433 MTRR_VARIABLE_SETTINGS
*
434 MtrrGetVariableMtrrWorker (
435 IN MTRR_SETTINGS
*MtrrSetting
,
436 IN UINT32 VariableMtrrCount
,
437 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
442 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
444 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
445 if (MtrrSetting
== NULL
) {
446 VariableSettings
->Mtrr
[Index
].Base
=
447 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1));
448 VariableSettings
->Mtrr
[Index
].Mask
=
449 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1));
451 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
452 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
456 return VariableSettings
;
460 Programs fixed MTRRs registers.
462 @param[in] Type The memory type to set.
463 @param[in, out] Base The base address of memory range.
464 @param[in, out] Length The length of memory range.
465 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
466 On return, the current index of the fixed MTRR MSR to program.
467 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
468 @param[out] OrMask The bits to set in the fixed MTRR MSR.
470 @retval RETURN_SUCCESS The cache type was updated successfully
471 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
476 MtrrLibProgramFixedMtrr (
477 IN MTRR_MEMORY_CACHE_TYPE Type
,
479 IN OUT UINT64
*Length
,
480 IN OUT UINT32
*LastMsrIndex
,
481 OUT UINT64
*ClearMask
,
486 UINT32 LeftByteShift
;
487 UINT32 RightByteShift
;
491 // Find the fixed MTRR index to be programmed
493 for (MsrIndex
= *LastMsrIndex
+ 1; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
494 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) &&
497 mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
+
498 (8 * mMtrrLibFixedMtrrTable
[MsrIndex
].Length
)
506 ASSERT (MsrIndex
!= ARRAY_SIZE (mMtrrLibFixedMtrrTable
));
509 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
511 if ((((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
513 // Base address should be aligned to the begin of a certain Fixed MTRR range.
515 return RETURN_UNSUPPORTED
;
517 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
518 ASSERT (LeftByteShift
< 8);
521 // Find the end offset in fixed MTRR and calculate byte offset of right shift
523 SubLength
= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
* (8 - LeftByteShift
);
524 if (*Length
>= SubLength
) {
527 if (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
529 // Length should be aligned to the end of a certain Fixed MTRR range.
531 return RETURN_UNSUPPORTED
;
533 RightByteShift
= 8 - LeftByteShift
- (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
535 // Update SubLength by actual length
540 *ClearMask
= CLEAR_SEED
;
541 *OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
543 if (LeftByteShift
!= 0) {
545 // Clear the low bits by LeftByteShift
547 *ClearMask
&= LShiftU64 (*ClearMask
, LeftByteShift
* 8);
548 *OrMask
&= LShiftU64 (*OrMask
, LeftByteShift
* 8);
551 if (RightByteShift
!= 0) {
553 // Clear the high bits by RightByteShift
555 *ClearMask
&= RShiftU64 (*ClearMask
, RightByteShift
* 8);
556 *OrMask
&= RShiftU64 (*OrMask
, RightByteShift
* 8);
559 *Length
-= SubLength
;
562 *LastMsrIndex
= MsrIndex
;
564 return RETURN_SUCCESS
;
569 Worker function gets the attribute of variable MTRRs.
571 This function shadows the content of variable MTRRs into an
572 internal array: VariableMtrr.
574 @param[in] VariableSettings The variable MTRR values to shadow
575 @param[in] VariableMtrrCount The number of variable MTRRs
576 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
577 @param[in] MtrrValidAddressMask The valid address mask for MTRR
578 @param[out] VariableMtrr The array to shadow variable MTRRs content
580 @return Number of MTRRs which has been used.
584 MtrrGetMemoryAttributeInVariableMtrrWorker (
585 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
586 IN UINTN VariableMtrrCount
,
587 IN UINT64 MtrrValidBitsMask
,
588 IN UINT64 MtrrValidAddressMask
,
589 OUT VARIABLE_MTRR
*VariableMtrr
595 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
596 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
597 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
598 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
599 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
600 VariableMtrr
[Index
].Length
=
601 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
602 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
603 VariableMtrr
[Index
].Valid
= TRUE
;
604 VariableMtrr
[Index
].Used
= TRUE
;
612 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
613 One MTRR_MEMORY_RANGE element is created for each MTRR setting.
614 The routine doesn't remove the overlap or combine the near-by region.
616 @param[in] VariableSettings The variable MTRR values to shadow
617 @param[in] VariableMtrrCount The number of variable MTRRs
618 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
619 @param[in] MtrrValidAddressMask The valid address mask for MTRR
620 @param[out] VariableMtrr The array to shadow variable MTRRs content
622 @return Number of MTRRs which has been used.
626 MtrrLibGetRawVariableRanges (
627 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
628 IN UINTN VariableMtrrCount
,
629 IN UINT64 MtrrValidBitsMask
,
630 IN UINT64 MtrrValidAddressMask
,
631 OUT MTRR_MEMORY_RANGE
*VariableMtrr
637 ZeroMem (VariableMtrr
, sizeof (MTRR_MEMORY_RANGE
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
638 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
639 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
640 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
641 VariableMtrr
[Index
].Length
=
642 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
643 VariableMtrr
[Index
].Type
= (MTRR_MEMORY_CACHE_TYPE
)(VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
651 Gets the attribute of variable MTRRs.
653 This function shadows the content of variable MTRRs into an
654 internal array: VariableMtrr.
656 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
657 @param[in] MtrrValidAddressMask The valid address mask for MTRR
658 @param[out] VariableMtrr The array to shadow variable MTRRs content
660 @return The return value of this parameter indicates the
661 number of MTRRs which has been used.
666 MtrrGetMemoryAttributeInVariableMtrr (
667 IN UINT64 MtrrValidBitsMask
,
668 IN UINT64 MtrrValidAddressMask
,
669 OUT VARIABLE_MTRR
*VariableMtrr
672 MTRR_VARIABLE_SETTINGS VariableSettings
;
674 if (!IsMtrrSupported ()) {
678 MtrrGetVariableMtrrWorker (
680 GetVariableMtrrCountWorker (),
684 return MtrrGetMemoryAttributeInVariableMtrrWorker (
686 GetFirmwareVariableMtrrCountWorker (),
688 MtrrValidAddressMask
,
694 Return the biggest alignment (lowest set bit) of address.
695 The function is equivalent to: 1 << LowBitSet64 (Address).
697 @param Address The address to return the alignment.
698 @param Alignment0 The alignment to return when Address is 0.
700 @return The least alignment of the Address.
703 MtrrLibBiggestAlignment (
712 return Address
& ((~Address
) + 1);
716 Return whether the left MTRR type precedes the right MTRR type.
718 The MTRR type precedence rules are:
719 1. UC precedes any other type
721 For further details, please refer the IA32 Software Developer's Manual,
722 Volume 3, Section "MTRR Precedences".
724 @param Left The left MTRR type.
725 @param Right The right MTRR type.
727 @retval TRUE Left precedes Right.
728 @retval FALSE Left doesn't precede Right.
731 MtrrLibTypeLeftPrecedeRight (
732 IN MTRR_MEMORY_CACHE_TYPE Left
,
733 IN MTRR_MEMORY_CACHE_TYPE Right
736 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
740 Initializes the valid bits mask and valid address mask for MTRRs.
742 This function initializes the valid bits mask and valid address mask for MTRRs.
744 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
745 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
749 MtrrLibInitializeMtrrMask (
750 OUT UINT64
*MtrrValidBitsMask
,
751 OUT UINT64
*MtrrValidAddressMask
754 UINT32 MaxExtendedFunction
;
755 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
758 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
760 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
761 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
763 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
766 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
767 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
772 Determines the real attribute of a memory range.
774 This function is to arbitrate the real attribute of the memory when
775 there are 2 MTRRs covers the same memory range. For further details,
776 please refer the IA32 Software Developer's Manual, Volume 3,
777 Section "MTRR Precedences".
779 @param[in] MtrrType1 The first kind of Memory type
780 @param[in] MtrrType2 The second kind of memory type
783 MTRR_MEMORY_CACHE_TYPE
785 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
786 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
789 if (MtrrType1
== MtrrType2
) {
794 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
795 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
798 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
806 Worker function will get the memory cache type of the specific address.
808 If MtrrSetting is not NULL, gets the memory cache type from input
809 MTRR settings buffer.
810 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
812 @param[in] MtrrSetting A buffer holding all MTRRs content.
813 @param[in] Address The specific address
815 @return Memory cache type of the specific address
818 MTRR_MEMORY_CACHE_TYPE
819 MtrrGetMemoryAttributeByAddressWorker (
820 IN MTRR_SETTINGS
*MtrrSetting
,
821 IN PHYSICAL_ADDRESS Address
824 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
828 MTRR_MEMORY_CACHE_TYPE MtrrType
;
829 MTRR_MEMORY_RANGE VariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
830 UINT64 MtrrValidBitsMask
;
831 UINT64 MtrrValidAddressMask
;
832 UINT32 VariableMtrrCount
;
833 MTRR_VARIABLE_SETTINGS VariableSettings
;
836 // Check if MTRR is enabled, if not, return UC as attribute
838 if (MtrrSetting
== NULL
) {
839 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
841 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
844 if (DefType
.Bits
.E
== 0) {
845 return CacheUncacheable
;
849 // If address is less than 1M, then try to go through the fixed MTRR
851 if (Address
< BASE_1MB
) {
852 if (DefType
.Bits
.FE
!= 0) {
854 // Go through the fixed MTRR
856 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
857 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
858 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
859 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
861 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
862 mMtrrLibFixedMtrrTable
[Index
].Length
;
863 if (MtrrSetting
== NULL
) {
864 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
866 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
868 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
874 VariableMtrrCount
= GetVariableMtrrCountWorker ();
875 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
));
876 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
878 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
879 MtrrLibGetRawVariableRanges (
883 MtrrValidAddressMask
,
888 // Go through the variable MTRR
890 MtrrType
= CacheInvalid
;
891 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
892 if (VariableMtrr
[Index
].Length
!= 0) {
893 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
894 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
895 if (MtrrType
== CacheInvalid
) {
896 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
898 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
905 // If there is no MTRR which covers the Address, use the default MTRR type.
907 if (MtrrType
== CacheInvalid
) {
908 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
916 This function will get the memory cache type of the specific address.
918 This function is mainly for debug purpose.
920 @param[in] Address The specific address
922 @return Memory cache type of the specific address
925 MTRR_MEMORY_CACHE_TYPE
927 MtrrGetMemoryAttribute (
928 IN PHYSICAL_ADDRESS Address
931 if (!IsMtrrSupported ()) {
932 return CacheUncacheable
;
935 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
939 Update the Ranges array to change the specified range identified by
940 BaseAddress and Length to Type.
942 @param Ranges Array holding memory type settings for all memory regions.
943 @param Capacity The maximum count of memory ranges the array can hold.
944 @param Count Return the new memory range count in the array.
945 @param BaseAddress The base address of the memory range to change type.
946 @param Length The length of the memory range to change type.
947 @param Type The new type of the specified memory range.
949 @retval RETURN_SUCCESS The type of the specified memory range is
950 changed successfully.
951 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
953 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
954 range exceeds capacity.
957 MtrrLibSetMemoryType (
958 IN MTRR_MEMORY_RANGE
*Ranges
,
961 IN UINT64 BaseAddress
,
963 IN MTRR_MEMORY_CACHE_TYPE Type
976 Limit
= BaseAddress
+ Length
;
979 for (Index
= 0; Index
< *Count
; Index
++) {
980 if ((StartIndex
== *Count
) &&
981 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
982 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
984 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
987 if ((EndIndex
== *Count
) &&
988 (Ranges
[Index
].BaseAddress
< Limit
) &&
989 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
991 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
996 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
997 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
998 return RETURN_ALREADY_STARTED
;
1002 // The type change may cause merging with previous range or next range.
1003 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1004 // logic doesn't need to consider merging.
1006 if (StartIndex
!= 0) {
1007 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1009 Length
+= Ranges
[StartIndex
].Length
;
1010 BaseAddress
-= Ranges
[StartIndex
].Length
;
1013 if (EndIndex
!= (*Count
) - 1) {
1014 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1016 Length
+= Ranges
[EndIndex
].Length
;
1021 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1022 // |++++++++++++++++++| 0 3 1=3-0-2 3
1023 // |+++++++| 0 1 -1=1-0-2 5
1024 // |+| 0 0 -2=0-0-2 6
1025 // |+++| 0 0 -1=0-0-2+1 5
1028 DeltaCount
= EndIndex
- StartIndex
- 2;
1029 if (LengthLeft
== 0) {
1032 if (LengthRight
== 0) {
1035 if (*Count
- DeltaCount
> Capacity
) {
1036 return RETURN_OUT_OF_RESOURCES
;
1040 // Reserve (-DeltaCount) space
1042 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1043 *Count
-= DeltaCount
;
1045 if (LengthLeft
!= 0) {
1046 Ranges
[StartIndex
].Length
= LengthLeft
;
1049 if (LengthRight
!= 0) {
1050 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1051 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1052 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1054 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1055 Ranges
[StartIndex
].Length
= Length
;
1056 Ranges
[StartIndex
].Type
= Type
;
1057 return RETURN_SUCCESS
;
1061 Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1063 @param Ranges Array holding memory type settings for all memory regions.
1064 @param RangeCount The count of memory ranges the array holds.
1065 @param BaseAddress Base address.
1066 @param Length Length.
1067 @param Types Return bit mask to indicate all memory types in the specified range.
1069 @retval Number of memory types.
1072 MtrrLibGetNumberOfTypes (
1073 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1074 IN UINTN RangeCount
,
1075 IN UINT64 BaseAddress
,
1077 IN OUT UINT8
*Types OPTIONAL
1086 for (Index
= 0; Index
< RangeCount
; Index
++) {
1087 if ((Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1088 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)
1090 if ((LocalTypes
& (1 << Ranges
[Index
].Type
)) == 0) {
1091 LocalTypes
|= (UINT8
)(1 << Ranges
[Index
].Type
);
1095 if (BaseAddress
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1096 Length
-= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1097 BaseAddress
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
;
1104 if (Types
!= NULL
) {
1105 *Types
= LocalTypes
;
1111 Calculate the least MTRR number from vertex Start to Stop and update
1112 the Previous of all vertices from Start to Stop is updated to reflect
1113 how the memory range is covered by MTRR.
1115 @param VertexCount The count of vertices in the graph.
1116 @param Vertices Array holding all vertices.
1117 @param Weight 2-dimention array holding weights between vertices.
1118 @param Start Start vertex.
1119 @param Stop Stop vertex.
1120 @param IncludeOptional TRUE to count the optional weight.
1123 MtrrLibCalculateLeastMtrrs (
1124 IN UINT16 VertexCount
,
1125 IN MTRR_LIB_ADDRESS
*Vertices
,
1126 IN OUT CONST UINT8
*Weight
,
1129 IN BOOLEAN IncludeOptional
1138 for (Index
= Start
; Index
<= Stop
; Index
++) {
1139 Vertices
[Index
].Visited
= FALSE
;
1140 Mandatory
= Weight
[M(Start
,Index
)];
1141 Vertices
[Index
].Weight
= Mandatory
;
1142 if (Mandatory
!= MAX_WEIGHT
) {
1143 Optional
= IncludeOptional
? Weight
[O(Start
, Index
)] : 0;
1144 Vertices
[Index
].Weight
+= Optional
;
1145 ASSERT (Vertices
[Index
].Weight
>= Optional
);
1151 while (!Vertices
[Stop
].Visited
) {
1153 // Update the weight from the shortest vertex to other unvisited vertices
1155 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1156 if (!Vertices
[Index
].Visited
) {
1157 Mandatory
= Weight
[M(MinI
, Index
)];
1158 if (Mandatory
!= MAX_WEIGHT
) {
1159 Optional
= IncludeOptional
? Weight
[O(MinI
, Index
)] : 0;
1160 if (MinWeight
+ Mandatory
+ Optional
<= Vertices
[Index
].Weight
) {
1161 Vertices
[Index
].Weight
= MinWeight
+ Mandatory
+ Optional
;
1162 Vertices
[Index
].Previous
= MinI
; // Previous is Start based.
1169 // Find the shortest vertex from Start
1172 MinWeight
= MAX_WEIGHT
;
1173 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1174 if (!Vertices
[Index
].Visited
&& MinWeight
> Vertices
[Index
].Weight
) {
1176 MinWeight
= Vertices
[Index
].Weight
;
1181 // Mark the shortest vertex from Start as visited
1183 Vertices
[MinI
].Visited
= TRUE
;
1188 Append the MTRR setting to MTRR setting array.
1190 @param Mtrrs Array holding all MTRR settings.
1191 @param MtrrCapacity Capacity of the MTRR array.
1192 @param MtrrCount The count of MTRR settings in array.
1193 @param BaseAddress Base address.
1194 @param Length Length.
1195 @param Type Memory type.
1197 @retval RETURN_SUCCESS MTRR setting is appended to array.
1198 @retval RETURN_OUT_OF_RESOURCES Array is full.
1201 MtrrLibAppendVariableMtrr (
1202 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1203 IN UINT32 MtrrCapacity
,
1204 IN OUT UINT32
*MtrrCount
,
1205 IN UINT64 BaseAddress
,
1207 IN MTRR_MEMORY_CACHE_TYPE Type
1210 if (*MtrrCount
== MtrrCapacity
) {
1211 return RETURN_OUT_OF_RESOURCES
;
1214 Mtrrs
[*MtrrCount
].BaseAddress
= BaseAddress
;
1215 Mtrrs
[*MtrrCount
].Length
= Length
;
1216 Mtrrs
[*MtrrCount
].Type
= Type
;
1218 return RETURN_SUCCESS
;
1222 Return the memory type that has the least precedence.
1224 @param TypeBits Bit mask of memory type.
1226 @retval Memory type that has the least precedence.
1228 MTRR_MEMORY_CACHE_TYPE
1235 ASSERT (TypeBits
!= 0);
1236 for (Type
= 7; (INT8
)TypeBits
> 0; Type
--, TypeBits
<<= 1);
1237 return (MTRR_MEMORY_CACHE_TYPE
)Type
;
1241 Return TRUE when the Operand is exactly power of 2.
1243 @retval TRUE Operand is exactly power of 2.
1244 @retval FALSE Operand is not power of 2.
1247 MtrrLibIsPowerOfTwo (
1251 ASSERT (Operand
!= 0);
1252 return (BOOLEAN
) ((Operand
& (Operand
- 1)) == 0);
1256 Calculate the subtractive path from vertex Start to Stop.
1258 @param DefaultType Default memory type.
1259 @param A0 Alignment to use when base address is 0.
1260 @param Ranges Array holding memory type settings for all memory regions.
1261 @param RangeCount The count of memory ranges the array holds.
1262 @param VertexCount The count of vertices in the graph.
1263 @param Vertices Array holding all vertices.
1264 @param Weight 2-dimention array holding weights between vertices.
1265 @param Start Start vertex.
1266 @param Stop Stop vertex.
1267 @param Types Type bit mask of memory range from Start to Stop.
1268 @param TypeCount Number of different memory types from Start to Stop.
1269 @param Mtrrs Array holding all MTRR settings.
1270 @param MtrrCapacity Capacity of the MTRR array.
1271 @param MtrrCount The count of MTRR settings in array.
1273 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1274 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1278 MtrrLibCalculateSubtractivePath (
1279 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1281 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1282 IN UINTN RangeCount
,
1283 IN UINT16 VertexCount
,
1284 IN MTRR_LIB_ADDRESS
*Vertices
,
1285 IN OUT UINT8
*Weight
,
1290 IN OUT MTRR_MEMORY_RANGE
*Mtrrs OPTIONAL
,
1291 IN UINT32 MtrrCapacity OPTIONAL
,
1292 IN OUT UINT32
*MtrrCount OPTIONAL
1295 RETURN_STATUS Status
;
1298 UINT8 PrecedentTypes
;
1307 MTRR_MEMORY_CACHE_TYPE LowestType
;
1308 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType
;
1310 Base
= Vertices
[Start
].Address
;
1311 Length
= Vertices
[Stop
].Address
- Base
;
1313 LowestType
= MtrrLibLowestType (Types
);
1316 // Clear the lowest type (highest bit) to get the precedent types
1318 PrecedentTypes
= ~(1 << LowestType
) & Types
;
1319 LowestPrecedentType
= MtrrLibLowestType (PrecedentTypes
);
1321 if (Mtrrs
== NULL
) {
1322 Weight
[M(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 0 : 1);
1323 Weight
[O(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 1 : 0);
1326 // Add all high level ranges
1329 for (Index
= 0; Index
< RangeCount
; Index
++) {
1333 if ((Base
< Ranges
[Index
].BaseAddress
) || (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
<= Base
)) {
1338 // Base is in the Range[Index]
1340 if (Base
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1341 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Base
;
1345 if (((1 << Ranges
[Index
].Type
) & PrecedentTypes
) != 0) {
1347 // Meet a range whose types take precedence.
1348 // Update the [HBase, HBase + HLength) to include the range,
1349 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1351 if (HBase
== MAX_UINT64
) {
1354 HLength
+= SubLength
;
1358 Length
-= SubLength
;
1364 if ((Ranges
[Index
].Type
== LowestType
) || (Length
== 0)) { // meet low type or end
1367 // Add the MTRRs for each high priority type range
1368 // the range[HBase, HBase + HLength) contains only two types.
1369 // We might use positive or subtractive, depending on which way uses less MTRR
1371 for (SubStart
= Start
; SubStart
<= Stop
; SubStart
++) {
1372 if (Vertices
[SubStart
].Address
== HBase
) {
1377 for (SubStop
= SubStart
; SubStop
<= Stop
; SubStop
++) {
1378 if (Vertices
[SubStop
].Address
== HBase
+ HLength
) {
1382 ASSERT (Vertices
[SubStart
].Address
== HBase
);
1383 ASSERT (Vertices
[SubStop
].Address
== HBase
+ HLength
);
1385 if ((TypeCount
== 2) || (SubStart
== SubStop
- 1)) {
1387 // add subtractive MTRRs for [HBase, HBase + HLength)
1388 // [HBase, HBase + HLength) contains only one type.
1389 // while - loop is to split the range to MTRR - compliant aligned range.
1391 if (Mtrrs
== NULL
) {
1392 Weight
[M (Start
, Stop
)] += (UINT8
)(SubStop
- SubStart
);
1394 while (SubStart
!= SubStop
) {
1395 Status
= MtrrLibAppendVariableMtrr (
1396 Mtrrs
, MtrrCapacity
, MtrrCount
,
1397 Vertices
[SubStart
].Address
, Vertices
[SubStart
].Length
, Vertices
[SubStart
].Type
1399 if (RETURN_ERROR (Status
)) {
1406 ASSERT (TypeCount
== 3);
1407 MtrrLibCalculateLeastMtrrs (VertexCount
, Vertices
, Weight
, SubStart
, SubStop
, TRUE
);
1409 if (Mtrrs
== NULL
) {
1410 Weight
[M (Start
, Stop
)] += Vertices
[SubStop
].Weight
;
1412 // When we need to collect the optimal path from SubStart to SubStop
1413 while (SubStop
!= SubStart
) {
1415 Pre
= Vertices
[Cur
].Previous
;
1418 if (Weight
[M (Pre
, Cur
)] + Weight
[O (Pre
, Cur
)] != 0) {
1419 Status
= MtrrLibAppendVariableMtrr (
1420 Mtrrs
, MtrrCapacity
, MtrrCount
,
1421 Vertices
[Pre
].Address
, Vertices
[Cur
].Address
- Vertices
[Pre
].Address
,
1422 (Pre
!= Cur
- 1) ? LowestPrecedentType
: Vertices
[Pre
].Type
1424 if (RETURN_ERROR (Status
)) {
1428 if (Pre
!= Cur
- 1) {
1429 Status
= MtrrLibCalculateSubtractivePath (
1432 VertexCount
, Vertices
, Weight
,
1433 Pre
, Cur
, PrecedentTypes
, 2,
1434 Mtrrs
, MtrrCapacity
, MtrrCount
1436 if (RETURN_ERROR (Status
)) {
1445 // Reset HBase, HLength
1451 return RETURN_SUCCESS
;
1455 Calculate MTRR settings to cover the specified memory ranges.
1457 @param DefaultType Default memory type.
1458 @param A0 Alignment to use when base address is 0.
1459 @param Ranges Memory range array holding the memory type
1460 settings for all memory address.
1461 @param RangeCount Count of memory ranges.
1462 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1463 This is an optional parameter that may be NULL.
1464 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1465 It may be updated to the actual required size when the calculation
1466 needs more scratch buffer.
1467 @param Mtrrs Array holding all MTRR settings.
1468 @param MtrrCapacity Capacity of the MTRR array.
1469 @param MtrrCount The count of MTRR settings in array.
1471 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1472 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1473 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1476 MtrrLibCalculateMtrrs (
1477 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1479 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1480 IN UINTN RangeCount
,
1482 IN OUT UINTN
*ScratchSize
,
1483 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1484 IN UINT32 MtrrCapacity
,
1485 IN OUT UINT32
*MtrrCount
1495 MTRR_LIB_ADDRESS
*Vertices
;
1499 UINTN RequiredScratchSize
;
1504 RETURN_STATUS Status
;
1506 Base0
= Ranges
[0].BaseAddress
;
1507 Base1
= Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
;
1508 MTRR_LIB_ASSERT_ALIGNED (Base0
, Base1
- Base0
);
1511 // Count the number of vertices.
1513 Vertices
= (MTRR_LIB_ADDRESS
*)Scratch
;
1514 for (VertexIndex
= 0, Index
= 0; Index
< RangeCount
; Index
++) {
1515 Base
= Ranges
[Index
].BaseAddress
;
1516 Length
= Ranges
[Index
].Length
;
1517 while (Length
!= 0) {
1518 Alignment
= MtrrLibBiggestAlignment (Base
, A0
);
1519 SubLength
= Alignment
;
1520 if (SubLength
> Length
) {
1521 SubLength
= GetPowerOfTwo64 (Length
);
1523 if (VertexIndex
< *ScratchSize
/ sizeof (*Vertices
)) {
1524 Vertices
[VertexIndex
].Address
= Base
;
1525 Vertices
[VertexIndex
].Alignment
= Alignment
;
1526 Vertices
[VertexIndex
].Type
= Ranges
[Index
].Type
;
1527 Vertices
[VertexIndex
].Length
= SubLength
;
1530 Length
-= SubLength
;
1535 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1537 VertexCount
= VertexIndex
+ 1;
1539 DEBUG_CACHE
, " Count of vertices (%016llx - %016llx) = %d\n",
1540 Ranges
[0].BaseAddress
, Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
, VertexCount
1542 ASSERT (VertexCount
< MAX_UINT16
);
1544 RequiredScratchSize
= VertexCount
* sizeof (*Vertices
) + VertexCount
* VertexCount
* sizeof (*Weight
);
1545 if (*ScratchSize
< RequiredScratchSize
) {
1546 *ScratchSize
= RequiredScratchSize
;
1547 return RETURN_BUFFER_TOO_SMALL
;
1549 Vertices
[VertexCount
- 1].Address
= Base1
;
1551 Weight
= (UINT8
*) &Vertices
[VertexCount
];
1552 for (VertexIndex
= 0; VertexIndex
< VertexCount
; VertexIndex
++) {
1554 // Set optional weight between vertices and self->self to 0
1556 SetMem (&Weight
[M(VertexIndex
, 0)], VertexIndex
+ 1, 0);
1558 // Set mandatory weight between vertices to MAX_WEIGHT
1560 SetMem (&Weight
[M (VertexIndex
, VertexIndex
+ 1)], VertexCount
- VertexIndex
- 1, MAX_WEIGHT
);
1562 // Final result looks like:
1570 // Set mandatory weight and optional weight for adjacent vertices
1572 for (VertexIndex
= 0; VertexIndex
< VertexCount
- 1; VertexIndex
++) {
1573 if (Vertices
[VertexIndex
].Type
!= DefaultType
) {
1574 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 1;
1575 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 0;
1577 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 0;
1578 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 1;
1582 for (TypeCount
= 2; TypeCount
<= 3; TypeCount
++) {
1583 for (Start
= 0; Start
< VertexCount
; Start
++) {
1584 for (Stop
= Start
+ 2; Stop
< VertexCount
; Stop
++) {
1585 ASSERT (Vertices
[Stop
].Address
> Vertices
[Start
].Address
);
1586 Length
= Vertices
[Stop
].Address
- Vertices
[Start
].Address
;
1587 if (Length
> Vertices
[Start
].Alignment
) {
1589 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1593 if ((Weight
[M(Start
, Stop
)] == MAX_WEIGHT
) && MtrrLibIsPowerOfTwo (Length
)) {
1594 if (MtrrLibGetNumberOfTypes (
1595 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1598 // Update the Weight[Start, Stop] using subtractive path.
1600 MtrrLibCalculateSubtractivePath (
1603 (UINT16
)VertexCount
, Vertices
, Weight
,
1604 Start
, Stop
, Type
, TypeCount
,
1607 } else if (TypeCount
== 2) {
1609 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1610 // Because no matter how Stop is increased, we always meet 3-type range.
1619 Status
= RETURN_SUCCESS
;
1620 MtrrLibCalculateLeastMtrrs ((UINT16
) VertexCount
, Vertices
, Weight
, 0, (UINT16
) VertexCount
- 1, FALSE
);
1621 Stop
= (UINT16
) VertexCount
- 1;
1623 Start
= Vertices
[Stop
].Previous
;
1624 TypeCount
= MAX_UINT8
;
1626 if (Weight
[M(Start
, Stop
)] != 0) {
1627 TypeCount
= MtrrLibGetNumberOfTypes (Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
);
1628 Status
= MtrrLibAppendVariableMtrr (
1629 Mtrrs
, MtrrCapacity
, MtrrCount
,
1630 Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1631 MtrrLibLowestType (Type
)
1633 if (RETURN_ERROR (Status
)) {
1638 if (Start
!= Stop
- 1) {
1640 // substractive path
1642 if (TypeCount
== MAX_UINT8
) {
1643 TypeCount
= MtrrLibGetNumberOfTypes (
1644 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1647 Status
= MtrrLibCalculateSubtractivePath (
1650 (UINT16
) VertexCount
, Vertices
, Weight
, Start
, Stop
,
1652 Mtrrs
, MtrrCapacity
, MtrrCount
1654 if (RETURN_ERROR (Status
)) {
1665 Apply the fixed MTRR settings to memory range array.
1667 @param Fixed The fixed MTRR settings.
1668 @param Ranges Return the memory range array holding memory type
1669 settings for all memory address.
1670 @param RangeCapacity The capacity of memory range array.
1671 @param RangeCount Return the count of memory range.
1673 @retval RETURN_SUCCESS The memory range array is returned successfully.
1674 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1677 MtrrLibApplyFixedMtrrs (
1678 IN MTRR_FIXED_SETTINGS
*Fixed
,
1679 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1680 IN UINTN RangeCapacity
,
1681 IN OUT UINTN
*RangeCount
1684 RETURN_STATUS Status
;
1687 MTRR_MEMORY_CACHE_TYPE MemoryType
;
1691 for (MsrIndex
= 0; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
1692 ASSERT (Base
== mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
);
1693 for (Index
= 0; Index
< sizeof (UINT64
); Index
++) {
1694 MemoryType
= (MTRR_MEMORY_CACHE_TYPE
)((UINT8
*)(&Fixed
->Mtrr
[MsrIndex
]))[Index
];
1695 Status
= MtrrLibSetMemoryType (
1696 Ranges
, RangeCapacity
, RangeCount
, Base
, mMtrrLibFixedMtrrTable
[MsrIndex
].Length
, MemoryType
1698 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1701 Base
+= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
1704 ASSERT (Base
== BASE_1MB
);
1705 return RETURN_SUCCESS
;
1709 Apply the variable MTRR settings to memory range array.
1711 @param VariableMtrr The variable MTRR array.
1712 @param VariableMtrrCount The count of variable MTRRs.
1713 @param Ranges Return the memory range array with new MTRR settings applied.
1714 @param RangeCapacity The capacity of memory range array.
1715 @param RangeCount Return the count of memory range.
1717 @retval RETURN_SUCCESS The memory range array is returned successfully.
1718 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1721 MtrrLibApplyVariableMtrrs (
1722 IN CONST MTRR_MEMORY_RANGE
*VariableMtrr
,
1723 IN UINT32 VariableMtrrCount
,
1724 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1725 IN UINTN RangeCapacity
,
1726 IN OUT UINTN
*RangeCount
1729 RETURN_STATUS Status
;
1735 // UC > * (except WB, UC) > WB
1741 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1742 if ((VariableMtrr
[Index
].Length
!= 0) && (VariableMtrr
[Index
].Type
== CacheWriteBack
)) {
1743 Status
= MtrrLibSetMemoryType (
1744 Ranges
, RangeCapacity
, RangeCount
,
1745 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1747 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1754 // 2. Set other types than WB or UC
1756 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1757 if ((VariableMtrr
[Index
].Length
!= 0) &&
1758 (VariableMtrr
[Index
].Type
!= CacheWriteBack
) && (VariableMtrr
[Index
].Type
!= CacheUncacheable
)) {
1759 Status
= MtrrLibSetMemoryType (
1760 Ranges
, RangeCapacity
, RangeCount
,
1761 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1763 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1772 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1773 if (VariableMtrr
[Index
].Length
!= 0 && VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1774 Status
= MtrrLibSetMemoryType (
1775 Ranges
, RangeCapacity
, RangeCount
,
1776 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1778 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1783 return RETURN_SUCCESS
;
1787 Return the memory type bit mask that's compatible to first type in the Ranges.
1789 @param Ranges Memory range array holding the memory type
1790 settings for all memory address.
1791 @param RangeCount Count of memory ranges.
1793 @return Compatible memory type bit mask.
1796 MtrrLibGetCompatibleTypes (
1797 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1801 ASSERT (RangeCount
!= 0);
1803 switch (Ranges
[0].Type
) {
1804 case CacheWriteBack
:
1805 case CacheWriteThrough
:
1806 return (1 << CacheWriteBack
) | (1 << CacheWriteThrough
) | (1 << CacheUncacheable
);
1809 case CacheWriteCombining
:
1810 case CacheWriteProtected
:
1811 return (1 << Ranges
[0].Type
) | (1 << CacheUncacheable
);
1814 case CacheUncacheable
:
1815 if (RangeCount
== 1) {
1816 return (1 << CacheUncacheable
);
1818 return MtrrLibGetCompatibleTypes (&Ranges
[1], RangeCount
- 1);
1830 Overwrite the destination MTRR settings with the source MTRR settings.
1831 This routine is to make sure the modification to destination MTRR settings
1832 is as small as possible.
1834 @param DstMtrrs Destination MTRR settings.
1835 @param DstMtrrCount Count of destination MTRR settings.
1836 @param SrcMtrrs Source MTRR settings.
1837 @param SrcMtrrCount Count of source MTRR settings.
1838 @param Modified Flag array to indicate which destination MTRR setting is modified.
1841 MtrrLibMergeVariableMtrr (
1842 MTRR_MEMORY_RANGE
*DstMtrrs
,
1843 UINT32 DstMtrrCount
,
1844 MTRR_MEMORY_RANGE
*SrcMtrrs
,
1845 UINT32 SrcMtrrCount
,
1852 ASSERT (SrcMtrrCount
<= DstMtrrCount
);
1854 for (DstIndex
= 0; DstIndex
< DstMtrrCount
; DstIndex
++) {
1855 Modified
[DstIndex
] = FALSE
;
1857 if (DstMtrrs
[DstIndex
].Length
== 0) {
1860 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1861 if (DstMtrrs
[DstIndex
].BaseAddress
== SrcMtrrs
[SrcIndex
].BaseAddress
&&
1862 DstMtrrs
[DstIndex
].Length
== SrcMtrrs
[SrcIndex
].Length
&&
1863 DstMtrrs
[DstIndex
].Type
== SrcMtrrs
[SrcIndex
].Type
) {
1868 if (SrcIndex
== SrcMtrrCount
) {
1870 // Remove the one from DstMtrrs which is not in SrcMtrrs
1872 DstMtrrs
[DstIndex
].Length
= 0;
1873 Modified
[DstIndex
] = TRUE
;
1876 // Remove the one from SrcMtrrs which is also in DstMtrrs
1878 SrcMtrrs
[SrcIndex
].Length
= 0;
1883 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1884 // Merge MTRRs from SrcMtrrs to DstMtrrs
1887 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1888 if (SrcMtrrs
[SrcIndex
].Length
!= 0) {
1891 // Find the empty slot in DstMtrrs
1893 while (DstIndex
< DstMtrrCount
) {
1894 if (DstMtrrs
[DstIndex
].Length
== 0) {
1899 ASSERT (DstIndex
< DstMtrrCount
);
1900 CopyMem (&DstMtrrs
[DstIndex
], &SrcMtrrs
[SrcIndex
], sizeof (SrcMtrrs
[0]));
1901 Modified
[DstIndex
] = TRUE
;
1907 Calculate the variable MTRR settings for all memory ranges.
1909 @param DefaultType Default memory type.
1910 @param A0 Alignment to use when base address is 0.
1911 @param Ranges Memory range array holding the memory type
1912 settings for all memory address.
1913 @param RangeCount Count of memory ranges.
1914 @param Scratch Scratch buffer to be used in MTRR calculation.
1915 @param ScratchSize Pointer to the size of scratch buffer.
1916 @param VariableMtrr Array holding all MTRR settings.
1917 @param VariableMtrrCapacity Capacity of the MTRR array.
1918 @param VariableMtrrCount The count of MTRR settings in array.
1920 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1921 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1922 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1923 The required scratch buffer size is returned through ScratchSize.
1926 MtrrLibSetMemoryRanges (
1927 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1929 IN MTRR_MEMORY_RANGE
*Ranges
,
1930 IN UINTN RangeCount
,
1932 IN OUT UINTN
*ScratchSize
,
1933 OUT MTRR_MEMORY_RANGE
*VariableMtrr
,
1934 IN UINT32 VariableMtrrCapacity
,
1935 OUT UINT32
*VariableMtrrCount
1938 RETURN_STATUS Status
;
1943 UINT8 CompatibleTypes
;
1946 UINTN ActualScratchSize
;
1947 UINTN BiggestScratchSize
;
1949 *VariableMtrrCount
= 0;
1952 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
1953 // Each call needs different scratch buffer size.
1954 // When the provided scratch buffer size is not sufficient in any call,
1955 // set the GetActualScratchSize to TRUE, and following calls will only
1956 // calculate the actual scratch size for the caller.
1958 BiggestScratchSize
= 0;
1960 for (Index
= 0; Index
< RangeCount
;) {
1961 Base0
= Ranges
[Index
].BaseAddress
;
1964 // Full step is optimal
1966 while (Index
< RangeCount
) {
1967 ASSERT (Ranges
[Index
].BaseAddress
== Base0
);
1968 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
1969 while (Base0
+ Alignment
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1970 if ((BiggestScratchSize
<= *ScratchSize
) && (Ranges
[Index
].Type
!= DefaultType
)) {
1971 Status
= MtrrLibAppendVariableMtrr (
1972 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1973 Base0
, Alignment
, Ranges
[Index
].Type
1975 if (RETURN_ERROR (Status
)) {
1980 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
1984 // Remove the above range from Ranges[Index]
1986 Ranges
[Index
].Length
-= Base0
- Ranges
[Index
].BaseAddress
;
1987 Ranges
[Index
].BaseAddress
= Base0
;
1988 if (Ranges
[Index
].Length
!= 0) {
1995 if (Index
== RangeCount
) {
2000 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2001 // Per SDM, the compatible types between[B0, B1) are:
2006 CompatibleTypes
= MtrrLibGetCompatibleTypes (&Ranges
[Index
], RangeCount
- Index
);
2008 End
= Index
; // End points to last one that matches the CompatibleTypes.
2009 while (End
+ 1 < RangeCount
) {
2010 if (((1 << Ranges
[End
+ 1].Type
) & CompatibleTypes
) == 0) {
2015 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2016 Length
= GetPowerOfTwo64 (Ranges
[End
].BaseAddress
+ Ranges
[End
].Length
- Base0
);
2017 Base1
= Base0
+ MIN (Alignment
, Length
);
2020 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2023 while (End
+ 1 < RangeCount
) {
2024 if (Base1
<= Ranges
[End
+ 1].BaseAddress
) {
2030 Length
= Ranges
[End
].Length
;
2031 Ranges
[End
].Length
= Base1
- Ranges
[End
].BaseAddress
;
2032 ActualScratchSize
= *ScratchSize
;
2033 Status
= MtrrLibCalculateMtrrs (
2035 &Ranges
[Index
], End
+ 1 - Index
,
2036 Scratch
, &ActualScratchSize
,
2037 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
2039 if (Status
== RETURN_BUFFER_TOO_SMALL
) {
2040 BiggestScratchSize
= MAX (BiggestScratchSize
, ActualScratchSize
);
2042 // Ignore this error, because we need to calculate the biggest
2043 // scratch buffer size.
2045 Status
= RETURN_SUCCESS
;
2047 if (RETURN_ERROR (Status
)) {
2051 if (Length
!= Ranges
[End
].Length
) {
2052 Ranges
[End
].BaseAddress
= Base1
;
2053 Ranges
[End
].Length
= Length
- Ranges
[End
].Length
;
2060 if (*ScratchSize
< BiggestScratchSize
) {
2061 *ScratchSize
= BiggestScratchSize
;
2062 return RETURN_BUFFER_TOO_SMALL
;
2064 return RETURN_SUCCESS
;
2068 Set the below-1MB memory attribute to fixed MTRR buffer.
2069 Modified flag array indicates which fixed MTRR is modified.
2071 @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
2072 @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
2073 @param [in] BaseAddress Base address.
2074 @param [in] Length Length.
2075 @param [in] Type Memory type.
2077 @retval RETURN_SUCCESS The memory attribute is set successfully.
2078 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2079 for the fixed MTRRs.
2082 MtrrLibSetBelow1MBMemoryAttribute (
2083 IN OUT UINT64
*ClearMasks
,
2084 IN OUT UINT64
*OrMasks
,
2085 IN PHYSICAL_ADDRESS BaseAddress
,
2087 IN MTRR_MEMORY_CACHE_TYPE Type
2090 RETURN_STATUS Status
;
2095 ASSERT (BaseAddress
< BASE_1MB
);
2097 MsrIndex
= (UINT32
)-1;
2098 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
2099 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
2100 if (RETURN_ERROR (Status
)) {
2103 ClearMasks
[MsrIndex
] = ClearMasks
[MsrIndex
] | ClearMask
;
2104 OrMasks
[MsrIndex
] = (OrMasks
[MsrIndex
] & ~ClearMask
) | OrMask
;
2106 return RETURN_SUCCESS
;
2110 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2112 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2113 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2114 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2115 It may be updated to the actual required size when the calculation
2116 needs more scratch buffer.
2117 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2118 When range overlap happens, the last one takes higher priority.
2119 When the function returns, either all the attributes are set successfully,
2120 or none of them is set.
2121 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2123 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2124 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2125 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2126 memory resource range specified by BaseAddress and Length in any range.
2127 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2128 range specified by BaseAddress and Length in any range.
2129 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2130 the memory resource ranges.
2131 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2132 BaseAddress and Length cannot be modified.
2133 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2137 MtrrSetMemoryAttributesInMtrrSettings (
2138 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2140 IN OUT UINTN
*ScratchSize
,
2141 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
2145 RETURN_STATUS Status
;
2149 BOOLEAN Above1MbExist
;
2151 UINT64 MtrrValidBitsMask
;
2152 UINT64 MtrrValidAddressMask
;
2153 MTRR_MEMORY_CACHE_TYPE DefaultType
;
2154 MTRR_VARIABLE_SETTINGS VariableSettings
;
2155 MTRR_MEMORY_RANGE WorkingRanges
[2 * ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
) + 2];
2156 UINTN WorkingRangeCount
;
2158 MTRR_VARIABLE_SETTING VariableSetting
;
2159 UINT32 OriginalVariableMtrrCount
;
2160 UINT32 FirmwareVariableMtrrCount
;
2161 UINT32 WorkingVariableMtrrCount
;
2162 MTRR_MEMORY_RANGE OriginalVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2163 MTRR_MEMORY_RANGE WorkingVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2164 BOOLEAN VariableSettingModified
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2166 UINT64 ClearMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2167 UINT64 OrMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2169 MTRR_CONTEXT MtrrContext
;
2170 BOOLEAN MtrrContextValid
;
2172 Status
= RETURN_SUCCESS
;
2173 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2176 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2178 SetMem (VariableSettingModified
, ARRAY_SIZE (VariableSettingModified
), FALSE
);
2181 // TRUE indicating the caller requests to set variable MTRRs.
2183 Above1MbExist
= FALSE
;
2184 OriginalVariableMtrrCount
= 0;
2187 // 0. Dump the requests.
2190 DEBUG ((DEBUG_CACHE
, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2191 (MtrrSetting
== NULL
) ? "Hardware" : "Buffer", *ScratchSize
,
2192 (RangeCount
<= 1) ? "," : "\n"
2194 for (Index
= 0; Index
< RangeCount
; Index
++) {
2195 DEBUG ((DEBUG_CACHE
, " %a: [%016lx, %016lx)\n",
2196 mMtrrMemoryCacheTypeShortName
[MIN (Ranges
[Index
].Type
, CacheInvalid
)],
2197 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
2203 // 1. Validate the parameters.
2205 if (!IsMtrrSupported ()) {
2206 Status
= RETURN_UNSUPPORTED
;
2210 for (Index
= 0; Index
< RangeCount
; Index
++) {
2211 if (Ranges
[Index
].Length
== 0) {
2212 Status
= RETURN_INVALID_PARAMETER
;
2215 if (((Ranges
[Index
].BaseAddress
& ~MtrrValidAddressMask
) != 0) ||
2216 ((((Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) & ~MtrrValidAddressMask
) != 0) &&
2217 (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) != MtrrValidBitsMask
+ 1)
2220 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2221 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2223 Status
= RETURN_UNSUPPORTED
;
2226 if ((Ranges
[Index
].Type
!= CacheUncacheable
) &&
2227 (Ranges
[Index
].Type
!= CacheWriteCombining
) &&
2228 (Ranges
[Index
].Type
!= CacheWriteThrough
) &&
2229 (Ranges
[Index
].Type
!= CacheWriteProtected
) &&
2230 (Ranges
[Index
].Type
!= CacheWriteBack
)) {
2231 Status
= RETURN_INVALID_PARAMETER
;
2234 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
> BASE_1MB
) {
2235 Above1MbExist
= TRUE
;
2240 // 2. Apply the above-1MB memory attribute settings.
2242 if (Above1MbExist
) {
2244 // 2.1. Read all variable MTRRs and convert to Ranges.
2246 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
2247 MtrrGetVariableMtrrWorker (MtrrSetting
, OriginalVariableMtrrCount
, &VariableSettings
);
2248 MtrrLibGetRawVariableRanges (
2249 &VariableSettings
, OriginalVariableMtrrCount
,
2250 MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
2253 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
2254 WorkingRangeCount
= 1;
2255 WorkingRanges
[0].BaseAddress
= 0;
2256 WorkingRanges
[0].Length
= MtrrValidBitsMask
+ 1;
2257 WorkingRanges
[0].Type
= DefaultType
;
2259 Status
= MtrrLibApplyVariableMtrrs (
2260 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2261 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
);
2262 ASSERT_RETURN_ERROR (Status
);
2264 ASSERT (OriginalVariableMtrrCount
>= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
));
2265 FirmwareVariableMtrrCount
= OriginalVariableMtrrCount
- PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
2266 ASSERT (WorkingRangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
2269 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2271 Status
= MtrrLibSetMemoryType (
2272 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2273 0, SIZE_1MB
, CacheUncacheable
2275 ASSERT (Status
!= RETURN_OUT_OF_RESOURCES
);
2278 // 2.3. Apply the new memory attribute settings to Ranges.
2281 for (Index
= 0; Index
< RangeCount
; Index
++) {
2282 BaseAddress
= Ranges
[Index
].BaseAddress
;
2283 Length
= Ranges
[Index
].Length
;
2284 if (BaseAddress
< BASE_1MB
) {
2285 if (Length
<= BASE_1MB
- BaseAddress
) {
2288 Length
-= BASE_1MB
- BaseAddress
;
2289 BaseAddress
= BASE_1MB
;
2291 Status
= MtrrLibSetMemoryType (
2292 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2293 BaseAddress
, Length
, Ranges
[Index
].Type
2295 if (Status
== RETURN_ALREADY_STARTED
) {
2296 Status
= RETURN_SUCCESS
;
2297 } else if (Status
== RETURN_OUT_OF_RESOURCES
) {
2300 ASSERT_RETURN_ERROR (Status
);
2307 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2308 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2310 Status
= MtrrLibSetMemoryRanges (
2311 DefaultType
, LShiftU64 (1, (UINTN
)HighBitSet64 (MtrrValidBitsMask
)), WorkingRanges
, WorkingRangeCount
,
2312 Scratch
, ScratchSize
,
2313 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
2315 if (RETURN_ERROR (Status
)) {
2320 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2322 for (Index
= 0; Index
< WorkingVariableMtrrCount
; Index
++) {
2323 if (WorkingVariableMtrr
[Index
].BaseAddress
== 0 && WorkingVariableMtrr
[Index
].Length
== SIZE_1MB
) {
2324 ASSERT (WorkingVariableMtrr
[Index
].Type
== CacheUncacheable
);
2325 WorkingVariableMtrrCount
--;
2327 &WorkingVariableMtrr
[Index
], &WorkingVariableMtrr
[Index
+ 1],
2328 (WorkingVariableMtrrCount
- Index
) * sizeof (WorkingVariableMtrr
[0])
2334 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
2335 Status
= RETURN_OUT_OF_RESOURCES
;
2340 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2341 // Make sure least modification is made to OriginalVariableMtrr.
2343 MtrrLibMergeVariableMtrr (
2344 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2345 WorkingVariableMtrr
, WorkingVariableMtrrCount
,
2346 VariableSettingModified
2352 // 3. Apply the below-1MB memory attribute settings.
2354 // (Value & ~0 | 0) still equals to (Value)
2356 ZeroMem (ClearMasks
, sizeof (ClearMasks
));
2357 ZeroMem (OrMasks
, sizeof (OrMasks
));
2358 for (Index
= 0; Index
< RangeCount
; Index
++) {
2359 if (Ranges
[Index
].BaseAddress
>= BASE_1MB
) {
2363 Status
= MtrrLibSetBelow1MBMemoryAttribute (
2364 ClearMasks
, OrMasks
,
2365 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
, Ranges
[Index
].Type
2367 if (RETURN_ERROR (Status
)) {
2372 MtrrContextValid
= FALSE
;
2374 // 4. Write fixed MTRRs that have been modified
2376 for (Index
= 0; Index
< ARRAY_SIZE (ClearMasks
); Index
++) {
2377 if (ClearMasks
[Index
] != 0) {
2378 if (MtrrSetting
!= NULL
) {
2379 MtrrSetting
->Fixed
.Mtrr
[Index
] = (MtrrSetting
->Fixed
.Mtrr
[Index
] & ~ClearMasks
[Index
]) | OrMasks
[Index
];
2381 if (!MtrrContextValid
) {
2382 MtrrLibPreMtrrChange (&MtrrContext
);
2383 MtrrContextValid
= TRUE
;
2385 AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
, ~ClearMasks
[Index
], OrMasks
[Index
]);
2391 // 5. Write variable MTRRs that have been modified
2393 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2394 if (VariableSettingModified
[Index
]) {
2395 if (OriginalVariableMtrr
[Index
].Length
!= 0) {
2396 VariableSetting
.Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
)
2397 | (UINT8
)OriginalVariableMtrr
[Index
].Type
;
2398 VariableSetting
.Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2400 VariableSetting
.Base
= 0;
2401 VariableSetting
.Mask
= 0;
2403 if (MtrrSetting
!= NULL
) {
2404 CopyMem (&MtrrSetting
->Variables
.Mtrr
[Index
], &VariableSetting
, sizeof (VariableSetting
));
2406 if (!MtrrContextValid
) {
2407 MtrrLibPreMtrrChange (&MtrrContext
);
2408 MtrrContextValid
= TRUE
;
2411 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2412 VariableSetting
.Base
2415 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2416 VariableSetting
.Mask
2422 if (MtrrSetting
!= NULL
) {
2423 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2424 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
2426 if (MtrrContextValid
) {
2427 MtrrLibPostMtrrChange (&MtrrContext
);
2432 DEBUG ((DEBUG_CACHE
, " Result = %r\n", Status
));
2433 if (!RETURN_ERROR (Status
)) {
2434 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2440 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2442 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2443 @param[in] BaseAddress The physical address that is the start address
2445 @param[in] Length The size in bytes of the memory range.
2446 @param[in] Attribute The bit mask of attributes to set for the
2449 @retval RETURN_SUCCESS The attributes were set for the memory range.
2450 @retval RETURN_INVALID_PARAMETER Length is zero.
2451 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2452 memory resource range specified by BaseAddress and Length.
2453 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2454 range specified by BaseAddress and Length.
2455 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2456 BaseAddress and Length cannot be modified.
2457 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2458 the memory resource range.
2459 Multiple memory range attributes setting by calling this API multiple
2460 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2461 the number of CPU MTRRs are too small to set such memory attributes.
2462 Pass the multiple memory range attributes to one call of
2463 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2464 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2465 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2466 external scratch buffer.
2470 MtrrSetMemoryAttributeInMtrrSettings (
2471 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2472 IN PHYSICAL_ADDRESS BaseAddress
,
2474 IN MTRR_MEMORY_CACHE_TYPE Attribute
2477 UINT8 Scratch
[SCRATCH_BUFFER_SIZE
];
2479 MTRR_MEMORY_RANGE Range
;
2481 Range
.BaseAddress
= BaseAddress
;
2482 Range
.Length
= Length
;
2483 Range
.Type
= Attribute
;
2484 ScratchSize
= sizeof (Scratch
);
2485 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting
, Scratch
, &ScratchSize
, &Range
, 1);
2489 This function attempts to set the attributes for a memory range.
2491 @param[in] BaseAddress The physical address that is the start
2492 address of a memory range.
2493 @param[in] Length The size in bytes of the memory range.
2494 @param[in] Attributes The bit mask of attributes to set for the
2497 @retval RETURN_SUCCESS The attributes were set for the memory
2499 @retval RETURN_INVALID_PARAMETER Length is zero.
2500 @retval RETURN_UNSUPPORTED The processor does not support one or
2501 more bytes of the memory resource range
2502 specified by BaseAddress and Length.
2503 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2504 for the memory resource range specified
2505 by BaseAddress and Length.
2506 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2507 range specified by BaseAddress and Length
2509 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2510 modify the attributes of the memory
2512 Multiple memory range attributes setting by calling this API multiple
2513 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2514 the number of CPU MTRRs are too small to set such memory attributes.
2515 Pass the multiple memory range attributes to one call of
2516 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2517 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2518 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2519 external scratch buffer.
2523 MtrrSetMemoryAttribute (
2524 IN PHYSICAL_ADDRESS BaseAddress
,
2526 IN MTRR_MEMORY_CACHE_TYPE Attribute
2529 return MtrrSetMemoryAttributeInMtrrSettings (NULL
, BaseAddress
, Length
, Attribute
);
2533 Worker function setting variable MTRRs
2535 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2539 MtrrSetVariableMtrrWorker (
2540 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2544 UINT32 VariableMtrrCount
;
2546 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2547 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
2549 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2551 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2552 VariableSettings
->Mtrr
[Index
].Base
2555 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2556 VariableSettings
->Mtrr
[Index
].Mask
2562 Worker function setting fixed MTRRs
2564 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2568 MtrrSetFixedMtrrWorker (
2569 IN MTRR_FIXED_SETTINGS
*FixedSettings
2574 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2576 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2577 FixedSettings
->Mtrr
[Index
]
2584 This function gets the content in all MTRRs (variable and fixed)
2586 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2588 @retval the pointer of MtrrSetting
2594 OUT MTRR_SETTINGS
*MtrrSetting
2597 if (!IsMtrrSupported ()) {
2604 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2607 // Get variable MTRRs
2609 MtrrGetVariableMtrrWorker (
2611 GetVariableMtrrCountWorker (),
2612 &MtrrSetting
->Variables
2616 // Get MTRR_DEF_TYPE value
2618 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2625 This function sets all MTRRs (variable and fixed)
2627 @param[in] MtrrSetting A buffer holding all MTRRs content.
2629 @retval The pointer of MtrrSetting
2635 IN MTRR_SETTINGS
*MtrrSetting
2638 MTRR_CONTEXT MtrrContext
;
2640 if (!IsMtrrSupported ()) {
2644 MtrrLibPreMtrrChange (&MtrrContext
);
2649 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2652 // Set variable MTRRs
2654 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2657 // Set MTRR_DEF_TYPE value
2659 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2661 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2668 Checks if MTRR is supported.
2670 @retval TRUE MTRR is supported.
2671 @retval FALSE MTRR is not supported.
2680 CPUID_VERSION_INFO_EDX Edx
;
2681 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2684 // Check CPUID(1).EDX[12] for MTRR capability
2686 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2687 if (Edx
.Bits
.MTRR
== 0) {
2692 // Check number of variable MTRRs and fixed MTRRs existence.
2693 // If number of variable MTRRs is zero, or fixed MTRRs do not
2694 // exist, return false.
2696 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2697 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {
2705 Worker function prints all MTRRs for debugging.
2707 If MtrrSetting is not NULL, print MTRR settings from input MTRR
2709 If MtrrSetting is NULL, print MTRR settings from MTRRs.
2711 @param MtrrSetting A buffer holding all MTRRs content.
2714 MtrrDebugPrintAllMtrrsWorker (
2715 IN MTRR_SETTINGS
*MtrrSetting
2719 MTRR_SETTINGS LocalMtrrs
;
2720 MTRR_SETTINGS
*Mtrrs
;
2723 UINT64 MtrrValidBitsMask
;
2724 UINT64 MtrrValidAddressMask
;
2725 UINT32 VariableMtrrCount
;
2726 BOOLEAN ContainVariableMtrr
;
2727 MTRR_MEMORY_RANGE Ranges
[
2728 ARRAY_SIZE (mMtrrLibFixedMtrrTable
) * sizeof (UINT64
) + 2 * ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
) + 1
2730 MTRR_MEMORY_RANGE RawVariableRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
2732 if (!IsMtrrSupported ()) {
2736 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2738 if (MtrrSetting
!= NULL
) {
2739 Mtrrs
= MtrrSetting
;
2741 MtrrGetAllMtrrs (&LocalMtrrs
);
2742 Mtrrs
= &LocalMtrrs
;
2746 // Dump RAW MTRR contents
2748 DEBUG ((DEBUG_CACHE
, "MTRR Settings:\n"));
2749 DEBUG ((DEBUG_CACHE
, "=============\n"));
2750 DEBUG ((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
2751 for (Index
= 0; Index
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); Index
++) {
2752 DEBUG ((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
2754 ContainVariableMtrr
= FALSE
;
2755 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2756 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
2758 // If mask is not valid, then do not display range
2762 ContainVariableMtrr
= TRUE
;
2763 DEBUG ((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2765 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
2766 Mtrrs
->Variables
.Mtrr
[Index
].Mask
2769 if (!ContainVariableMtrr
) {
2770 DEBUG ((DEBUG_CACHE
, "Variable MTRR : None.\n"));
2772 DEBUG((DEBUG_CACHE
, "\n"));
2775 // Dump MTRR setting in ranges
2777 DEBUG((DEBUG_CACHE
, "Memory Ranges:\n"));
2778 DEBUG((DEBUG_CACHE
, "====================================\n"));
2779 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2780 Ranges
[0].BaseAddress
= 0;
2781 Ranges
[0].Length
= MtrrValidBitsMask
+ 1;
2782 Ranges
[0].Type
= MtrrGetDefaultMemoryTypeWorker (Mtrrs
);
2785 MtrrLibGetRawVariableRanges (
2786 &Mtrrs
->Variables
, VariableMtrrCount
,
2787 MtrrValidBitsMask
, MtrrValidAddressMask
, RawVariableRanges
2789 MtrrLibApplyVariableMtrrs (
2790 RawVariableRanges
, VariableMtrrCount
,
2791 Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
2794 MtrrLibApplyFixedMtrrs (&Mtrrs
->Fixed
, Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
);
2796 for (Index
= 0; Index
< RangeCount
; Index
++) {
2797 DEBUG ((DEBUG_CACHE
, "%a:%016lx-%016lx\n",
2798 mMtrrMemoryCacheTypeShortName
[Ranges
[Index
].Type
],
2799 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- 1
2806 This function prints all MTRRs for debugging.
2810 MtrrDebugPrintAllMtrrs (
2814 MtrrDebugPrintAllMtrrsWorker (NULL
);