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 - 2019, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #include <Register/Cpuid.h>
15 #include <Register/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 This function will get the raw value in variable MTRRs
462 @param[out] VariableSettings A buffer to hold variable MTRRs content.
464 @return The VariableSettings input pointer
467 MTRR_VARIABLE_SETTINGS
*
469 MtrrGetVariableMtrr (
470 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
473 if (!IsMtrrSupported ()) {
474 return VariableSettings
;
477 return MtrrGetVariableMtrrWorker (
479 GetVariableMtrrCountWorker (),
485 Programs fixed MTRRs registers.
487 @param[in] Type The memory type to set.
488 @param[in, out] Base The base address of memory range.
489 @param[in, out] Length The length of memory range.
490 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
491 On return, the current index of the fixed MTRR MSR to program.
492 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
493 @param[out] OrMask The bits to set in the fixed MTRR MSR.
495 @retval RETURN_SUCCESS The cache type was updated successfully
496 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
501 MtrrLibProgramFixedMtrr (
502 IN MTRR_MEMORY_CACHE_TYPE Type
,
504 IN OUT UINT64
*Length
,
505 IN OUT UINT32
*LastMsrIndex
,
506 OUT UINT64
*ClearMask
,
511 UINT32 LeftByteShift
;
512 UINT32 RightByteShift
;
516 // Find the fixed MTRR index to be programmed
518 for (MsrIndex
= *LastMsrIndex
+ 1; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
519 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) &&
522 mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
+
523 (8 * mMtrrLibFixedMtrrTable
[MsrIndex
].Length
)
531 ASSERT (MsrIndex
!= ARRAY_SIZE (mMtrrLibFixedMtrrTable
));
534 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
536 if ((((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
538 // Base address should be aligned to the begin of a certain Fixed MTRR range.
540 return RETURN_UNSUPPORTED
;
542 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
543 ASSERT (LeftByteShift
< 8);
546 // Find the end offset in fixed MTRR and calculate byte offset of right shift
548 SubLength
= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
* (8 - LeftByteShift
);
549 if (*Length
>= SubLength
) {
552 if (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
554 // Length should be aligned to the end of a certain Fixed MTRR range.
556 return RETURN_UNSUPPORTED
;
558 RightByteShift
= 8 - LeftByteShift
- (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
560 // Update SubLength by actual length
565 *ClearMask
= CLEAR_SEED
;
566 *OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
568 if (LeftByteShift
!= 0) {
570 // Clear the low bits by LeftByteShift
572 *ClearMask
&= LShiftU64 (*ClearMask
, LeftByteShift
* 8);
573 *OrMask
&= LShiftU64 (*OrMask
, LeftByteShift
* 8);
576 if (RightByteShift
!= 0) {
578 // Clear the high bits by RightByteShift
580 *ClearMask
&= RShiftU64 (*ClearMask
, RightByteShift
* 8);
581 *OrMask
&= RShiftU64 (*OrMask
, RightByteShift
* 8);
584 *Length
-= SubLength
;
587 *LastMsrIndex
= MsrIndex
;
589 return RETURN_SUCCESS
;
594 Worker function gets the attribute of variable MTRRs.
596 This function shadows the content of variable MTRRs into an
597 internal array: VariableMtrr.
599 @param[in] VariableSettings The variable MTRR values to shadow
600 @param[in] VariableMtrrCount The number of variable MTRRs
601 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
602 @param[in] MtrrValidAddressMask The valid address mask for MTRR
603 @param[out] VariableMtrr The array to shadow variable MTRRs content
605 @return Number of MTRRs which has been used.
609 MtrrGetMemoryAttributeInVariableMtrrWorker (
610 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
611 IN UINTN VariableMtrrCount
,
612 IN UINT64 MtrrValidBitsMask
,
613 IN UINT64 MtrrValidAddressMask
,
614 OUT VARIABLE_MTRR
*VariableMtrr
620 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
621 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
622 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
623 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
624 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
625 VariableMtrr
[Index
].Length
=
626 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
627 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
628 VariableMtrr
[Index
].Valid
= TRUE
;
629 VariableMtrr
[Index
].Used
= TRUE
;
637 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
638 One MTRR_MEMORY_RANGE element is created for each MTRR setting.
639 The routine doesn't remove the overlap or combine the near-by region.
641 @param[in] VariableSettings The variable MTRR values to shadow
642 @param[in] VariableMtrrCount The number of variable MTRRs
643 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
644 @param[in] MtrrValidAddressMask The valid address mask for MTRR
645 @param[out] VariableMtrr The array to shadow variable MTRRs content
647 @return Number of MTRRs which has been used.
651 MtrrLibGetRawVariableRanges (
652 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
653 IN UINTN VariableMtrrCount
,
654 IN UINT64 MtrrValidBitsMask
,
655 IN UINT64 MtrrValidAddressMask
,
656 OUT MTRR_MEMORY_RANGE
*VariableMtrr
662 ZeroMem (VariableMtrr
, sizeof (MTRR_MEMORY_RANGE
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
663 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
664 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
665 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
666 VariableMtrr
[Index
].Length
=
667 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
668 VariableMtrr
[Index
].Type
= (MTRR_MEMORY_CACHE_TYPE
)(VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
676 Gets the attribute of variable MTRRs.
678 This function shadows the content of variable MTRRs into an
679 internal array: VariableMtrr.
681 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
682 @param[in] MtrrValidAddressMask The valid address mask for MTRR
683 @param[out] VariableMtrr The array to shadow variable MTRRs content
685 @return The return value of this parameter indicates the
686 number of MTRRs which has been used.
691 MtrrGetMemoryAttributeInVariableMtrr (
692 IN UINT64 MtrrValidBitsMask
,
693 IN UINT64 MtrrValidAddressMask
,
694 OUT VARIABLE_MTRR
*VariableMtrr
697 MTRR_VARIABLE_SETTINGS VariableSettings
;
699 if (!IsMtrrSupported ()) {
703 MtrrGetVariableMtrrWorker (
705 GetVariableMtrrCountWorker (),
709 return MtrrGetMemoryAttributeInVariableMtrrWorker (
711 GetFirmwareVariableMtrrCountWorker (),
713 MtrrValidAddressMask
,
719 Return the biggest alignment (lowest set bit) of address.
720 The function is equivalent to: 1 << LowBitSet64 (Address).
722 @param Address The address to return the alignment.
723 @param Alignment0 The alignment to return when Address is 0.
725 @return The least alignment of the Address.
728 MtrrLibBiggestAlignment (
737 return Address
& ((~Address
) + 1);
741 Return whether the left MTRR type precedes the right MTRR type.
743 The MTRR type precedence rules are:
744 1. UC precedes any other type
746 For further details, please refer the IA32 Software Developer's Manual,
747 Volume 3, Section "MTRR Precedences".
749 @param Left The left MTRR type.
750 @param Right The right MTRR type.
752 @retval TRUE Left precedes Right.
753 @retval FALSE Left doesn't precede Right.
756 MtrrLibTypeLeftPrecedeRight (
757 IN MTRR_MEMORY_CACHE_TYPE Left
,
758 IN MTRR_MEMORY_CACHE_TYPE Right
761 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
765 Initializes the valid bits mask and valid address mask for MTRRs.
767 This function initializes the valid bits mask and valid address mask for MTRRs.
769 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
770 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
774 MtrrLibInitializeMtrrMask (
775 OUT UINT64
*MtrrValidBitsMask
,
776 OUT UINT64
*MtrrValidAddressMask
779 UINT32 MaxExtendedFunction
;
780 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
783 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
785 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
786 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
788 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
791 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
792 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
797 Determines the real attribute of a memory range.
799 This function is to arbitrate the real attribute of the memory when
800 there are 2 MTRRs covers the same memory range. For further details,
801 please refer the IA32 Software Developer's Manual, Volume 3,
802 Section "MTRR Precedences".
804 @param[in] MtrrType1 The first kind of Memory type
805 @param[in] MtrrType2 The second kind of memory type
808 MTRR_MEMORY_CACHE_TYPE
810 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
811 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
814 if (MtrrType1
== MtrrType2
) {
819 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
820 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
823 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
831 Worker function will get the memory cache type of the specific address.
833 If MtrrSetting is not NULL, gets the memory cache type from input
834 MTRR settings buffer.
835 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
837 @param[in] MtrrSetting A buffer holding all MTRRs content.
838 @param[in] Address The specific address
840 @return Memory cache type of the specific address
843 MTRR_MEMORY_CACHE_TYPE
844 MtrrGetMemoryAttributeByAddressWorker (
845 IN MTRR_SETTINGS
*MtrrSetting
,
846 IN PHYSICAL_ADDRESS Address
849 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
853 MTRR_MEMORY_CACHE_TYPE MtrrType
;
854 MTRR_MEMORY_RANGE VariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
855 UINT64 MtrrValidBitsMask
;
856 UINT64 MtrrValidAddressMask
;
857 UINT32 VariableMtrrCount
;
858 MTRR_VARIABLE_SETTINGS VariableSettings
;
861 // Check if MTRR is enabled, if not, return UC as attribute
863 if (MtrrSetting
== NULL
) {
864 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
866 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
869 if (DefType
.Bits
.E
== 0) {
870 return CacheUncacheable
;
874 // If address is less than 1M, then try to go through the fixed MTRR
876 if (Address
< BASE_1MB
) {
877 if (DefType
.Bits
.FE
!= 0) {
879 // Go through the fixed MTRR
881 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
882 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
883 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
884 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
886 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
887 mMtrrLibFixedMtrrTable
[Index
].Length
;
888 if (MtrrSetting
== NULL
) {
889 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
891 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
893 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
899 VariableMtrrCount
= GetVariableMtrrCountWorker ();
900 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
));
901 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
903 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
904 MtrrLibGetRawVariableRanges (
908 MtrrValidAddressMask
,
913 // Go through the variable MTRR
915 MtrrType
= CacheInvalid
;
916 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
917 if (VariableMtrr
[Index
].Length
!= 0) {
918 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
919 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
920 if (MtrrType
== CacheInvalid
) {
921 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
923 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
930 // If there is no MTRR which covers the Address, use the default MTRR type.
932 if (MtrrType
== CacheInvalid
) {
933 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
941 This function will get the memory cache type of the specific address.
943 This function is mainly for debug purpose.
945 @param[in] Address The specific address
947 @return Memory cache type of the specific address
950 MTRR_MEMORY_CACHE_TYPE
952 MtrrGetMemoryAttribute (
953 IN PHYSICAL_ADDRESS Address
956 if (!IsMtrrSupported ()) {
957 return CacheUncacheable
;
960 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
964 Update the Ranges array to change the specified range identified by
965 BaseAddress and Length to Type.
967 @param Ranges Array holding memory type settings for all memory regions.
968 @param Capacity The maximum count of memory ranges the array can hold.
969 @param Count Return the new memory range count in the array.
970 @param BaseAddress The base address of the memory range to change type.
971 @param Length The length of the memory range to change type.
972 @param Type The new type of the specified memory range.
974 @retval RETURN_SUCCESS The type of the specified memory range is
975 changed successfully.
976 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
978 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
979 range exceeds capacity.
982 MtrrLibSetMemoryType (
983 IN MTRR_MEMORY_RANGE
*Ranges
,
986 IN UINT64 BaseAddress
,
988 IN MTRR_MEMORY_CACHE_TYPE Type
1001 Limit
= BaseAddress
+ Length
;
1002 StartIndex
= *Count
;
1004 for (Index
= 0; Index
< *Count
; Index
++) {
1005 if ((StartIndex
== *Count
) &&
1006 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1007 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1009 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1012 if ((EndIndex
== *Count
) &&
1013 (Ranges
[Index
].BaseAddress
< Limit
) &&
1014 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1016 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1021 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1022 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1023 return RETURN_ALREADY_STARTED
;
1027 // The type change may cause merging with previous range or next range.
1028 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1029 // logic doesn't need to consider merging.
1031 if (StartIndex
!= 0) {
1032 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1034 Length
+= Ranges
[StartIndex
].Length
;
1035 BaseAddress
-= Ranges
[StartIndex
].Length
;
1038 if (EndIndex
!= (*Count
) - 1) {
1039 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1041 Length
+= Ranges
[EndIndex
].Length
;
1046 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1047 // |++++++++++++++++++| 0 3 1=3-0-2 3
1048 // |+++++++| 0 1 -1=1-0-2 5
1049 // |+| 0 0 -2=0-0-2 6
1050 // |+++| 0 0 -1=0-0-2+1 5
1053 DeltaCount
= EndIndex
- StartIndex
- 2;
1054 if (LengthLeft
== 0) {
1057 if (LengthRight
== 0) {
1060 if (*Count
- DeltaCount
> Capacity
) {
1061 return RETURN_OUT_OF_RESOURCES
;
1065 // Reserve (-DeltaCount) space
1067 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1068 *Count
-= DeltaCount
;
1070 if (LengthLeft
!= 0) {
1071 Ranges
[StartIndex
].Length
= LengthLeft
;
1074 if (LengthRight
!= 0) {
1075 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1076 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1077 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1079 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1080 Ranges
[StartIndex
].Length
= Length
;
1081 Ranges
[StartIndex
].Type
= Type
;
1082 return RETURN_SUCCESS
;
1086 Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1088 @param Ranges Array holding memory type settings for all memory regions.
1089 @param RangeCount The count of memory ranges the array holds.
1090 @param BaseAddress Base address.
1091 @param Length Length.
1092 @param Types Return bit mask to indicate all memory types in the specified range.
1094 @retval Number of memory types.
1097 MtrrLibGetNumberOfTypes (
1098 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1099 IN UINTN RangeCount
,
1100 IN UINT64 BaseAddress
,
1102 IN OUT UINT8
*Types OPTIONAL
1111 for (Index
= 0; Index
< RangeCount
; Index
++) {
1112 if ((Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1113 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)
1115 if ((LocalTypes
& (1 << Ranges
[Index
].Type
)) == 0) {
1116 LocalTypes
|= (UINT8
)(1 << Ranges
[Index
].Type
);
1120 if (BaseAddress
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1121 Length
-= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1122 BaseAddress
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
;
1129 if (Types
!= NULL
) {
1130 *Types
= LocalTypes
;
1136 Calculate the least MTRR number from vertex Start to Stop and update
1137 the Previous of all vertices from Start to Stop is updated to reflect
1138 how the memory range is covered by MTRR.
1140 @param VertexCount The count of vertices in the graph.
1141 @param Vertices Array holding all vertices.
1142 @param Weight 2-dimention array holding weights between vertices.
1143 @param Start Start vertex.
1144 @param Stop Stop vertex.
1145 @param IncludeOptional TRUE to count the optional weight.
1148 MtrrLibCalculateLeastMtrrs (
1149 IN UINT16 VertexCount
,
1150 IN MTRR_LIB_ADDRESS
*Vertices
,
1151 IN OUT CONST UINT8
*Weight
,
1154 IN BOOLEAN IncludeOptional
1163 for (Index
= Start
; Index
<= Stop
; Index
++) {
1164 Vertices
[Index
].Visited
= FALSE
;
1165 Mandatory
= Weight
[M(Start
,Index
)];
1166 Vertices
[Index
].Weight
= Mandatory
;
1167 if (Mandatory
!= MAX_WEIGHT
) {
1168 Optional
= IncludeOptional
? Weight
[O(Start
, Index
)] : 0;
1169 Vertices
[Index
].Weight
+= Optional
;
1170 ASSERT (Vertices
[Index
].Weight
>= Optional
);
1176 while (!Vertices
[Stop
].Visited
) {
1178 // Update the weight from the shortest vertex to other unvisited vertices
1180 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1181 if (!Vertices
[Index
].Visited
) {
1182 Mandatory
= Weight
[M(MinI
, Index
)];
1183 if (Mandatory
!= MAX_WEIGHT
) {
1184 Optional
= IncludeOptional
? Weight
[O(MinI
, Index
)] : 0;
1185 if (MinWeight
+ Mandatory
+ Optional
<= Vertices
[Index
].Weight
) {
1186 Vertices
[Index
].Weight
= MinWeight
+ Mandatory
+ Optional
;
1187 Vertices
[Index
].Previous
= MinI
; // Previous is Start based.
1194 // Find the shortest vertex from Start
1197 MinWeight
= MAX_WEIGHT
;
1198 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1199 if (!Vertices
[Index
].Visited
&& MinWeight
> Vertices
[Index
].Weight
) {
1201 MinWeight
= Vertices
[Index
].Weight
;
1206 // Mark the shortest vertex from Start as visited
1208 Vertices
[MinI
].Visited
= TRUE
;
1213 Append the MTRR setting to MTRR setting array.
1215 @param Mtrrs Array holding all MTRR settings.
1216 @param MtrrCapacity Capacity of the MTRR array.
1217 @param MtrrCount The count of MTRR settings in array.
1218 @param BaseAddress Base address.
1219 @param Length Length.
1220 @param Type Memory type.
1222 @retval RETURN_SUCCESS MTRR setting is appended to array.
1223 @retval RETURN_OUT_OF_RESOURCES Array is full.
1226 MtrrLibAppendVariableMtrr (
1227 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1228 IN UINT32 MtrrCapacity
,
1229 IN OUT UINT32
*MtrrCount
,
1230 IN UINT64 BaseAddress
,
1232 IN MTRR_MEMORY_CACHE_TYPE Type
1235 if (*MtrrCount
== MtrrCapacity
) {
1236 return RETURN_OUT_OF_RESOURCES
;
1239 Mtrrs
[*MtrrCount
].BaseAddress
= BaseAddress
;
1240 Mtrrs
[*MtrrCount
].Length
= Length
;
1241 Mtrrs
[*MtrrCount
].Type
= Type
;
1243 return RETURN_SUCCESS
;
1247 Return the memory type that has the least precedence.
1249 @param TypeBits Bit mask of memory type.
1251 @retval Memory type that has the least precedence.
1253 MTRR_MEMORY_CACHE_TYPE
1260 ASSERT (TypeBits
!= 0);
1261 for (Type
= 7; (INT8
)TypeBits
> 0; Type
--, TypeBits
<<= 1);
1262 return (MTRR_MEMORY_CACHE_TYPE
)Type
;
1266 Return TRUE when the Operand is exactly power of 2.
1268 @retval TRUE Operand is exactly power of 2.
1269 @retval FALSE Operand is not power of 2.
1272 MtrrLibIsPowerOfTwo (
1276 ASSERT (Operand
!= 0);
1277 return (BOOLEAN
) ((Operand
& (Operand
- 1)) == 0);
1281 Calculate the subtractive path from vertex Start to Stop.
1283 @param DefaultType Default memory type.
1284 @param A0 Alignment to use when base address is 0.
1285 @param Ranges Array holding memory type settings for all memory regions.
1286 @param RangeCount The count of memory ranges the array holds.
1287 @param VertexCount The count of vertices in the graph.
1288 @param Vertices Array holding all vertices.
1289 @param Weight 2-dimention array holding weights between vertices.
1290 @param Start Start vertex.
1291 @param Stop Stop vertex.
1292 @param Types Type bit mask of memory range from Start to Stop.
1293 @param TypeCount Number of different memory types from Start to Stop.
1294 @param Mtrrs Array holding all MTRR settings.
1295 @param MtrrCapacity Capacity of the MTRR array.
1296 @param MtrrCount The count of MTRR settings in array.
1298 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1299 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1303 MtrrLibCalculateSubtractivePath (
1304 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1306 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1307 IN UINTN RangeCount
,
1308 IN UINT16 VertexCount
,
1309 IN MTRR_LIB_ADDRESS
*Vertices
,
1310 IN OUT UINT8
*Weight
,
1315 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
, OPTIONAL
1316 IN UINT32 MtrrCapacity
, OPTIONAL
1317 IN OUT UINT32
*MtrrCount OPTIONAL
1320 RETURN_STATUS Status
;
1323 UINT8 PrecedentTypes
;
1332 MTRR_MEMORY_CACHE_TYPE LowestType
;
1333 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType
;
1335 Base
= Vertices
[Start
].Address
;
1336 Length
= Vertices
[Stop
].Address
- Base
;
1338 LowestType
= MtrrLibLowestType (Types
);
1341 // Clear the lowest type (highest bit) to get the precedent types
1343 PrecedentTypes
= ~(1 << LowestType
) & Types
;
1344 LowestPrecedentType
= MtrrLibLowestType (PrecedentTypes
);
1346 if (Mtrrs
== NULL
) {
1347 Weight
[M(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 0 : 1);
1348 Weight
[O(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 1 : 0);
1351 // Add all high level ranges
1354 for (Index
= 0; Index
< RangeCount
; Index
++) {
1358 if ((Base
< Ranges
[Index
].BaseAddress
) || (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
<= Base
)) {
1363 // Base is in the Range[Index]
1365 if (Base
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1366 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Base
;
1370 if (((1 << Ranges
[Index
].Type
) & PrecedentTypes
) != 0) {
1372 // Meet a range whose types take precedence.
1373 // Update the [HBase, HBase + HLength) to include the range,
1374 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1376 if (HBase
== MAX_UINT64
) {
1379 HLength
+= SubLength
;
1383 Length
-= SubLength
;
1389 if ((Ranges
[Index
].Type
== LowestType
) || (Length
== 0)) { // meet low type or end
1392 // Add the MTRRs for each high priority type range
1393 // the range[HBase, HBase + HLength) contains only two types.
1394 // We might use positive or subtractive, depending on which way uses less MTRR
1396 for (SubStart
= Start
; SubStart
<= Stop
; SubStart
++) {
1397 if (Vertices
[SubStart
].Address
== HBase
) {
1402 for (SubStop
= SubStart
; SubStop
<= Stop
; SubStop
++) {
1403 if (Vertices
[SubStop
].Address
== HBase
+ HLength
) {
1407 ASSERT (Vertices
[SubStart
].Address
== HBase
);
1408 ASSERT (Vertices
[SubStop
].Address
== HBase
+ HLength
);
1410 if ((TypeCount
== 2) || (SubStart
== SubStop
- 1)) {
1412 // add subtractive MTRRs for [HBase, HBase + HLength)
1413 // [HBase, HBase + HLength) contains only one type.
1414 // while - loop is to split the range to MTRR - compliant aligned range.
1416 if (Mtrrs
== NULL
) {
1417 Weight
[M (Start
, Stop
)] += (UINT8
)(SubStop
- SubStart
);
1419 while (SubStart
!= SubStop
) {
1420 Status
= MtrrLibAppendVariableMtrr (
1421 Mtrrs
, MtrrCapacity
, MtrrCount
,
1422 Vertices
[SubStart
].Address
, Vertices
[SubStart
].Length
, Vertices
[SubStart
].Type
1424 if (RETURN_ERROR (Status
)) {
1431 ASSERT (TypeCount
== 3);
1432 MtrrLibCalculateLeastMtrrs (VertexCount
, Vertices
, Weight
, SubStart
, SubStop
, TRUE
);
1434 if (Mtrrs
== NULL
) {
1435 Weight
[M (Start
, Stop
)] += Vertices
[SubStop
].Weight
;
1437 // When we need to collect the optimal path from SubStart to SubStop
1438 while (SubStop
!= SubStart
) {
1440 Pre
= Vertices
[Cur
].Previous
;
1443 if (Weight
[M (Pre
, Cur
)] + Weight
[O (Pre
, Cur
)] != 0) {
1444 Status
= MtrrLibAppendVariableMtrr (
1445 Mtrrs
, MtrrCapacity
, MtrrCount
,
1446 Vertices
[Pre
].Address
, Vertices
[Cur
].Address
- Vertices
[Pre
].Address
,
1447 (Pre
!= Cur
- 1) ? LowestPrecedentType
: Vertices
[Pre
].Type
1449 if (RETURN_ERROR (Status
)) {
1453 if (Pre
!= Cur
- 1) {
1454 Status
= MtrrLibCalculateSubtractivePath (
1457 VertexCount
, Vertices
, Weight
,
1458 Pre
, Cur
, PrecedentTypes
, 2,
1459 Mtrrs
, MtrrCapacity
, MtrrCount
1461 if (RETURN_ERROR (Status
)) {
1470 // Reset HBase, HLength
1476 return RETURN_SUCCESS
;
1480 Calculate MTRR settings to cover the specified memory ranges.
1482 @param DefaultType Default memory type.
1483 @param A0 Alignment to use when base address is 0.
1484 @param Ranges Memory range array holding the memory type
1485 settings for all memory address.
1486 @param RangeCount Count of memory ranges.
1487 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1488 This is an optional parameter that may be NULL.
1489 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1490 It may be updated to the actual required size when the calculation
1491 needs more scratch buffer.
1492 @param Mtrrs Array holding all MTRR settings.
1493 @param MtrrCapacity Capacity of the MTRR array.
1494 @param MtrrCount The count of MTRR settings in array.
1496 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1497 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1498 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1501 MtrrLibCalculateMtrrs (
1502 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1504 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1505 IN UINTN RangeCount
,
1507 IN OUT UINTN
*ScratchSize
,
1508 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1509 IN UINT32 MtrrCapacity
,
1510 IN OUT UINT32
*MtrrCount
1520 MTRR_LIB_ADDRESS
*Vertices
;
1524 UINTN RequiredScratchSize
;
1529 RETURN_STATUS Status
;
1531 Base0
= Ranges
[0].BaseAddress
;
1532 Base1
= Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
;
1533 MTRR_LIB_ASSERT_ALIGNED (Base0
, Base1
- Base0
);
1536 // Count the number of vertices.
1538 Vertices
= (MTRR_LIB_ADDRESS
*)Scratch
;
1539 for (VertexIndex
= 0, Index
= 0; Index
< RangeCount
; Index
++) {
1540 Base
= Ranges
[Index
].BaseAddress
;
1541 Length
= Ranges
[Index
].Length
;
1542 while (Length
!= 0) {
1543 Alignment
= MtrrLibBiggestAlignment (Base
, A0
);
1544 SubLength
= Alignment
;
1545 if (SubLength
> Length
) {
1546 SubLength
= GetPowerOfTwo64 (Length
);
1548 if (VertexIndex
< *ScratchSize
/ sizeof (*Vertices
)) {
1549 Vertices
[VertexIndex
].Address
= Base
;
1550 Vertices
[VertexIndex
].Alignment
= Alignment
;
1551 Vertices
[VertexIndex
].Type
= Ranges
[Index
].Type
;
1552 Vertices
[VertexIndex
].Length
= SubLength
;
1555 Length
-= SubLength
;
1560 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1562 VertexCount
= VertexIndex
+ 1;
1564 DEBUG_CACHE
, " Count of vertices (%016llx - %016llx) = %d\n",
1565 Ranges
[0].BaseAddress
, Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
, VertexCount
1567 ASSERT (VertexCount
< MAX_UINT16
);
1569 RequiredScratchSize
= VertexCount
* sizeof (*Vertices
) + VertexCount
* VertexCount
* sizeof (*Weight
);
1570 if (*ScratchSize
< RequiredScratchSize
) {
1571 *ScratchSize
= RequiredScratchSize
;
1572 return RETURN_BUFFER_TOO_SMALL
;
1574 Vertices
[VertexCount
- 1].Address
= Base1
;
1576 Weight
= (UINT8
*) &Vertices
[VertexCount
];
1577 for (VertexIndex
= 0; VertexIndex
< VertexCount
; VertexIndex
++) {
1579 // Set optional weight between vertices and self->self to 0
1581 SetMem (&Weight
[M(VertexIndex
, 0)], VertexIndex
+ 1, 0);
1583 // Set mandatory weight between vertices to MAX_WEIGHT
1585 SetMem (&Weight
[M (VertexIndex
, VertexIndex
+ 1)], VertexCount
- VertexIndex
- 1, MAX_WEIGHT
);
1587 // Final result looks like:
1595 // Set mandatory weight and optional weight for adjacent vertices
1597 for (VertexIndex
= 0; VertexIndex
< VertexCount
- 1; VertexIndex
++) {
1598 if (Vertices
[VertexIndex
].Type
!= DefaultType
) {
1599 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 1;
1600 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 0;
1602 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 0;
1603 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 1;
1607 for (TypeCount
= 2; TypeCount
<= 3; TypeCount
++) {
1608 for (Start
= 0; Start
< VertexCount
; Start
++) {
1609 for (Stop
= Start
+ 2; Stop
< VertexCount
; Stop
++) {
1610 ASSERT (Vertices
[Stop
].Address
> Vertices
[Start
].Address
);
1611 Length
= Vertices
[Stop
].Address
- Vertices
[Start
].Address
;
1612 if (Length
> Vertices
[Start
].Alignment
) {
1614 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1618 if ((Weight
[M(Start
, Stop
)] == MAX_WEIGHT
) && MtrrLibIsPowerOfTwo (Length
)) {
1619 if (MtrrLibGetNumberOfTypes (
1620 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1623 // Update the Weight[Start, Stop] using subtractive path.
1625 MtrrLibCalculateSubtractivePath (
1628 (UINT16
)VertexCount
, Vertices
, Weight
,
1629 Start
, Stop
, Type
, TypeCount
,
1632 } else if (TypeCount
== 2) {
1634 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1635 // Because no matter how Stop is increased, we always meet 3-type range.
1644 Status
= RETURN_SUCCESS
;
1645 MtrrLibCalculateLeastMtrrs ((UINT16
) VertexCount
, Vertices
, Weight
, 0, (UINT16
) VertexCount
- 1, FALSE
);
1646 Stop
= (UINT16
) VertexCount
- 1;
1648 Start
= Vertices
[Stop
].Previous
;
1649 TypeCount
= MAX_UINT8
;
1651 if (Weight
[M(Start
, Stop
)] != 0) {
1652 TypeCount
= MtrrLibGetNumberOfTypes (Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
);
1653 Status
= MtrrLibAppendVariableMtrr (
1654 Mtrrs
, MtrrCapacity
, MtrrCount
,
1655 Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1656 MtrrLibLowestType (Type
)
1658 if (RETURN_ERROR (Status
)) {
1663 if (Start
!= Stop
- 1) {
1665 // substractive path
1667 if (TypeCount
== MAX_UINT8
) {
1668 TypeCount
= MtrrLibGetNumberOfTypes (
1669 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1672 Status
= MtrrLibCalculateSubtractivePath (
1675 (UINT16
) VertexCount
, Vertices
, Weight
, Start
, Stop
,
1677 Mtrrs
, MtrrCapacity
, MtrrCount
1679 if (RETURN_ERROR (Status
)) {
1690 Apply the fixed MTRR settings to memory range array.
1692 @param Fixed The fixed MTRR settings.
1693 @param Ranges Return the memory range array holding memory type
1694 settings for all memory address.
1695 @param RangeCapacity The capacity of memory range array.
1696 @param RangeCount Return the count of memory range.
1698 @retval RETURN_SUCCESS The memory range array is returned successfully.
1699 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1702 MtrrLibApplyFixedMtrrs (
1703 IN MTRR_FIXED_SETTINGS
*Fixed
,
1704 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1705 IN UINTN RangeCapacity
,
1706 IN OUT UINTN
*RangeCount
1709 RETURN_STATUS Status
;
1712 MTRR_MEMORY_CACHE_TYPE MemoryType
;
1716 for (MsrIndex
= 0; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
1717 ASSERT (Base
== mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
);
1718 for (Index
= 0; Index
< sizeof (UINT64
); Index
++) {
1719 MemoryType
= (MTRR_MEMORY_CACHE_TYPE
)((UINT8
*)(&Fixed
->Mtrr
[MsrIndex
]))[Index
];
1720 Status
= MtrrLibSetMemoryType (
1721 Ranges
, RangeCapacity
, RangeCount
, Base
, mMtrrLibFixedMtrrTable
[MsrIndex
].Length
, MemoryType
1723 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1726 Base
+= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
1729 ASSERT (Base
== BASE_1MB
);
1730 return RETURN_SUCCESS
;
1734 Apply the variable MTRR settings to memory range array.
1736 @param VariableMtrr The variable MTRR array.
1737 @param VariableMtrrCount The count of variable MTRRs.
1738 @param Ranges Return the memory range array with new MTRR settings applied.
1739 @param RangeCapacity The capacity of memory range array.
1740 @param RangeCount Return the count of memory range.
1742 @retval RETURN_SUCCESS The memory range array is returned successfully.
1743 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1746 MtrrLibApplyVariableMtrrs (
1747 IN CONST MTRR_MEMORY_RANGE
*VariableMtrr
,
1748 IN UINT32 VariableMtrrCount
,
1749 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1750 IN UINTN RangeCapacity
,
1751 IN OUT UINTN
*RangeCount
1754 RETURN_STATUS Status
;
1760 // UC > * (except WB, UC) > WB
1766 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1767 if ((VariableMtrr
[Index
].Length
!= 0) && (VariableMtrr
[Index
].Type
== CacheWriteBack
)) {
1768 Status
= MtrrLibSetMemoryType (
1769 Ranges
, RangeCapacity
, RangeCount
,
1770 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1772 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1779 // 2. Set other types than WB or UC
1781 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1782 if ((VariableMtrr
[Index
].Length
!= 0) &&
1783 (VariableMtrr
[Index
].Type
!= CacheWriteBack
) && (VariableMtrr
[Index
].Type
!= CacheUncacheable
)) {
1784 Status
= MtrrLibSetMemoryType (
1785 Ranges
, RangeCapacity
, RangeCount
,
1786 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1788 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1797 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1798 if (VariableMtrr
[Index
].Length
!= 0 && VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1799 Status
= MtrrLibSetMemoryType (
1800 Ranges
, RangeCapacity
, RangeCount
,
1801 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1803 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1808 return RETURN_SUCCESS
;
1812 Return the memory type bit mask that's compatible to first type in the Ranges.
1814 @param Ranges Memory range array holding the memory type
1815 settings for all memory address.
1816 @param RangeCount Count of memory ranges.
1818 @return Compatible memory type bit mask.
1821 MtrrLibGetCompatibleTypes (
1822 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1826 ASSERT (RangeCount
!= 0);
1828 switch (Ranges
[0].Type
) {
1829 case CacheWriteBack
:
1830 case CacheWriteThrough
:
1831 return (1 << CacheWriteBack
) | (1 << CacheWriteThrough
) | (1 << CacheUncacheable
);
1834 case CacheWriteCombining
:
1835 case CacheWriteProtected
:
1836 return (1 << Ranges
[0].Type
) | (1 << CacheUncacheable
);
1839 case CacheUncacheable
:
1840 if (RangeCount
== 1) {
1841 return (1 << CacheUncacheable
);
1843 return MtrrLibGetCompatibleTypes (&Ranges
[1], RangeCount
- 1);
1855 Overwrite the destination MTRR settings with the source MTRR settings.
1856 This routine is to make sure the modification to destination MTRR settings
1857 is as small as possible.
1859 @param DstMtrrs Destination MTRR settings.
1860 @param DstMtrrCount Count of destination MTRR settings.
1861 @param SrcMtrrs Source MTRR settings.
1862 @param SrcMtrrCount Count of source MTRR settings.
1863 @param Modified Flag array to indicate which destination MTRR setting is modified.
1866 MtrrLibMergeVariableMtrr (
1867 MTRR_MEMORY_RANGE
*DstMtrrs
,
1868 UINT32 DstMtrrCount
,
1869 MTRR_MEMORY_RANGE
*SrcMtrrs
,
1870 UINT32 SrcMtrrCount
,
1877 ASSERT (SrcMtrrCount
<= DstMtrrCount
);
1879 for (DstIndex
= 0; DstIndex
< DstMtrrCount
; DstIndex
++) {
1880 Modified
[DstIndex
] = FALSE
;
1882 if (DstMtrrs
[DstIndex
].Length
== 0) {
1885 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1886 if (DstMtrrs
[DstIndex
].BaseAddress
== SrcMtrrs
[SrcIndex
].BaseAddress
&&
1887 DstMtrrs
[DstIndex
].Length
== SrcMtrrs
[SrcIndex
].Length
&&
1888 DstMtrrs
[DstIndex
].Type
== SrcMtrrs
[SrcIndex
].Type
) {
1893 if (SrcIndex
== SrcMtrrCount
) {
1895 // Remove the one from DstMtrrs which is not in SrcMtrrs
1897 DstMtrrs
[DstIndex
].Length
= 0;
1898 Modified
[DstIndex
] = TRUE
;
1901 // Remove the one from SrcMtrrs which is also in DstMtrrs
1903 SrcMtrrs
[SrcIndex
].Length
= 0;
1908 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1909 // Merge MTRRs from SrcMtrrs to DstMtrrs
1912 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1913 if (SrcMtrrs
[SrcIndex
].Length
!= 0) {
1916 // Find the empty slot in DstMtrrs
1918 while (DstIndex
< DstMtrrCount
) {
1919 if (DstMtrrs
[DstIndex
].Length
== 0) {
1924 ASSERT (DstIndex
< DstMtrrCount
);
1925 CopyMem (&DstMtrrs
[DstIndex
], &SrcMtrrs
[SrcIndex
], sizeof (SrcMtrrs
[0]));
1926 Modified
[DstIndex
] = TRUE
;
1932 Calculate the variable MTRR settings for all memory ranges.
1934 @param DefaultType Default memory type.
1935 @param A0 Alignment to use when base address is 0.
1936 @param Ranges Memory range array holding the memory type
1937 settings for all memory address.
1938 @param RangeCount Count of memory ranges.
1939 @param Scratch Scratch buffer to be used in MTRR calculation.
1940 @param ScratchSize Pointer to the size of scratch buffer.
1941 @param VariableMtrr Array holding all MTRR settings.
1942 @param VariableMtrrCapacity Capacity of the MTRR array.
1943 @param VariableMtrrCount The count of MTRR settings in array.
1945 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1946 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1947 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1948 The required scratch buffer size is returned through ScratchSize.
1951 MtrrLibSetMemoryRanges (
1952 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1954 IN MTRR_MEMORY_RANGE
*Ranges
,
1955 IN UINTN RangeCount
,
1957 IN OUT UINTN
*ScratchSize
,
1958 OUT MTRR_MEMORY_RANGE
*VariableMtrr
,
1959 IN UINT32 VariableMtrrCapacity
,
1960 OUT UINT32
*VariableMtrrCount
1963 RETURN_STATUS Status
;
1968 UINT8 CompatibleTypes
;
1971 UINTN ActualScratchSize
;
1972 UINTN BiggestScratchSize
;
1974 *VariableMtrrCount
= 0;
1977 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
1978 // Each call needs different scratch buffer size.
1979 // When the provided scratch buffer size is not sufficient in any call,
1980 // set the GetActualScratchSize to TRUE, and following calls will only
1981 // calculate the actual scratch size for the caller.
1983 BiggestScratchSize
= 0;
1985 for (Index
= 0; Index
< RangeCount
;) {
1986 Base0
= Ranges
[Index
].BaseAddress
;
1989 // Full step is optimal
1991 while (Index
< RangeCount
) {
1992 ASSERT (Ranges
[Index
].BaseAddress
== Base0
);
1993 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
1994 while (Base0
+ Alignment
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1995 if ((BiggestScratchSize
<= *ScratchSize
) && (Ranges
[Index
].Type
!= DefaultType
)) {
1996 Status
= MtrrLibAppendVariableMtrr (
1997 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
1998 Base0
, Alignment
, Ranges
[Index
].Type
2000 if (RETURN_ERROR (Status
)) {
2005 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2009 // Remove the above range from Ranges[Index]
2011 Ranges
[Index
].Length
-= Base0
- Ranges
[Index
].BaseAddress
;
2012 Ranges
[Index
].BaseAddress
= Base0
;
2013 if (Ranges
[Index
].Length
!= 0) {
2020 if (Index
== RangeCount
) {
2025 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2026 // Per SDM, the compatible types between[B0, B1) are:
2031 CompatibleTypes
= MtrrLibGetCompatibleTypes (&Ranges
[Index
], RangeCount
- Index
);
2033 End
= Index
; // End points to last one that matches the CompatibleTypes.
2034 while (End
+ 1 < RangeCount
) {
2035 if (((1 << Ranges
[End
+ 1].Type
) & CompatibleTypes
) == 0) {
2040 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2041 Length
= GetPowerOfTwo64 (Ranges
[End
].BaseAddress
+ Ranges
[End
].Length
- Base0
);
2042 Base1
= Base0
+ MIN (Alignment
, Length
);
2045 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2048 while (End
+ 1 < RangeCount
) {
2049 if (Base1
<= Ranges
[End
+ 1].BaseAddress
) {
2055 Length
= Ranges
[End
].Length
;
2056 Ranges
[End
].Length
= Base1
- Ranges
[End
].BaseAddress
;
2057 ActualScratchSize
= *ScratchSize
;
2058 Status
= MtrrLibCalculateMtrrs (
2060 &Ranges
[Index
], End
+ 1 - Index
,
2061 Scratch
, &ActualScratchSize
,
2062 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
2064 if (Status
== RETURN_BUFFER_TOO_SMALL
) {
2065 BiggestScratchSize
= MAX (BiggestScratchSize
, ActualScratchSize
);
2067 // Ignore this error, because we need to calculate the biggest
2068 // scratch buffer size.
2070 Status
= RETURN_SUCCESS
;
2072 if (RETURN_ERROR (Status
)) {
2076 if (Length
!= Ranges
[End
].Length
) {
2077 Ranges
[End
].BaseAddress
= Base1
;
2078 Ranges
[End
].Length
= Length
- Ranges
[End
].Length
;
2085 if (*ScratchSize
< BiggestScratchSize
) {
2086 *ScratchSize
= BiggestScratchSize
;
2087 return RETURN_BUFFER_TOO_SMALL
;
2089 return RETURN_SUCCESS
;
2093 Set the below-1MB memory attribute to fixed MTRR buffer.
2094 Modified flag array indicates which fixed MTRR is modified.
2096 @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
2097 @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
2098 @param [in] BaseAddress Base address.
2099 @param [in] Length Length.
2100 @param [in] Type Memory type.
2102 @retval RETURN_SUCCESS The memory attribute is set successfully.
2103 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2104 for the fixed MTRRs.
2107 MtrrLibSetBelow1MBMemoryAttribute (
2108 IN OUT UINT64
*ClearMasks
,
2109 IN OUT UINT64
*OrMasks
,
2110 IN PHYSICAL_ADDRESS BaseAddress
,
2112 IN MTRR_MEMORY_CACHE_TYPE Type
2115 RETURN_STATUS Status
;
2120 ASSERT (BaseAddress
< BASE_1MB
);
2122 MsrIndex
= (UINT32
)-1;
2123 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
2124 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
2125 if (RETURN_ERROR (Status
)) {
2128 ClearMasks
[MsrIndex
] = ClearMasks
[MsrIndex
] | ClearMask
;
2129 OrMasks
[MsrIndex
] = (OrMasks
[MsrIndex
] & ~ClearMask
) | OrMask
;
2131 return RETURN_SUCCESS
;
2135 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2137 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2138 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2139 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2140 It may be updated to the actual required size when the calculation
2141 needs more scratch buffer.
2142 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2143 When range overlap happens, the last one takes higher priority.
2144 When the function returns, either all the attributes are set successfully,
2145 or none of them is set.
2146 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2148 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2149 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2150 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2151 memory resource range specified by BaseAddress and Length in any range.
2152 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2153 range specified by BaseAddress and Length in any range.
2154 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2155 the memory resource ranges.
2156 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2157 BaseAddress and Length cannot be modified.
2158 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2162 MtrrSetMemoryAttributesInMtrrSettings (
2163 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2165 IN OUT UINTN
*ScratchSize
,
2166 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
2170 RETURN_STATUS Status
;
2174 BOOLEAN Above1MbExist
;
2176 UINT64 MtrrValidBitsMask
;
2177 UINT64 MtrrValidAddressMask
;
2178 MTRR_MEMORY_CACHE_TYPE DefaultType
;
2179 MTRR_VARIABLE_SETTINGS VariableSettings
;
2180 MTRR_MEMORY_RANGE WorkingRanges
[2 * ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
) + 2];
2181 UINTN WorkingRangeCount
;
2183 MTRR_VARIABLE_SETTING VariableSetting
;
2184 UINT32 OriginalVariableMtrrCount
;
2185 UINT32 FirmwareVariableMtrrCount
;
2186 UINT32 WorkingVariableMtrrCount
;
2187 MTRR_MEMORY_RANGE OriginalVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2188 MTRR_MEMORY_RANGE WorkingVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2189 BOOLEAN VariableSettingModified
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2191 UINT64 ClearMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2192 UINT64 OrMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2194 MTRR_CONTEXT MtrrContext
;
2195 BOOLEAN MtrrContextValid
;
2197 Status
= RETURN_SUCCESS
;
2198 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2201 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2203 SetMem (VariableSettingModified
, ARRAY_SIZE (VariableSettingModified
), FALSE
);
2206 // TRUE indicating the caller requests to set variable MTRRs.
2208 Above1MbExist
= FALSE
;
2209 OriginalVariableMtrrCount
= 0;
2212 // 0. Dump the requests.
2215 DEBUG ((DEBUG_CACHE
, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2216 (MtrrSetting
== NULL
) ? "Hardware" : "Buffer", *ScratchSize
,
2217 (RangeCount
<= 1) ? "," : "\n"
2219 for (Index
= 0; Index
< RangeCount
; Index
++) {
2220 DEBUG ((DEBUG_CACHE
, " %a: [%016lx, %016lx)\n",
2221 mMtrrMemoryCacheTypeShortName
[MIN (Ranges
[Index
].Type
, CacheInvalid
)],
2222 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
2228 // 1. Validate the parameters.
2230 if (!IsMtrrSupported ()) {
2231 Status
= RETURN_UNSUPPORTED
;
2235 for (Index
= 0; Index
< RangeCount
; Index
++) {
2236 if (Ranges
[Index
].Length
== 0) {
2237 Status
= RETURN_INVALID_PARAMETER
;
2240 if (((Ranges
[Index
].BaseAddress
& ~MtrrValidAddressMask
) != 0) ||
2241 ((((Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) & ~MtrrValidAddressMask
) != 0) &&
2242 (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) != MtrrValidBitsMask
+ 1)
2245 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2246 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2248 Status
= RETURN_UNSUPPORTED
;
2251 if ((Ranges
[Index
].Type
!= CacheUncacheable
) &&
2252 (Ranges
[Index
].Type
!= CacheWriteCombining
) &&
2253 (Ranges
[Index
].Type
!= CacheWriteThrough
) &&
2254 (Ranges
[Index
].Type
!= CacheWriteProtected
) &&
2255 (Ranges
[Index
].Type
!= CacheWriteBack
)) {
2256 Status
= RETURN_INVALID_PARAMETER
;
2259 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
> BASE_1MB
) {
2260 Above1MbExist
= TRUE
;
2265 // 2. Apply the above-1MB memory attribute settings.
2267 if (Above1MbExist
) {
2269 // 2.1. Read all variable MTRRs and convert to Ranges.
2271 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
2272 MtrrGetVariableMtrrWorker (MtrrSetting
, OriginalVariableMtrrCount
, &VariableSettings
);
2273 MtrrLibGetRawVariableRanges (
2274 &VariableSettings
, OriginalVariableMtrrCount
,
2275 MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
2278 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
2279 WorkingRangeCount
= 1;
2280 WorkingRanges
[0].BaseAddress
= 0;
2281 WorkingRanges
[0].Length
= MtrrValidBitsMask
+ 1;
2282 WorkingRanges
[0].Type
= DefaultType
;
2284 Status
= MtrrLibApplyVariableMtrrs (
2285 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2286 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
);
2287 ASSERT_RETURN_ERROR (Status
);
2289 ASSERT (OriginalVariableMtrrCount
>= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
));
2290 FirmwareVariableMtrrCount
= OriginalVariableMtrrCount
- PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
2291 ASSERT (WorkingRangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
2294 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2296 Status
= MtrrLibSetMemoryType (
2297 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2298 0, SIZE_1MB
, CacheUncacheable
2300 ASSERT (Status
!= RETURN_OUT_OF_RESOURCES
);
2303 // 2.3. Apply the new memory attribute settings to Ranges.
2306 for (Index
= 0; Index
< RangeCount
; Index
++) {
2307 BaseAddress
= Ranges
[Index
].BaseAddress
;
2308 Length
= Ranges
[Index
].Length
;
2309 if (BaseAddress
< BASE_1MB
) {
2310 if (Length
<= BASE_1MB
- BaseAddress
) {
2313 Length
-= BASE_1MB
- BaseAddress
;
2314 BaseAddress
= BASE_1MB
;
2316 Status
= MtrrLibSetMemoryType (
2317 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2318 BaseAddress
, Length
, Ranges
[Index
].Type
2320 if (Status
== RETURN_ALREADY_STARTED
) {
2321 Status
= RETURN_SUCCESS
;
2322 } else if (Status
== RETURN_OUT_OF_RESOURCES
) {
2325 ASSERT_RETURN_ERROR (Status
);
2332 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2333 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2335 Status
= MtrrLibSetMemoryRanges (
2336 DefaultType
, LShiftU64 (1, (UINTN
)HighBitSet64 (MtrrValidBitsMask
)), WorkingRanges
, WorkingRangeCount
,
2337 Scratch
, ScratchSize
,
2338 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
2340 if (RETURN_ERROR (Status
)) {
2345 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2347 for (Index
= 0; Index
< WorkingVariableMtrrCount
; Index
++) {
2348 if (WorkingVariableMtrr
[Index
].BaseAddress
== 0 && WorkingVariableMtrr
[Index
].Length
== SIZE_1MB
) {
2349 ASSERT (WorkingVariableMtrr
[Index
].Type
== CacheUncacheable
);
2350 WorkingVariableMtrrCount
--;
2352 &WorkingVariableMtrr
[Index
], &WorkingVariableMtrr
[Index
+ 1],
2353 (WorkingVariableMtrrCount
- Index
) * sizeof (WorkingVariableMtrr
[0])
2359 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
2360 Status
= RETURN_OUT_OF_RESOURCES
;
2365 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2366 // Make sure least modification is made to OriginalVariableMtrr.
2368 MtrrLibMergeVariableMtrr (
2369 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2370 WorkingVariableMtrr
, WorkingVariableMtrrCount
,
2371 VariableSettingModified
2377 // 3. Apply the below-1MB memory attribute settings.
2379 // (Value & ~0 | 0) still equals to (Value)
2381 ZeroMem (ClearMasks
, sizeof (ClearMasks
));
2382 ZeroMem (OrMasks
, sizeof (OrMasks
));
2383 for (Index
= 0; Index
< RangeCount
; Index
++) {
2384 if (Ranges
[Index
].BaseAddress
>= BASE_1MB
) {
2388 Status
= MtrrLibSetBelow1MBMemoryAttribute (
2389 ClearMasks
, OrMasks
,
2390 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
, Ranges
[Index
].Type
2392 if (RETURN_ERROR (Status
)) {
2397 MtrrContextValid
= FALSE
;
2399 // 4. Write fixed MTRRs that have been modified
2401 for (Index
= 0; Index
< ARRAY_SIZE (ClearMasks
); Index
++) {
2402 if (ClearMasks
[Index
] != 0) {
2403 if (MtrrSetting
!= NULL
) {
2404 MtrrSetting
->Fixed
.Mtrr
[Index
] = (MtrrSetting
->Fixed
.Mtrr
[Index
] & ~ClearMasks
[Index
]) | OrMasks
[Index
];
2406 if (!MtrrContextValid
) {
2407 MtrrLibPreMtrrChange (&MtrrContext
);
2408 MtrrContextValid
= TRUE
;
2410 AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
, ~ClearMasks
[Index
], OrMasks
[Index
]);
2416 // 5. Write variable MTRRs that have been modified
2418 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2419 if (VariableSettingModified
[Index
]) {
2420 if (OriginalVariableMtrr
[Index
].Length
!= 0) {
2421 VariableSetting
.Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
)
2422 | (UINT8
)OriginalVariableMtrr
[Index
].Type
;
2423 VariableSetting
.Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2425 VariableSetting
.Base
= 0;
2426 VariableSetting
.Mask
= 0;
2428 if (MtrrSetting
!= NULL
) {
2429 CopyMem (&MtrrSetting
->Variables
.Mtrr
[Index
], &VariableSetting
, sizeof (VariableSetting
));
2431 if (!MtrrContextValid
) {
2432 MtrrLibPreMtrrChange (&MtrrContext
);
2433 MtrrContextValid
= TRUE
;
2436 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2437 VariableSetting
.Base
2440 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2441 VariableSetting
.Mask
2447 if (MtrrSetting
!= NULL
) {
2448 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2449 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
2451 if (MtrrContextValid
) {
2452 MtrrLibPostMtrrChange (&MtrrContext
);
2457 DEBUG ((DEBUG_CACHE
, " Result = %r\n", Status
));
2458 if (!RETURN_ERROR (Status
)) {
2459 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2465 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2467 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2468 @param[in] BaseAddress The physical address that is the start address
2470 @param[in] Length The size in bytes of the memory range.
2471 @param[in] Attribute The bit mask of attributes to set for the
2474 @retval RETURN_SUCCESS The attributes were set for the memory range.
2475 @retval RETURN_INVALID_PARAMETER Length is zero.
2476 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2477 memory resource range specified by BaseAddress and Length.
2478 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2479 range specified by BaseAddress and Length.
2480 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2481 BaseAddress and Length cannot be modified.
2482 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2483 the memory resource range.
2484 Multiple memory range attributes setting by calling this API multiple
2485 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2486 the number of CPU MTRRs are too small to set such memory attributes.
2487 Pass the multiple memory range attributes to one call of
2488 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2489 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2490 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2491 external scratch buffer.
2495 MtrrSetMemoryAttributeInMtrrSettings (
2496 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2497 IN PHYSICAL_ADDRESS BaseAddress
,
2499 IN MTRR_MEMORY_CACHE_TYPE Attribute
2502 UINT8 Scratch
[SCRATCH_BUFFER_SIZE
];
2504 MTRR_MEMORY_RANGE Range
;
2506 Range
.BaseAddress
= BaseAddress
;
2507 Range
.Length
= Length
;
2508 Range
.Type
= Attribute
;
2509 ScratchSize
= sizeof (Scratch
);
2510 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting
, Scratch
, &ScratchSize
, &Range
, 1);
2514 This function attempts to set the attributes for a memory range.
2516 @param[in] BaseAddress The physical address that is the start
2517 address of a memory range.
2518 @param[in] Length The size in bytes of the memory range.
2519 @param[in] Attributes The bit mask of attributes to set for the
2522 @retval RETURN_SUCCESS The attributes were set for the memory
2524 @retval RETURN_INVALID_PARAMETER Length is zero.
2525 @retval RETURN_UNSUPPORTED The processor does not support one or
2526 more bytes of the memory resource range
2527 specified by BaseAddress and Length.
2528 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2529 for the memory resource range specified
2530 by BaseAddress and Length.
2531 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2532 range specified by BaseAddress and Length
2534 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2535 modify the attributes of the memory
2537 Multiple memory range attributes setting by calling this API multiple
2538 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2539 the number of CPU MTRRs are too small to set such memory attributes.
2540 Pass the multiple memory range attributes to one call of
2541 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2542 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2543 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2544 external scratch buffer.
2548 MtrrSetMemoryAttribute (
2549 IN PHYSICAL_ADDRESS BaseAddress
,
2551 IN MTRR_MEMORY_CACHE_TYPE Attribute
2554 return MtrrSetMemoryAttributeInMtrrSettings (NULL
, BaseAddress
, Length
, Attribute
);
2558 Worker function setting variable MTRRs
2560 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2564 MtrrSetVariableMtrrWorker (
2565 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2569 UINT32 VariableMtrrCount
;
2571 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2572 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
2574 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2576 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2577 VariableSettings
->Mtrr
[Index
].Base
2580 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2581 VariableSettings
->Mtrr
[Index
].Mask
2588 This function sets variable MTRRs
2590 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2592 @return The pointer of VariableSettings
2595 MTRR_VARIABLE_SETTINGS
*
2597 MtrrSetVariableMtrr (
2598 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2601 MTRR_CONTEXT MtrrContext
;
2603 if (!IsMtrrSupported ()) {
2604 return VariableSettings
;
2607 MtrrLibPreMtrrChange (&MtrrContext
);
2608 MtrrSetVariableMtrrWorker (VariableSettings
);
2609 MtrrLibPostMtrrChange (&MtrrContext
);
2610 MtrrDebugPrintAllMtrrs ();
2612 return VariableSettings
;
2616 Worker function setting fixed MTRRs
2618 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2622 MtrrSetFixedMtrrWorker (
2623 IN MTRR_FIXED_SETTINGS
*FixedSettings
2628 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2630 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2631 FixedSettings
->Mtrr
[Index
]
2638 This function sets fixed MTRRs
2640 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2642 @retval The pointer of FixedSettings
2645 MTRR_FIXED_SETTINGS
*
2648 IN MTRR_FIXED_SETTINGS
*FixedSettings
2651 MTRR_CONTEXT MtrrContext
;
2653 if (!IsMtrrSupported ()) {
2654 return FixedSettings
;
2657 MtrrLibPreMtrrChange (&MtrrContext
);
2658 MtrrSetFixedMtrrWorker (FixedSettings
);
2659 MtrrLibPostMtrrChange (&MtrrContext
);
2660 MtrrDebugPrintAllMtrrs ();
2662 return FixedSettings
;
2667 This function gets the content in all MTRRs (variable and fixed)
2669 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2671 @retval the pointer of MtrrSetting
2677 OUT MTRR_SETTINGS
*MtrrSetting
2680 if (!IsMtrrSupported ()) {
2687 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2690 // Get variable MTRRs
2692 MtrrGetVariableMtrrWorker (
2694 GetVariableMtrrCountWorker (),
2695 &MtrrSetting
->Variables
2699 // Get MTRR_DEF_TYPE value
2701 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2708 This function sets all MTRRs (variable and fixed)
2710 @param[in] MtrrSetting A buffer holding all MTRRs content.
2712 @retval The pointer of MtrrSetting
2718 IN MTRR_SETTINGS
*MtrrSetting
2721 MTRR_CONTEXT MtrrContext
;
2723 if (!IsMtrrSupported ()) {
2727 MtrrLibPreMtrrChange (&MtrrContext
);
2732 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2735 // Set variable MTRRs
2737 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2740 // Set MTRR_DEF_TYPE value
2742 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2744 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2751 Checks if MTRR is supported.
2753 @retval TRUE MTRR is supported.
2754 @retval FALSE MTRR is not supported.
2763 CPUID_VERSION_INFO_EDX Edx
;
2764 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2767 // Check CPUID(1).EDX[12] for MTRR capability
2769 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2770 if (Edx
.Bits
.MTRR
== 0) {
2775 // Check number of variable MTRRs and fixed MTRRs existence.
2776 // If number of variable MTRRs is zero, or fixed MTRRs do not
2777 // exist, return false.
2779 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2780 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {
2788 Worker function prints all MTRRs for debugging.
2790 If MtrrSetting is not NULL, print MTRR settings from input MTRR
2792 If MtrrSetting is NULL, print MTRR settings from MTRRs.
2794 @param MtrrSetting A buffer holding all MTRRs content.
2797 MtrrDebugPrintAllMtrrsWorker (
2798 IN MTRR_SETTINGS
*MtrrSetting
2802 MTRR_SETTINGS LocalMtrrs
;
2803 MTRR_SETTINGS
*Mtrrs
;
2806 UINT64 MtrrValidBitsMask
;
2807 UINT64 MtrrValidAddressMask
;
2808 UINT32 VariableMtrrCount
;
2809 BOOLEAN ContainVariableMtrr
;
2810 MTRR_MEMORY_RANGE Ranges
[
2811 ARRAY_SIZE (mMtrrLibFixedMtrrTable
) * sizeof (UINT64
) + 2 * ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
) + 1
2813 MTRR_MEMORY_RANGE RawVariableRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
2815 if (!IsMtrrSupported ()) {
2819 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2821 if (MtrrSetting
!= NULL
) {
2822 Mtrrs
= MtrrSetting
;
2824 MtrrGetAllMtrrs (&LocalMtrrs
);
2825 Mtrrs
= &LocalMtrrs
;
2829 // Dump RAW MTRR contents
2831 DEBUG ((DEBUG_CACHE
, "MTRR Settings:\n"));
2832 DEBUG ((DEBUG_CACHE
, "=============\n"));
2833 DEBUG ((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
2834 for (Index
= 0; Index
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); Index
++) {
2835 DEBUG ((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
2837 ContainVariableMtrr
= FALSE
;
2838 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2839 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
2841 // If mask is not valid, then do not display range
2845 ContainVariableMtrr
= TRUE
;
2846 DEBUG ((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2848 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
2849 Mtrrs
->Variables
.Mtrr
[Index
].Mask
2852 if (!ContainVariableMtrr
) {
2853 DEBUG ((DEBUG_CACHE
, "Variable MTRR : None.\n"));
2855 DEBUG((DEBUG_CACHE
, "\n"));
2858 // Dump MTRR setting in ranges
2860 DEBUG((DEBUG_CACHE
, "Memory Ranges:\n"));
2861 DEBUG((DEBUG_CACHE
, "====================================\n"));
2862 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2863 Ranges
[0].BaseAddress
= 0;
2864 Ranges
[0].Length
= MtrrValidBitsMask
+ 1;
2865 Ranges
[0].Type
= MtrrGetDefaultMemoryTypeWorker (Mtrrs
);
2868 MtrrLibGetRawVariableRanges (
2869 &Mtrrs
->Variables
, VariableMtrrCount
,
2870 MtrrValidBitsMask
, MtrrValidAddressMask
, RawVariableRanges
2872 MtrrLibApplyVariableMtrrs (
2873 RawVariableRanges
, VariableMtrrCount
,
2874 Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
2877 MtrrLibApplyFixedMtrrs (&Mtrrs
->Fixed
, Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
);
2879 for (Index
= 0; Index
< RangeCount
; Index
++) {
2880 DEBUG ((DEBUG_CACHE
, "%a:%016lx-%016lx\n",
2881 mMtrrMemoryCacheTypeShortName
[Ranges
[Index
].Type
],
2882 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- 1
2889 This function prints all MTRRs for debugging.
2893 MtrrDebugPrintAllMtrrs (
2897 MtrrDebugPrintAllMtrrsWorker (NULL
);