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 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include <Register/Cpuid.h>
21 #include <Register/Msr.h>
23 #include <Library/MtrrLib.h>
24 #include <Library/BaseLib.h>
25 #include <Library/CpuLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DebugLib.h>
29 #define OR_SEED 0x0101010101010101ull
30 #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
31 #define MAX_WEIGHT MAX_UINT8
32 #define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)
33 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
35 #define M(x,y) ((x) * VertexCount + (y))
36 #define O(x,y) ((y) * VertexCount + (x))
39 // Context to save and restore when MTRRs are programmed
43 BOOLEAN InterruptState
;
50 MTRR_MEMORY_CACHE_TYPE Type
: 7;
53 // Temprary use for calculating the best MTRR settings.
61 // This table defines the offset, base and length of the fixed MTRRs
63 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
65 MSR_IA32_MTRR_FIX64K_00000
,
70 MSR_IA32_MTRR_FIX16K_80000
,
75 MSR_IA32_MTRR_FIX16K_A0000
,
80 MSR_IA32_MTRR_FIX4K_C0000
,
85 MSR_IA32_MTRR_FIX4K_C8000
,
90 MSR_IA32_MTRR_FIX4K_D0000
,
95 MSR_IA32_MTRR_FIX4K_D8000
,
100 MSR_IA32_MTRR_FIX4K_E0000
,
105 MSR_IA32_MTRR_FIX4K_E8000
,
110 MSR_IA32_MTRR_FIX4K_F0000
,
115 MSR_IA32_MTRR_FIX4K_F8000
,
122 // Lookup table used to print MTRRs
124 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
125 "UC", // CacheUncacheable
126 "WC", // CacheWriteCombining
129 "WT", // CacheWriteThrough
130 "WP", // CacheWriteProtected
131 "WB", // CacheWriteBack
137 Worker function prints all MTRRs for debugging.
139 If MtrrSetting is not NULL, print MTRR settings from input MTRR
141 If MtrrSetting is NULL, print MTRR settings from MTRRs.
143 @param MtrrSetting A buffer holding all MTRRs content.
146 MtrrDebugPrintAllMtrrsWorker (
147 IN MTRR_SETTINGS
*MtrrSetting
151 Worker function returns the variable MTRR count for the CPU.
153 @return Variable MTRR count
157 GetVariableMtrrCountWorker (
161 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
163 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
164 ASSERT (MtrrCap
.Bits
.VCNT
<= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS
*) 0)->Mtrr
));
165 return MtrrCap
.Bits
.VCNT
;
169 Returns the variable MTRR count for the CPU.
171 @return Variable MTRR count
176 GetVariableMtrrCount (
180 if (!IsMtrrSupported ()) {
183 return GetVariableMtrrCountWorker ();
187 Worker function returns the firmware usable variable MTRR count for the CPU.
189 @return Firmware usable variable MTRR count
193 GetFirmwareVariableMtrrCountWorker (
197 UINT32 VariableMtrrCount
;
198 UINT32 ReservedMtrrNumber
;
200 VariableMtrrCount
= GetVariableMtrrCountWorker ();
201 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
202 if (VariableMtrrCount
< ReservedMtrrNumber
) {
206 return VariableMtrrCount
- ReservedMtrrNumber
;
210 Returns the firmware usable variable MTRR count for the CPU.
212 @return Firmware usable variable MTRR count
217 GetFirmwareVariableMtrrCount (
221 if (!IsMtrrSupported ()) {
224 return GetFirmwareVariableMtrrCountWorker ();
228 Worker function returns the default MTRR cache type for the system.
230 If MtrrSetting is not NULL, returns the default MTRR cache type from input
231 MTRR settings buffer.
232 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
234 @param[in] MtrrSetting A buffer holding all MTRRs content.
236 @return The default MTRR cache type.
239 MTRR_MEMORY_CACHE_TYPE
240 MtrrGetDefaultMemoryTypeWorker (
241 IN MTRR_SETTINGS
*MtrrSetting
244 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
246 if (MtrrSetting
== NULL
) {
247 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
249 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
252 return (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
257 Returns the default MTRR cache type for the system.
259 @return The default MTRR cache type.
262 MTRR_MEMORY_CACHE_TYPE
264 MtrrGetDefaultMemoryType (
268 if (!IsMtrrSupported ()) {
269 return CacheUncacheable
;
271 return MtrrGetDefaultMemoryTypeWorker (NULL
);
275 Preparation before programming MTRR.
277 This function will do some preparation for programming MTRRs:
278 disable cache, invalid cache and disable MTRR caching functionality
280 @param[out] MtrrContext Pointer to context to save
284 MtrrLibPreMtrrChange (
285 OUT MTRR_CONTEXT
*MtrrContext
288 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
290 // Disable interrupts and save current interrupt state
292 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
295 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
300 // Save original CR4 value and clear PGE flag (Bit 7)
302 MtrrContext
->Cr4
= AsmReadCr4 ();
303 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
313 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
315 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
319 Cleaning up after programming MTRRs.
321 This function will do some clean up after programming MTRRs:
322 Flush all TLBs, re-enable caching, restore CR4.
324 @param[in] MtrrContext Pointer to context to restore
328 MtrrLibPostMtrrChangeEnableCache (
329 IN MTRR_CONTEXT
*MtrrContext
338 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
343 // Restore original CR4 value
345 AsmWriteCr4 (MtrrContext
->Cr4
);
348 // Restore original interrupt state
350 SetInterruptState (MtrrContext
->InterruptState
);
354 Cleaning up after programming MTRRs.
356 This function will do some clean up after programming MTRRs:
357 enable MTRR caching functionality, and enable cache
359 @param[in] MtrrContext Pointer to context to restore
363 MtrrLibPostMtrrChange (
364 IN MTRR_CONTEXT
*MtrrContext
367 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
371 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
374 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, DefType
.Uint64
);
376 MtrrLibPostMtrrChangeEnableCache (MtrrContext
);
380 Worker function gets the content in fixed MTRRs
382 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
384 @retval The pointer of FixedSettings
388 MtrrGetFixedMtrrWorker (
389 OUT MTRR_FIXED_SETTINGS
*FixedSettings
394 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
395 FixedSettings
->Mtrr
[Index
] =
396 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
399 return FixedSettings
;
404 This function gets the content in fixed MTRRs
406 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
408 @retval The pointer of FixedSettings
414 OUT MTRR_FIXED_SETTINGS
*FixedSettings
417 if (!IsMtrrSupported ()) {
418 return FixedSettings
;
421 return MtrrGetFixedMtrrWorker (FixedSettings
);
426 Worker function will get the raw value in variable MTRRs
428 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
429 MTRR settings buffer.
430 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
432 @param[in] MtrrSetting A buffer holding all MTRRs content.
433 @param[in] VariableMtrrCount Number of variable MTRRs.
434 @param[out] VariableSettings A buffer to hold variable MTRRs content.
436 @return The VariableSettings input pointer
439 MTRR_VARIABLE_SETTINGS
*
440 MtrrGetVariableMtrrWorker (
441 IN MTRR_SETTINGS
*MtrrSetting
,
442 IN UINT32 VariableMtrrCount
,
443 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
448 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
450 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
451 if (MtrrSetting
== NULL
) {
452 VariableSettings
->Mtrr
[Index
].Base
=
453 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1));
454 VariableSettings
->Mtrr
[Index
].Mask
=
455 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1));
457 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
458 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
462 return VariableSettings
;
466 This function will get the raw value in variable MTRRs
468 @param[out] VariableSettings A buffer to hold variable MTRRs content.
470 @return The VariableSettings input pointer
473 MTRR_VARIABLE_SETTINGS
*
475 MtrrGetVariableMtrr (
476 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
479 if (!IsMtrrSupported ()) {
480 return VariableSettings
;
483 return MtrrGetVariableMtrrWorker (
485 GetVariableMtrrCountWorker (),
491 Programs fixed MTRRs registers.
493 @param[in] Type The memory type to set.
494 @param[in, out] Base The base address of memory range.
495 @param[in, out] Length The length of memory range.
496 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
497 On return, the current index of the fixed MTRR MSR to program.
498 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
499 @param[out] OrMask The bits to set in the fixed MTRR MSR.
501 @retval RETURN_SUCCESS The cache type was updated successfully
502 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
507 MtrrLibProgramFixedMtrr (
508 IN MTRR_MEMORY_CACHE_TYPE Type
,
510 IN OUT UINT64
*Length
,
511 IN OUT UINT32
*LastMsrIndex
,
512 OUT UINT64
*ClearMask
,
517 UINT32 LeftByteShift
;
518 UINT32 RightByteShift
;
522 // Find the fixed MTRR index to be programmed
524 for (MsrIndex
= *LastMsrIndex
+ 1; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
525 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) &&
528 mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
+
529 (8 * mMtrrLibFixedMtrrTable
[MsrIndex
].Length
)
537 ASSERT (MsrIndex
!= ARRAY_SIZE (mMtrrLibFixedMtrrTable
));
540 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
542 if ((((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
544 // Base address should be aligned to the begin of a certain Fixed MTRR range.
546 return RETURN_UNSUPPORTED
;
548 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
549 ASSERT (LeftByteShift
< 8);
552 // Find the end offset in fixed MTRR and calculate byte offset of right shift
554 SubLength
= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
* (8 - LeftByteShift
);
555 if (*Length
>= SubLength
) {
558 if (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrIndex
].Length
) != 0) {
560 // Length should be aligned to the end of a certain Fixed MTRR range.
562 return RETURN_UNSUPPORTED
;
564 RightByteShift
= 8 - LeftByteShift
- (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
566 // Update SubLength by actual length
571 *ClearMask
= CLEAR_SEED
;
572 *OrMask
= MultU64x32 (OR_SEED
, (UINT32
) Type
);
574 if (LeftByteShift
!= 0) {
576 // Clear the low bits by LeftByteShift
578 *ClearMask
&= LShiftU64 (*ClearMask
, LeftByteShift
* 8);
579 *OrMask
&= LShiftU64 (*OrMask
, LeftByteShift
* 8);
582 if (RightByteShift
!= 0) {
584 // Clear the high bits by RightByteShift
586 *ClearMask
&= RShiftU64 (*ClearMask
, RightByteShift
* 8);
587 *OrMask
&= RShiftU64 (*OrMask
, RightByteShift
* 8);
590 *Length
-= SubLength
;
593 *LastMsrIndex
= MsrIndex
;
595 return RETURN_SUCCESS
;
600 Worker function gets the attribute of variable MTRRs.
602 This function shadows the content of variable MTRRs into an
603 internal array: VariableMtrr.
605 @param[in] VariableSettings The variable MTRR values to shadow
606 @param[in] VariableMtrrCount The number of variable MTRRs
607 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
608 @param[in] MtrrValidAddressMask The valid address mask for MTRR
609 @param[out] VariableMtrr The array to shadow variable MTRRs content
611 @return Number of MTRRs which has been used.
615 MtrrGetMemoryAttributeInVariableMtrrWorker (
616 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
617 IN UINTN VariableMtrrCount
,
618 IN UINT64 MtrrValidBitsMask
,
619 IN UINT64 MtrrValidAddressMask
,
620 OUT VARIABLE_MTRR
*VariableMtrr
626 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
627 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
628 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
629 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
630 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
631 VariableMtrr
[Index
].Length
=
632 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
633 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
634 VariableMtrr
[Index
].Valid
= TRUE
;
635 VariableMtrr
[Index
].Used
= TRUE
;
643 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
644 One MTRR_MEMORY_RANGE element is created for each MTRR setting.
645 The routine doesn't remove the overlap or combine the near-by region.
647 @param[in] VariableSettings The variable MTRR values to shadow
648 @param[in] VariableMtrrCount The number of variable MTRRs
649 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
650 @param[in] MtrrValidAddressMask The valid address mask for MTRR
651 @param[out] VariableMtrr The array to shadow variable MTRRs content
653 @return Number of MTRRs which has been used.
657 MtrrLibGetRawVariableRanges (
658 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
659 IN UINTN VariableMtrrCount
,
660 IN UINT64 MtrrValidBitsMask
,
661 IN UINT64 MtrrValidAddressMask
,
662 OUT MTRR_MEMORY_RANGE
*VariableMtrr
668 ZeroMem (VariableMtrr
, sizeof (MTRR_MEMORY_RANGE
) * ARRAY_SIZE (VariableSettings
->Mtrr
));
669 for (Index
= 0, UsedMtrr
= 0; Index
< VariableMtrrCount
; Index
++) {
670 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &VariableSettings
->Mtrr
[Index
].Mask
)->Bits
.V
!= 0) {
671 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
672 VariableMtrr
[Index
].Length
=
673 ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
674 VariableMtrr
[Index
].Type
= (MTRR_MEMORY_CACHE_TYPE
)(VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
682 Gets the attribute of variable MTRRs.
684 This function shadows the content of variable MTRRs into an
685 internal array: VariableMtrr.
687 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
688 @param[in] MtrrValidAddressMask The valid address mask for MTRR
689 @param[out] VariableMtrr The array to shadow variable MTRRs content
691 @return The return value of this parameter indicates the
692 number of MTRRs which has been used.
697 MtrrGetMemoryAttributeInVariableMtrr (
698 IN UINT64 MtrrValidBitsMask
,
699 IN UINT64 MtrrValidAddressMask
,
700 OUT VARIABLE_MTRR
*VariableMtrr
703 MTRR_VARIABLE_SETTINGS VariableSettings
;
705 if (!IsMtrrSupported ()) {
709 MtrrGetVariableMtrrWorker (
711 GetVariableMtrrCountWorker (),
715 return MtrrGetMemoryAttributeInVariableMtrrWorker (
717 GetFirmwareVariableMtrrCountWorker (),
719 MtrrValidAddressMask
,
725 Return the biggest alignment (lowest set bit) of address.
726 The function is equivalent to: 1 << LowBitSet64 (Address).
728 @param Address The address to return the alignment.
729 @param Alignment0 The alignment to return when Address is 0.
731 @return The least alignment of the Address.
734 MtrrLibBiggestAlignment (
743 return Address
& ((~Address
) + 1);
747 Return whether the left MTRR type precedes the right MTRR type.
749 The MTRR type precedence rules are:
750 1. UC precedes any other type
752 For further details, please refer the IA32 Software Developer's Manual,
753 Volume 3, Section "MTRR Precedences".
755 @param Left The left MTRR type.
756 @param Right The right MTRR type.
758 @retval TRUE Left precedes Right.
759 @retval FALSE Left doesn't precede Right.
762 MtrrLibTypeLeftPrecedeRight (
763 IN MTRR_MEMORY_CACHE_TYPE Left
,
764 IN MTRR_MEMORY_CACHE_TYPE Right
767 return (BOOLEAN
) (Left
== CacheUncacheable
|| (Left
== CacheWriteThrough
&& Right
== CacheWriteBack
));
771 Initializes the valid bits mask and valid address mask for MTRRs.
773 This function initializes the valid bits mask and valid address mask for MTRRs.
775 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
776 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
780 MtrrLibInitializeMtrrMask (
781 OUT UINT64
*MtrrValidBitsMask
,
782 OUT UINT64
*MtrrValidAddressMask
785 UINT32 MaxExtendedFunction
;
786 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize
;
789 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedFunction
, NULL
, NULL
, NULL
);
791 if (MaxExtendedFunction
>= CPUID_VIR_PHY_ADDRESS_SIZE
) {
792 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, &VirPhyAddressSize
.Uint32
, NULL
, NULL
, NULL
);
794 VirPhyAddressSize
.Bits
.PhysicalAddressBits
= 36;
797 *MtrrValidBitsMask
= LShiftU64 (1, VirPhyAddressSize
.Bits
.PhysicalAddressBits
) - 1;
798 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
803 Determines the real attribute of a memory range.
805 This function is to arbitrate the real attribute of the memory when
806 there are 2 MTRRs covers the same memory range. For further details,
807 please refer the IA32 Software Developer's Manual, Volume 3,
808 Section "MTRR Precedences".
810 @param[in] MtrrType1 The first kind of Memory type
811 @param[in] MtrrType2 The second kind of memory type
814 MTRR_MEMORY_CACHE_TYPE
816 IN MTRR_MEMORY_CACHE_TYPE MtrrType1
,
817 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
820 if (MtrrType1
== MtrrType2
) {
825 MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
) ||
826 MtrrLibTypeLeftPrecedeRight (MtrrType2
, MtrrType1
)
829 if (MtrrLibTypeLeftPrecedeRight (MtrrType1
, MtrrType2
)) {
837 Worker function will get the memory cache type of the specific address.
839 If MtrrSetting is not NULL, gets the memory cache type from input
840 MTRR settings buffer.
841 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
843 @param[in] MtrrSetting A buffer holding all MTRRs content.
844 @param[in] Address The specific address
846 @return Memory cache type of the specific address
849 MTRR_MEMORY_CACHE_TYPE
850 MtrrGetMemoryAttributeByAddressWorker (
851 IN MTRR_SETTINGS
*MtrrSetting
,
852 IN PHYSICAL_ADDRESS Address
855 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType
;
859 MTRR_MEMORY_CACHE_TYPE MtrrType
;
860 MTRR_MEMORY_RANGE VariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
861 UINT64 MtrrValidBitsMask
;
862 UINT64 MtrrValidAddressMask
;
863 UINT32 VariableMtrrCount
;
864 MTRR_VARIABLE_SETTINGS VariableSettings
;
867 // Check if MTRR is enabled, if not, return UC as attribute
869 if (MtrrSetting
== NULL
) {
870 DefType
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
872 DefType
.Uint64
= MtrrSetting
->MtrrDefType
;
875 if (DefType
.Bits
.E
== 0) {
876 return CacheUncacheable
;
880 // If address is less than 1M, then try to go through the fixed MTRR
882 if (Address
< BASE_1MB
) {
883 if (DefType
.Bits
.FE
!= 0) {
885 // Go through the fixed MTRR
887 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
888 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
889 Address
< mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
890 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)) {
892 ((UINTN
) Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
893 mMtrrLibFixedMtrrTable
[Index
].Length
;
894 if (MtrrSetting
== NULL
) {
895 FixedMtrr
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
897 FixedMtrr
= MtrrSetting
->Fixed
.Mtrr
[Index
];
899 return (MTRR_MEMORY_CACHE_TYPE
) (RShiftU64 (FixedMtrr
, SubIndex
* 8) & 0xFF);
905 VariableMtrrCount
= GetVariableMtrrCountWorker ();
906 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
));
907 MtrrGetVariableMtrrWorker (MtrrSetting
, VariableMtrrCount
, &VariableSettings
);
909 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
910 MtrrLibGetRawVariableRanges (
914 MtrrValidAddressMask
,
919 // Go through the variable MTRR
921 MtrrType
= CacheInvalid
;
922 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
923 if (VariableMtrr
[Index
].Length
!= 0) {
924 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
925 Address
< VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
) {
926 if (MtrrType
== CacheInvalid
) {
927 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
;
929 MtrrType
= MtrrLibPrecedence (MtrrType
, (MTRR_MEMORY_CACHE_TYPE
) VariableMtrr
[Index
].Type
);
936 // If there is no MTRR which covers the Address, use the default MTRR type.
938 if (MtrrType
== CacheInvalid
) {
939 MtrrType
= (MTRR_MEMORY_CACHE_TYPE
) DefType
.Bits
.Type
;
947 This function will get the memory cache type of the specific address.
949 This function is mainly for debug purpose.
951 @param[in] Address The specific address
953 @return Memory cache type of the specific address
956 MTRR_MEMORY_CACHE_TYPE
958 MtrrGetMemoryAttribute (
959 IN PHYSICAL_ADDRESS Address
962 if (!IsMtrrSupported ()) {
963 return CacheUncacheable
;
966 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
970 Update the Ranges array to change the specified range identified by
971 BaseAddress and Length to Type.
973 @param Ranges Array holding memory type settings for all memory regions.
974 @param Capacity The maximum count of memory ranges the array can hold.
975 @param Count Return the new memory range count in the array.
976 @param BaseAddress The base address of the memory range to change type.
977 @param Length The length of the memory range to change type.
978 @param Type The new type of the specified memory range.
980 @retval RETURN_SUCCESS The type of the specified memory range is
981 changed successfully.
982 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
984 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
985 range exceeds capacity.
988 MtrrLibSetMemoryType (
989 IN MTRR_MEMORY_RANGE
*Ranges
,
992 IN UINT64 BaseAddress
,
994 IN MTRR_MEMORY_CACHE_TYPE Type
1007 Limit
= BaseAddress
+ Length
;
1008 StartIndex
= *Count
;
1010 for (Index
= 0; Index
< *Count
; Index
++) {
1011 if ((StartIndex
== *Count
) &&
1012 (Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1013 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1015 LengthLeft
= BaseAddress
- Ranges
[Index
].BaseAddress
;
1018 if ((EndIndex
== *Count
) &&
1019 (Ranges
[Index
].BaseAddress
< Limit
) &&
1020 (Limit
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)) {
1022 LengthRight
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Limit
;
1027 ASSERT (StartIndex
!= *Count
&& EndIndex
!= *Count
);
1028 if (StartIndex
== EndIndex
&& Ranges
[StartIndex
].Type
== Type
) {
1029 return RETURN_ALREADY_STARTED
;
1033 // The type change may cause merging with previous range or next range.
1034 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1035 // logic doesn't need to consider merging.
1037 if (StartIndex
!= 0) {
1038 if (LengthLeft
== 0 && Ranges
[StartIndex
- 1].Type
== Type
) {
1040 Length
+= Ranges
[StartIndex
].Length
;
1041 BaseAddress
-= Ranges
[StartIndex
].Length
;
1044 if (EndIndex
!= (*Count
) - 1) {
1045 if (LengthRight
== 0 && Ranges
[EndIndex
+ 1].Type
== Type
) {
1047 Length
+= Ranges
[EndIndex
].Length
;
1052 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1053 // |++++++++++++++++++| 0 3 1=3-0-2 3
1054 // |+++++++| 0 1 -1=1-0-2 5
1055 // |+| 0 0 -2=0-0-2 6
1056 // |+++| 0 0 -1=0-0-2+1 5
1059 DeltaCount
= EndIndex
- StartIndex
- 2;
1060 if (LengthLeft
== 0) {
1063 if (LengthRight
== 0) {
1066 if (*Count
- DeltaCount
> Capacity
) {
1067 return RETURN_OUT_OF_RESOURCES
;
1071 // Reserve (-DeltaCount) space
1073 CopyMem (&Ranges
[EndIndex
+ 1 - DeltaCount
], &Ranges
[EndIndex
+ 1], (*Count
- EndIndex
- 1) * sizeof (Ranges
[0]));
1074 *Count
-= DeltaCount
;
1076 if (LengthLeft
!= 0) {
1077 Ranges
[StartIndex
].Length
= LengthLeft
;
1080 if (LengthRight
!= 0) {
1081 Ranges
[EndIndex
- DeltaCount
].BaseAddress
= BaseAddress
+ Length
;
1082 Ranges
[EndIndex
- DeltaCount
].Length
= LengthRight
;
1083 Ranges
[EndIndex
- DeltaCount
].Type
= Ranges
[EndIndex
].Type
;
1085 Ranges
[StartIndex
].BaseAddress
= BaseAddress
;
1086 Ranges
[StartIndex
].Length
= Length
;
1087 Ranges
[StartIndex
].Type
= Type
;
1088 return RETURN_SUCCESS
;
1092 Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1094 @param Ranges Array holding memory type settings for all memory regions.
1095 @param RangeCount The count of memory ranges the array holds.
1096 @param BaseAddress Base address.
1097 @param Length Length.
1098 @param Types Return bit mask to indicate all memory types in the specified range.
1100 @retval Number of memory types.
1103 MtrrLibGetNumberOfTypes (
1104 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1105 IN UINTN RangeCount
,
1106 IN UINT64 BaseAddress
,
1108 IN OUT UINT8
*Types OPTIONAL
1117 for (Index
= 0; Index
< RangeCount
; Index
++) {
1118 if ((Ranges
[Index
].BaseAddress
<= BaseAddress
) &&
1119 (BaseAddress
< Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
)
1121 if ((LocalTypes
& (1 << Ranges
[Index
].Type
)) == 0) {
1122 LocalTypes
|= (UINT8
)(1 << Ranges
[Index
].Type
);
1126 if (BaseAddress
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1127 Length
-= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- BaseAddress
;
1128 BaseAddress
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
;
1135 if (Types
!= NULL
) {
1136 *Types
= LocalTypes
;
1142 Calculate the least MTRR number from vertex Start to Stop and update
1143 the Previous of all vertices from Start to Stop is updated to reflect
1144 how the memory range is covered by MTRR.
1146 @param VertexCount The count of vertices in the graph.
1147 @param Vertices Array holding all vertices.
1148 @param Weight 2-dimention array holding weights between vertices.
1149 @param Start Start vertex.
1150 @param Stop Stop vertex.
1151 @param IncludeOptional TRUE to count the optional weight.
1154 MtrrLibCalculateLeastMtrrs (
1155 IN UINT16 VertexCount
,
1156 IN MTRR_LIB_ADDRESS
*Vertices
,
1157 IN OUT CONST UINT8
*Weight
,
1160 IN BOOLEAN IncludeOptional
1169 for (Index
= Start
; Index
<= Stop
; Index
++) {
1170 Vertices
[Index
].Visited
= FALSE
;
1171 Mandatory
= Weight
[M(Start
,Index
)];
1172 Vertices
[Index
].Weight
= Mandatory
;
1173 if (Mandatory
!= MAX_WEIGHT
) {
1174 Optional
= IncludeOptional
? Weight
[O(Start
, Index
)] : 0;
1175 Vertices
[Index
].Weight
+= Optional
;
1176 ASSERT (Vertices
[Index
].Weight
>= Optional
);
1182 while (!Vertices
[Stop
].Visited
) {
1184 // Update the weight from the shortest vertex to other unvisited vertices
1186 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1187 if (!Vertices
[Index
].Visited
) {
1188 Mandatory
= Weight
[M(MinI
, Index
)];
1189 if (Mandatory
!= MAX_WEIGHT
) {
1190 Optional
= IncludeOptional
? Weight
[O(MinI
, Index
)] : 0;
1191 if (MinWeight
+ Mandatory
+ Optional
<= Vertices
[Index
].Weight
) {
1192 Vertices
[Index
].Weight
= MinWeight
+ Mandatory
+ Optional
;
1193 Vertices
[Index
].Previous
= MinI
; // Previous is Start based.
1200 // Find the shortest vertex from Start
1203 MinWeight
= MAX_WEIGHT
;
1204 for (Index
= Start
+ 1; Index
<= Stop
; Index
++) {
1205 if (!Vertices
[Index
].Visited
&& MinWeight
> Vertices
[Index
].Weight
) {
1207 MinWeight
= Vertices
[Index
].Weight
;
1212 // Mark the shortest vertex from Start as visited
1214 Vertices
[MinI
].Visited
= TRUE
;
1219 Append the MTRR setting to MTRR setting array.
1221 @param Mtrrs Array holding all MTRR settings.
1222 @param MtrrCapacity Capacity of the MTRR array.
1223 @param MtrrCount The count of MTRR settings in array.
1224 @param BaseAddress Base address.
1225 @param Length Length.
1226 @param Type Memory type.
1228 @retval RETURN_SUCCESS MTRR setting is appended to array.
1229 @retval RETURN_OUT_OF_RESOURCES Array is full.
1232 MtrrLibAppendVariableMtrr (
1233 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1234 IN UINT32 MtrrCapacity
,
1235 IN OUT UINT32
*MtrrCount
,
1236 IN UINT64 BaseAddress
,
1238 IN MTRR_MEMORY_CACHE_TYPE Type
1241 if (*MtrrCount
== MtrrCapacity
) {
1242 return RETURN_OUT_OF_RESOURCES
;
1245 Mtrrs
[*MtrrCount
].BaseAddress
= BaseAddress
;
1246 Mtrrs
[*MtrrCount
].Length
= Length
;
1247 Mtrrs
[*MtrrCount
].Type
= Type
;
1249 return RETURN_SUCCESS
;
1253 Return the memory type that has the least precedence.
1255 @param TypeBits Bit mask of memory type.
1257 @retval Memory type that has the least precedence.
1259 MTRR_MEMORY_CACHE_TYPE
1266 ASSERT (TypeBits
!= 0);
1267 for (Type
= 7; (INT8
)TypeBits
> 0; Type
--, TypeBits
<<= 1);
1268 return (MTRR_MEMORY_CACHE_TYPE
)Type
;
1272 Return TRUE when the Operand is exactly power of 2.
1274 @retval TRUE Operand is exactly power of 2.
1275 @retval FALSE Operand is not power of 2.
1278 MtrrLibIsPowerOfTwo (
1282 ASSERT (Operand
!= 0);
1283 return (BOOLEAN
) ((Operand
& (Operand
- 1)) == 0);
1287 Calculate the subtractive path from vertex Start to Stop.
1289 @param DefaultType Default memory type.
1290 @param A0 Alignment to use when base address is 0.
1291 @param Ranges Array holding memory type settings for all memory regions.
1292 @param RangeCount The count of memory ranges the array holds.
1293 @param VertexCount The count of vertices in the graph.
1294 @param Vertices Array holding all vertices.
1295 @param Weight 2-dimention array holding weights between vertices.
1296 @param Start Start vertex.
1297 @param Stop Stop vertex.
1298 @param Types Type bit mask of memory range from Start to Stop.
1299 @param TypeCount Number of different memory types from Start to Stop.
1300 @param Mtrrs Array holding all MTRR settings.
1301 @param MtrrCapacity Capacity of the MTRR array.
1302 @param MtrrCount The count of MTRR settings in array.
1304 @retval RETURN_SUCCESS The subtractive path is calculated successfully.
1305 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1309 MtrrLibCalculateSubtractivePath (
1310 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1312 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1313 IN UINTN RangeCount
,
1314 IN UINT16 VertexCount
,
1315 IN MTRR_LIB_ADDRESS
*Vertices
,
1316 IN OUT UINT8
*Weight
,
1321 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
, OPTIONAL
1322 IN UINT32 MtrrCapacity
, OPTIONAL
1323 IN OUT UINT32
*MtrrCount OPTIONAL
1326 RETURN_STATUS Status
;
1329 UINT8 PrecedentTypes
;
1338 MTRR_MEMORY_CACHE_TYPE LowestType
;
1339 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType
;
1341 Base
= Vertices
[Start
].Address
;
1342 Length
= Vertices
[Stop
].Address
- Base
;
1344 LowestType
= MtrrLibLowestType (Types
);
1347 // Clear the lowest type (highest bit) to get the precedent types
1349 PrecedentTypes
= ~(1 << LowestType
) & Types
;
1350 LowestPrecedentType
= MtrrLibLowestType (PrecedentTypes
);
1352 if (Mtrrs
== NULL
) {
1353 Weight
[M(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 0 : 1);
1354 Weight
[O(Start
, Stop
)] = ((LowestType
== DefaultType
) ? 1 : 0);
1357 // Add all high level ranges
1360 for (Index
= 0; Index
< RangeCount
; Index
++) {
1364 if ((Base
< Ranges
[Index
].BaseAddress
) || (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
<= Base
)) {
1369 // Base is in the Range[Index]
1371 if (Base
+ Length
> Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
1372 SubLength
= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- Base
;
1376 if (((1 << Ranges
[Index
].Type
) & PrecedentTypes
) != 0) {
1378 // Meet a range whose types take precedence.
1379 // Update the [HBase, HBase + HLength) to include the range,
1380 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1382 if (HBase
== MAX_UINT64
) {
1385 HLength
+= SubLength
;
1389 Length
-= SubLength
;
1395 if ((Ranges
[Index
].Type
== LowestType
) || (Length
== 0)) { // meet low type or end
1398 // Add the MTRRs for each high priority type range
1399 // the range[HBase, HBase + HLength) contains only two types.
1400 // We might use positive or subtractive, depending on which way uses less MTRR
1402 for (SubStart
= Start
; SubStart
<= Stop
; SubStart
++) {
1403 if (Vertices
[SubStart
].Address
== HBase
) {
1408 for (SubStop
= SubStart
; SubStop
<= Stop
; SubStop
++) {
1409 if (Vertices
[SubStop
].Address
== HBase
+ HLength
) {
1413 ASSERT (Vertices
[SubStart
].Address
== HBase
);
1414 ASSERT (Vertices
[SubStop
].Address
== HBase
+ HLength
);
1416 if ((TypeCount
== 2) || (SubStart
== SubStop
- 1)) {
1418 // add subtractive MTRRs for [HBase, HBase + HLength)
1419 // [HBase, HBase + HLength) contains only one type.
1420 // while - loop is to split the range to MTRR - compliant aligned range.
1422 if (Mtrrs
== NULL
) {
1423 Weight
[M (Start
, Stop
)] += (UINT8
)(SubStop
- SubStart
);
1425 while (SubStart
!= SubStop
) {
1426 Status
= MtrrLibAppendVariableMtrr (
1427 Mtrrs
, MtrrCapacity
, MtrrCount
,
1428 Vertices
[SubStart
].Address
, Vertices
[SubStart
].Length
, Vertices
[SubStart
].Type
1430 if (RETURN_ERROR (Status
)) {
1437 ASSERT (TypeCount
== 3);
1438 MtrrLibCalculateLeastMtrrs (VertexCount
, Vertices
, Weight
, SubStart
, SubStop
, TRUE
);
1440 if (Mtrrs
== NULL
) {
1441 Weight
[M (Start
, Stop
)] += Vertices
[SubStop
].Weight
;
1443 // When we need to collect the optimal path from SubStart to SubStop
1444 while (SubStop
!= SubStart
) {
1446 Pre
= Vertices
[Cur
].Previous
;
1449 if (Weight
[M (Pre
, Cur
)] + Weight
[O (Pre
, Cur
)] != 0) {
1450 Status
= MtrrLibAppendVariableMtrr (
1451 Mtrrs
, MtrrCapacity
, MtrrCount
,
1452 Vertices
[Pre
].Address
, Vertices
[Cur
].Address
- Vertices
[Pre
].Address
,
1453 (Pre
!= Cur
- 1) ? LowestPrecedentType
: Vertices
[Pre
].Type
1455 if (RETURN_ERROR (Status
)) {
1459 if (Pre
!= Cur
- 1) {
1460 Status
= MtrrLibCalculateSubtractivePath (
1463 VertexCount
, Vertices
, Weight
,
1464 Pre
, Cur
, PrecedentTypes
, 2,
1465 Mtrrs
, MtrrCapacity
, MtrrCount
1467 if (RETURN_ERROR (Status
)) {
1476 // Reset HBase, HLength
1482 return RETURN_SUCCESS
;
1486 Calculate MTRR settings to cover the specified memory ranges.
1488 @param DefaultType Default memory type.
1489 @param A0 Alignment to use when base address is 0.
1490 @param Ranges Memory range array holding the memory type
1491 settings for all memory address.
1492 @param RangeCount Count of memory ranges.
1493 @param Scratch A temporary scratch buffer that is used to perform the calculation.
1494 This is an optional parameter that may be NULL.
1495 @param ScratchSize Pointer to the size in bytes of the scratch buffer.
1496 It may be updated to the actual required size when the calculation
1497 needs more scratch buffer.
1498 @param Mtrrs Array holding all MTRR settings.
1499 @param MtrrCapacity Capacity of the MTRR array.
1500 @param MtrrCount The count of MTRR settings in array.
1502 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1503 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1504 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1507 MtrrLibCalculateMtrrs (
1508 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1510 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1511 IN UINTN RangeCount
,
1513 IN OUT UINTN
*ScratchSize
,
1514 IN OUT MTRR_MEMORY_RANGE
*Mtrrs
,
1515 IN UINT32 MtrrCapacity
,
1516 IN OUT UINT32
*MtrrCount
1526 MTRR_LIB_ADDRESS
*Vertices
;
1530 UINTN RequiredScratchSize
;
1535 RETURN_STATUS Status
;
1537 Base0
= Ranges
[0].BaseAddress
;
1538 Base1
= Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
;
1539 MTRR_LIB_ASSERT_ALIGNED (Base0
, Base1
- Base0
);
1542 // Count the number of vertices.
1544 Vertices
= (MTRR_LIB_ADDRESS
*)Scratch
;
1545 for (VertexIndex
= 0, Index
= 0; Index
< RangeCount
; Index
++) {
1546 Base
= Ranges
[Index
].BaseAddress
;
1547 Length
= Ranges
[Index
].Length
;
1548 while (Length
!= 0) {
1549 Alignment
= MtrrLibBiggestAlignment (Base
, A0
);
1550 SubLength
= Alignment
;
1551 if (SubLength
> Length
) {
1552 SubLength
= GetPowerOfTwo64 (Length
);
1554 if (VertexIndex
< *ScratchSize
/ sizeof (*Vertices
)) {
1555 Vertices
[VertexIndex
].Address
= Base
;
1556 Vertices
[VertexIndex
].Alignment
= Alignment
;
1557 Vertices
[VertexIndex
].Type
= Ranges
[Index
].Type
;
1558 Vertices
[VertexIndex
].Length
= SubLength
;
1561 Length
-= SubLength
;
1566 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1568 VertexCount
= VertexIndex
+ 1;
1570 DEBUG_CACHE
, " Count of vertices (%016llx - %016llx) = %d\n",
1571 Ranges
[0].BaseAddress
, Ranges
[RangeCount
- 1].BaseAddress
+ Ranges
[RangeCount
- 1].Length
, VertexCount
1573 ASSERT (VertexCount
< MAX_UINT16
);
1575 RequiredScratchSize
= VertexCount
* sizeof (*Vertices
) + VertexCount
* VertexCount
* sizeof (*Weight
);
1576 if (*ScratchSize
< RequiredScratchSize
) {
1577 *ScratchSize
= RequiredScratchSize
;
1578 return RETURN_BUFFER_TOO_SMALL
;
1580 Vertices
[VertexCount
- 1].Address
= Base1
;
1582 Weight
= (UINT8
*) &Vertices
[VertexCount
];
1583 for (VertexIndex
= 0; VertexIndex
< VertexCount
; VertexIndex
++) {
1585 // Set optional weight between vertices and self->self to 0
1587 SetMem (&Weight
[M(VertexIndex
, 0)], VertexIndex
+ 1, 0);
1589 // Set mandatory weight between vertices to MAX_WEIGHT
1591 SetMem (&Weight
[M (VertexIndex
, VertexIndex
+ 1)], VertexCount
- VertexIndex
- 1, MAX_WEIGHT
);
1593 // Final result looks like:
1601 // Set mandatory weight and optional weight for adjacent vertices
1603 for (VertexIndex
= 0; VertexIndex
< VertexCount
- 1; VertexIndex
++) {
1604 if (Vertices
[VertexIndex
].Type
!= DefaultType
) {
1605 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 1;
1606 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 0;
1608 Weight
[M (VertexIndex
, VertexIndex
+ 1)] = 0;
1609 Weight
[O (VertexIndex
, VertexIndex
+ 1)] = 1;
1613 for (TypeCount
= 2; TypeCount
<= 3; TypeCount
++) {
1614 for (Start
= 0; Start
< VertexCount
; Start
++) {
1615 for (Stop
= Start
+ 2; Stop
< VertexCount
; Stop
++) {
1616 ASSERT (Vertices
[Stop
].Address
> Vertices
[Start
].Address
);
1617 Length
= Vertices
[Stop
].Address
- Vertices
[Start
].Address
;
1618 if (Length
> Vertices
[Start
].Alignment
) {
1620 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1624 if ((Weight
[M(Start
, Stop
)] == MAX_WEIGHT
) && MtrrLibIsPowerOfTwo (Length
)) {
1625 if (MtrrLibGetNumberOfTypes (
1626 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1629 // Update the Weight[Start, Stop] using subtractive path.
1631 MtrrLibCalculateSubtractivePath (
1634 (UINT16
)VertexCount
, Vertices
, Weight
,
1635 Start
, Stop
, Type
, TypeCount
,
1638 } else if (TypeCount
== 2) {
1640 // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1641 // Because no matter how Stop is increased, we always meet 3-type range.
1650 Status
= RETURN_SUCCESS
;
1651 MtrrLibCalculateLeastMtrrs ((UINT16
) VertexCount
, Vertices
, Weight
, 0, (UINT16
) VertexCount
- 1, FALSE
);
1652 Stop
= (UINT16
) VertexCount
- 1;
1654 Start
= Vertices
[Stop
].Previous
;
1655 TypeCount
= MAX_UINT8
;
1657 if (Weight
[M(Start
, Stop
)] != 0) {
1658 TypeCount
= MtrrLibGetNumberOfTypes (Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
);
1659 Status
= MtrrLibAppendVariableMtrr (
1660 Mtrrs
, MtrrCapacity
, MtrrCount
,
1661 Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
,
1662 MtrrLibLowestType (Type
)
1664 if (RETURN_ERROR (Status
)) {
1669 if (Start
!= Stop
- 1) {
1671 // substractive path
1673 if (TypeCount
== MAX_UINT8
) {
1674 TypeCount
= MtrrLibGetNumberOfTypes (
1675 Ranges
, RangeCount
, Vertices
[Start
].Address
, Vertices
[Stop
].Address
- Vertices
[Start
].Address
, &Type
1678 Status
= MtrrLibCalculateSubtractivePath (
1681 (UINT16
) VertexCount
, Vertices
, Weight
, Start
, Stop
,
1683 Mtrrs
, MtrrCapacity
, MtrrCount
1685 if (RETURN_ERROR (Status
)) {
1696 Apply the fixed MTRR settings to memory range array.
1698 @param Fixed The fixed MTRR settings.
1699 @param Ranges Return the memory range array holding memory type
1700 settings for all memory address.
1701 @param RangeCapacity The capacity of memory range array.
1702 @param RangeCount Return the count of memory range.
1704 @retval RETURN_SUCCESS The memory range array is returned successfully.
1705 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1708 MtrrLibApplyFixedMtrrs (
1709 IN MTRR_FIXED_SETTINGS
*Fixed
,
1710 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1711 IN UINTN RangeCapacity
,
1712 IN OUT UINTN
*RangeCount
1715 RETURN_STATUS Status
;
1718 MTRR_MEMORY_CACHE_TYPE MemoryType
;
1722 for (MsrIndex
= 0; MsrIndex
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); MsrIndex
++) {
1723 ASSERT (Base
== mMtrrLibFixedMtrrTable
[MsrIndex
].BaseAddress
);
1724 for (Index
= 0; Index
< sizeof (UINT64
); Index
++) {
1725 MemoryType
= (MTRR_MEMORY_CACHE_TYPE
)((UINT8
*)(&Fixed
->Mtrr
[MsrIndex
]))[Index
];
1726 Status
= MtrrLibSetMemoryType (
1727 Ranges
, RangeCapacity
, RangeCount
, Base
, mMtrrLibFixedMtrrTable
[MsrIndex
].Length
, MemoryType
1729 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1732 Base
+= mMtrrLibFixedMtrrTable
[MsrIndex
].Length
;
1735 ASSERT (Base
== BASE_1MB
);
1736 return RETURN_SUCCESS
;
1740 Apply the variable MTRR settings to memory range array.
1742 @param VariableMtrr The variable MTRR array.
1743 @param VariableMtrrCount The count of variable MTRRs.
1744 @param Ranges Return the memory range array with new MTRR settings applied.
1745 @param RangeCapacity The capacity of memory range array.
1746 @param RangeCount Return the count of memory range.
1748 @retval RETURN_SUCCESS The memory range array is returned successfully.
1749 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1752 MtrrLibApplyVariableMtrrs (
1753 IN CONST MTRR_MEMORY_RANGE
*VariableMtrr
,
1754 IN UINT32 VariableMtrrCount
,
1755 IN OUT MTRR_MEMORY_RANGE
*Ranges
,
1756 IN UINTN RangeCapacity
,
1757 IN OUT UINTN
*RangeCount
1760 RETURN_STATUS Status
;
1766 // UC > * (except WB, UC) > WB
1772 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1773 if ((VariableMtrr
[Index
].Length
!= 0) && (VariableMtrr
[Index
].Type
== CacheWriteBack
)) {
1774 Status
= MtrrLibSetMemoryType (
1775 Ranges
, RangeCapacity
, RangeCount
,
1776 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1778 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1785 // 2. Set other types than WB or UC
1787 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1788 if ((VariableMtrr
[Index
].Length
!= 0) &&
1789 (VariableMtrr
[Index
].Type
!= CacheWriteBack
) && (VariableMtrr
[Index
].Type
!= CacheUncacheable
)) {
1790 Status
= MtrrLibSetMemoryType (
1791 Ranges
, RangeCapacity
, RangeCount
,
1792 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1794 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1803 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1804 if (VariableMtrr
[Index
].Length
!= 0 && VariableMtrr
[Index
].Type
== CacheUncacheable
) {
1805 Status
= MtrrLibSetMemoryType (
1806 Ranges
, RangeCapacity
, RangeCount
,
1807 VariableMtrr
[Index
].BaseAddress
, VariableMtrr
[Index
].Length
, VariableMtrr
[Index
].Type
1809 if (Status
== RETURN_OUT_OF_RESOURCES
) {
1814 return RETURN_SUCCESS
;
1818 Return the memory type bit mask that's compatible to first type in the Ranges.
1820 @param Ranges Memory range array holding the memory type
1821 settings for all memory address.
1822 @param RangeCount Count of memory ranges.
1824 @return Compatible memory type bit mask.
1827 MtrrLibGetCompatibleTypes (
1828 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
1832 ASSERT (RangeCount
!= 0);
1834 switch (Ranges
[0].Type
) {
1835 case CacheWriteBack
:
1836 case CacheWriteThrough
:
1837 return (1 << CacheWriteBack
) | (1 << CacheWriteThrough
) | (1 << CacheUncacheable
);
1840 case CacheWriteCombining
:
1841 case CacheWriteProtected
:
1842 return (1 << Ranges
[0].Type
) | (1 << CacheUncacheable
);
1845 case CacheUncacheable
:
1846 if (RangeCount
== 1) {
1847 return (1 << CacheUncacheable
);
1849 return MtrrLibGetCompatibleTypes (&Ranges
[1], RangeCount
- 1);
1861 Overwrite the destination MTRR settings with the source MTRR settings.
1862 This routine is to make sure the modification to destination MTRR settings
1863 is as small as possible.
1865 @param DstMtrrs Destination MTRR settings.
1866 @param DstMtrrCount Count of destination MTRR settings.
1867 @param SrcMtrrs Source MTRR settings.
1868 @param SrcMtrrCount Count of source MTRR settings.
1869 @param Modified Flag array to indicate which destination MTRR setting is modified.
1872 MtrrLibMergeVariableMtrr (
1873 MTRR_MEMORY_RANGE
*DstMtrrs
,
1874 UINT32 DstMtrrCount
,
1875 MTRR_MEMORY_RANGE
*SrcMtrrs
,
1876 UINT32 SrcMtrrCount
,
1883 ASSERT (SrcMtrrCount
<= DstMtrrCount
);
1885 for (DstIndex
= 0; DstIndex
< DstMtrrCount
; DstIndex
++) {
1886 Modified
[DstIndex
] = FALSE
;
1888 if (DstMtrrs
[DstIndex
].Length
== 0) {
1891 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1892 if (DstMtrrs
[DstIndex
].BaseAddress
== SrcMtrrs
[SrcIndex
].BaseAddress
&&
1893 DstMtrrs
[DstIndex
].Length
== SrcMtrrs
[SrcIndex
].Length
&&
1894 DstMtrrs
[DstIndex
].Type
== SrcMtrrs
[SrcIndex
].Type
) {
1899 if (SrcIndex
== SrcMtrrCount
) {
1901 // Remove the one from DstMtrrs which is not in SrcMtrrs
1903 DstMtrrs
[DstIndex
].Length
= 0;
1904 Modified
[DstIndex
] = TRUE
;
1907 // Remove the one from SrcMtrrs which is also in DstMtrrs
1909 SrcMtrrs
[SrcIndex
].Length
= 0;
1914 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1915 // Merge MTRRs from SrcMtrrs to DstMtrrs
1918 for (SrcIndex
= 0; SrcIndex
< SrcMtrrCount
; SrcIndex
++) {
1919 if (SrcMtrrs
[SrcIndex
].Length
!= 0) {
1922 // Find the empty slot in DstMtrrs
1924 while (DstIndex
< DstMtrrCount
) {
1925 if (DstMtrrs
[DstIndex
].Length
== 0) {
1930 ASSERT (DstIndex
< DstMtrrCount
);
1931 CopyMem (&DstMtrrs
[DstIndex
], &SrcMtrrs
[SrcIndex
], sizeof (SrcMtrrs
[0]));
1932 Modified
[DstIndex
] = TRUE
;
1938 Calculate the variable MTRR settings for all memory ranges.
1940 @param DefaultType Default memory type.
1941 @param A0 Alignment to use when base address is 0.
1942 @param Ranges Memory range array holding the memory type
1943 settings for all memory address.
1944 @param RangeCount Count of memory ranges.
1945 @param Scratch Scratch buffer to be used in MTRR calculation.
1946 @param ScratchSize Pointer to the size of scratch buffer.
1947 @param VariableMtrr Array holding all MTRR settings.
1948 @param VariableMtrrCapacity Capacity of the MTRR array.
1949 @param VariableMtrrCount The count of MTRR settings in array.
1951 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1952 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1953 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1954 The required scratch buffer size is returned through ScratchSize.
1957 MtrrLibSetMemoryRanges (
1958 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
1960 IN MTRR_MEMORY_RANGE
*Ranges
,
1961 IN UINTN RangeCount
,
1963 IN OUT UINTN
*ScratchSize
,
1964 OUT MTRR_MEMORY_RANGE
*VariableMtrr
,
1965 IN UINT32 VariableMtrrCapacity
,
1966 OUT UINT32
*VariableMtrrCount
1969 RETURN_STATUS Status
;
1974 UINT8 CompatibleTypes
;
1977 UINTN ActualScratchSize
;
1978 UINTN BiggestScratchSize
;
1980 *VariableMtrrCount
= 0;
1983 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
1984 // Each call needs different scratch buffer size.
1985 // When the provided scratch buffer size is not sufficient in any call,
1986 // set the GetActualScratchSize to TRUE, and following calls will only
1987 // calculate the actual scratch size for the caller.
1989 BiggestScratchSize
= 0;
1991 for (Index
= 0; Index
< RangeCount
;) {
1992 Base0
= Ranges
[Index
].BaseAddress
;
1995 // Full step is optimal
1997 while (Index
< RangeCount
) {
1998 ASSERT (Ranges
[Index
].BaseAddress
== Base0
);
1999 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2000 while (Base0
+ Alignment
<= Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) {
2001 if ((BiggestScratchSize
<= *ScratchSize
) && (Ranges
[Index
].Type
!= DefaultType
)) {
2002 Status
= MtrrLibAppendVariableMtrr (
2003 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
,
2004 Base0
, Alignment
, Ranges
[Index
].Type
2006 if (RETURN_ERROR (Status
)) {
2011 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2015 // Remove the above range from Ranges[Index]
2017 Ranges
[Index
].Length
-= Base0
- Ranges
[Index
].BaseAddress
;
2018 Ranges
[Index
].BaseAddress
= Base0
;
2019 if (Ranges
[Index
].Length
!= 0) {
2026 if (Index
== RangeCount
) {
2031 // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2032 // Per SDM, the compatible types between[B0, B1) are:
2037 CompatibleTypes
= MtrrLibGetCompatibleTypes (&Ranges
[Index
], RangeCount
- Index
);
2039 End
= Index
; // End points to last one that matches the CompatibleTypes.
2040 while (End
+ 1 < RangeCount
) {
2041 if (((1 << Ranges
[End
+ 1].Type
) & CompatibleTypes
) == 0) {
2046 Alignment
= MtrrLibBiggestAlignment (Base0
, A0
);
2047 Length
= GetPowerOfTwo64 (Ranges
[End
].BaseAddress
+ Ranges
[End
].Length
- Base0
);
2048 Base1
= Base0
+ MIN (Alignment
, Length
);
2051 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2054 while (End
+ 1 < RangeCount
) {
2055 if (Base1
<= Ranges
[End
+ 1].BaseAddress
) {
2061 Length
= Ranges
[End
].Length
;
2062 Ranges
[End
].Length
= Base1
- Ranges
[End
].BaseAddress
;
2063 ActualScratchSize
= *ScratchSize
;
2064 Status
= MtrrLibCalculateMtrrs (
2066 &Ranges
[Index
], End
+ 1 - Index
,
2067 Scratch
, &ActualScratchSize
,
2068 VariableMtrr
, VariableMtrrCapacity
, VariableMtrrCount
2070 if (Status
== RETURN_BUFFER_TOO_SMALL
) {
2071 BiggestScratchSize
= MAX (BiggestScratchSize
, ActualScratchSize
);
2073 // Ignore this error, because we need to calculate the biggest
2074 // scratch buffer size.
2076 Status
= RETURN_SUCCESS
;
2078 if (RETURN_ERROR (Status
)) {
2082 if (Length
!= Ranges
[End
].Length
) {
2083 Ranges
[End
].BaseAddress
= Base1
;
2084 Ranges
[End
].Length
= Length
- Ranges
[End
].Length
;
2091 if (*ScratchSize
< BiggestScratchSize
) {
2092 *ScratchSize
= BiggestScratchSize
;
2093 return RETURN_BUFFER_TOO_SMALL
;
2095 return RETURN_SUCCESS
;
2099 Set the below-1MB memory attribute to fixed MTRR buffer.
2100 Modified flag array indicates which fixed MTRR is modified.
2102 @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
2103 @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
2104 @param [in] BaseAddress Base address.
2105 @param [in] Length Length.
2106 @param [in] Type Memory type.
2108 @retval RETURN_SUCCESS The memory attribute is set successfully.
2109 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
2110 for the fixed MTRRs.
2113 MtrrLibSetBelow1MBMemoryAttribute (
2114 IN OUT UINT64
*ClearMasks
,
2115 IN OUT UINT64
*OrMasks
,
2116 IN PHYSICAL_ADDRESS BaseAddress
,
2118 IN MTRR_MEMORY_CACHE_TYPE Type
2121 RETURN_STATUS Status
;
2126 ASSERT (BaseAddress
< BASE_1MB
);
2128 MsrIndex
= (UINT32
)-1;
2129 while ((BaseAddress
< BASE_1MB
) && (Length
!= 0)) {
2130 Status
= MtrrLibProgramFixedMtrr (Type
, &BaseAddress
, &Length
, &MsrIndex
, &ClearMask
, &OrMask
);
2131 if (RETURN_ERROR (Status
)) {
2134 ClearMasks
[MsrIndex
] = ClearMasks
[MsrIndex
] | ClearMask
;
2135 OrMasks
[MsrIndex
] = (OrMasks
[MsrIndex
] & ~ClearMask
) | OrMask
;
2137 return RETURN_SUCCESS
;
2141 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2143 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2144 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
2145 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
2146 It may be updated to the actual required size when the calculation
2147 needs more scratch buffer.
2148 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
2149 When range overlap happens, the last one takes higher priority.
2150 When the function returns, either all the attributes are set successfully,
2151 or none of them is set.
2152 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
2154 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
2155 @retval RETURN_INVALID_PARAMETER Length in any range is zero.
2156 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2157 memory resource range specified by BaseAddress and Length in any range.
2158 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2159 range specified by BaseAddress and Length in any range.
2160 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2161 the memory resource ranges.
2162 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2163 BaseAddress and Length cannot be modified.
2164 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
2168 MtrrSetMemoryAttributesInMtrrSettings (
2169 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2171 IN OUT UINTN
*ScratchSize
,
2172 IN CONST MTRR_MEMORY_RANGE
*Ranges
,
2176 RETURN_STATUS Status
;
2180 BOOLEAN Above1MbExist
;
2182 UINT64 MtrrValidBitsMask
;
2183 UINT64 MtrrValidAddressMask
;
2184 MTRR_MEMORY_CACHE_TYPE DefaultType
;
2185 MTRR_VARIABLE_SETTINGS VariableSettings
;
2186 MTRR_MEMORY_RANGE WorkingRanges
[2 * ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
) + 2];
2187 UINTN WorkingRangeCount
;
2189 MTRR_VARIABLE_SETTING VariableSetting
;
2190 UINT32 OriginalVariableMtrrCount
;
2191 UINT32 FirmwareVariableMtrrCount
;
2192 UINT32 WorkingVariableMtrrCount
;
2193 MTRR_MEMORY_RANGE OriginalVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2194 MTRR_MEMORY_RANGE WorkingVariableMtrr
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2195 BOOLEAN VariableSettingModified
[ARRAY_SIZE (MtrrSetting
->Variables
.Mtrr
)];
2197 UINT64 ClearMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2198 UINT64 OrMasks
[ARRAY_SIZE (mMtrrLibFixedMtrrTable
)];
2200 MTRR_CONTEXT MtrrContext
;
2201 BOOLEAN MtrrContextValid
;
2203 Status
= RETURN_SUCCESS
;
2204 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2207 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2209 SetMem (VariableSettingModified
, ARRAY_SIZE (VariableSettingModified
), FALSE
);
2212 // TRUE indicating the caller requests to set variable MTRRs.
2214 Above1MbExist
= FALSE
;
2215 OriginalVariableMtrrCount
= 0;
2218 // 0. Dump the requests.
2221 DEBUG ((DEBUG_CACHE
, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2222 (MtrrSetting
== NULL
) ? "Hardware" : "Buffer", *ScratchSize
,
2223 (RangeCount
<= 1) ? "," : "\n"
2225 for (Index
= 0; Index
< RangeCount
; Index
++) {
2226 DEBUG ((DEBUG_CACHE
, " %a: [%016lx, %016lx)\n",
2227 mMtrrMemoryCacheTypeShortName
[MIN (Ranges
[Index
].Type
, CacheInvalid
)],
2228 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
2234 // 1. Validate the parameters.
2236 if (!IsMtrrSupported ()) {
2237 Status
= RETURN_UNSUPPORTED
;
2241 for (Index
= 0; Index
< RangeCount
; Index
++) {
2242 if (Ranges
[Index
].Length
== 0) {
2243 Status
= RETURN_INVALID_PARAMETER
;
2246 if (((Ranges
[Index
].BaseAddress
& ~MtrrValidAddressMask
) != 0) ||
2247 ((((Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) & ~MtrrValidAddressMask
) != 0) &&
2248 (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
) != MtrrValidBitsMask
+ 1)
2251 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2252 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2254 Status
= RETURN_UNSUPPORTED
;
2257 if ((Ranges
[Index
].Type
!= CacheUncacheable
) &&
2258 (Ranges
[Index
].Type
!= CacheWriteCombining
) &&
2259 (Ranges
[Index
].Type
!= CacheWriteThrough
) &&
2260 (Ranges
[Index
].Type
!= CacheWriteProtected
) &&
2261 (Ranges
[Index
].Type
!= CacheWriteBack
)) {
2262 Status
= RETURN_INVALID_PARAMETER
;
2265 if (Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
> BASE_1MB
) {
2266 Above1MbExist
= TRUE
;
2271 // 2. Apply the above-1MB memory attribute settings.
2273 if (Above1MbExist
) {
2275 // 2.1. Read all variable MTRRs and convert to Ranges.
2277 OriginalVariableMtrrCount
= GetVariableMtrrCountWorker ();
2278 MtrrGetVariableMtrrWorker (MtrrSetting
, OriginalVariableMtrrCount
, &VariableSettings
);
2279 MtrrLibGetRawVariableRanges (
2280 &VariableSettings
, OriginalVariableMtrrCount
,
2281 MtrrValidBitsMask
, MtrrValidAddressMask
, OriginalVariableMtrr
2284 DefaultType
= MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
2285 WorkingRangeCount
= 1;
2286 WorkingRanges
[0].BaseAddress
= 0;
2287 WorkingRanges
[0].Length
= MtrrValidBitsMask
+ 1;
2288 WorkingRanges
[0].Type
= DefaultType
;
2290 Status
= MtrrLibApplyVariableMtrrs (
2291 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2292 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
);
2293 ASSERT_RETURN_ERROR (Status
);
2295 ASSERT (OriginalVariableMtrrCount
>= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
));
2296 FirmwareVariableMtrrCount
= OriginalVariableMtrrCount
- PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
2297 ASSERT (WorkingRangeCount
<= 2 * FirmwareVariableMtrrCount
+ 1);
2300 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2302 Status
= MtrrLibSetMemoryType (
2303 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2304 0, SIZE_1MB
, CacheUncacheable
2306 ASSERT (Status
!= RETURN_OUT_OF_RESOURCES
);
2309 // 2.3. Apply the new memory attribute settings to Ranges.
2312 for (Index
= 0; Index
< RangeCount
; Index
++) {
2313 BaseAddress
= Ranges
[Index
].BaseAddress
;
2314 Length
= Ranges
[Index
].Length
;
2315 if (BaseAddress
< BASE_1MB
) {
2316 if (Length
<= BASE_1MB
- BaseAddress
) {
2319 Length
-= BASE_1MB
- BaseAddress
;
2320 BaseAddress
= BASE_1MB
;
2322 Status
= MtrrLibSetMemoryType (
2323 WorkingRanges
, ARRAY_SIZE (WorkingRanges
), &WorkingRangeCount
,
2324 BaseAddress
, Length
, Ranges
[Index
].Type
2326 if (Status
== RETURN_ALREADY_STARTED
) {
2327 Status
= RETURN_SUCCESS
;
2328 } else if (Status
== RETURN_OUT_OF_RESOURCES
) {
2331 ASSERT_RETURN_ERROR (Status
);
2338 // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2339 // Buffer Too Small may be returned if the scratch buffer size is insufficient.
2341 Status
= MtrrLibSetMemoryRanges (
2342 DefaultType
, LShiftU64 (1, (UINTN
)HighBitSet64 (MtrrValidBitsMask
)), WorkingRanges
, WorkingRangeCount
,
2343 Scratch
, ScratchSize
,
2344 WorkingVariableMtrr
, FirmwareVariableMtrrCount
+ 1, &WorkingVariableMtrrCount
2346 if (RETURN_ERROR (Status
)) {
2351 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2353 for (Index
= 0; Index
< WorkingVariableMtrrCount
; Index
++) {
2354 if (WorkingVariableMtrr
[Index
].BaseAddress
== 0 && WorkingVariableMtrr
[Index
].Length
== SIZE_1MB
) {
2355 ASSERT (WorkingVariableMtrr
[Index
].Type
== CacheUncacheable
);
2356 WorkingVariableMtrrCount
--;
2358 &WorkingVariableMtrr
[Index
], &WorkingVariableMtrr
[Index
+ 1],
2359 (WorkingVariableMtrrCount
- Index
) * sizeof (WorkingVariableMtrr
[0])
2365 if (WorkingVariableMtrrCount
> FirmwareVariableMtrrCount
) {
2366 Status
= RETURN_OUT_OF_RESOURCES
;
2371 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2372 // Make sure least modification is made to OriginalVariableMtrr.
2374 MtrrLibMergeVariableMtrr (
2375 OriginalVariableMtrr
, OriginalVariableMtrrCount
,
2376 WorkingVariableMtrr
, WorkingVariableMtrrCount
,
2377 VariableSettingModified
2383 // 3. Apply the below-1MB memory attribute settings.
2385 // (Value & ~0 | 0) still equals to (Value)
2387 ZeroMem (ClearMasks
, sizeof (ClearMasks
));
2388 ZeroMem (OrMasks
, sizeof (OrMasks
));
2389 for (Index
= 0; Index
< RangeCount
; Index
++) {
2390 if (Ranges
[Index
].BaseAddress
>= BASE_1MB
) {
2394 Status
= MtrrLibSetBelow1MBMemoryAttribute (
2395 ClearMasks
, OrMasks
,
2396 Ranges
[Index
].BaseAddress
, Ranges
[Index
].Length
, Ranges
[Index
].Type
2398 if (RETURN_ERROR (Status
)) {
2403 MtrrContextValid
= FALSE
;
2405 // 4. Write fixed MTRRs that have been modified
2407 for (Index
= 0; Index
< ARRAY_SIZE (ClearMasks
); Index
++) {
2408 if (ClearMasks
[Index
] != 0) {
2409 if (MtrrSetting
!= NULL
) {
2410 MtrrSetting
->Fixed
.Mtrr
[Index
] = (MtrrSetting
->Fixed
.Mtrr
[Index
] & ~ClearMasks
[Index
]) | OrMasks
[Index
];
2412 if (!MtrrContextValid
) {
2413 MtrrLibPreMtrrChange (&MtrrContext
);
2414 MtrrContextValid
= TRUE
;
2416 AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
, ~ClearMasks
[Index
], OrMasks
[Index
]);
2422 // 5. Write variable MTRRs that have been modified
2424 for (Index
= 0; Index
< OriginalVariableMtrrCount
; Index
++) {
2425 if (VariableSettingModified
[Index
]) {
2426 if (OriginalVariableMtrr
[Index
].Length
!= 0) {
2427 VariableSetting
.Base
= (OriginalVariableMtrr
[Index
].BaseAddress
& MtrrValidAddressMask
)
2428 | (UINT8
)OriginalVariableMtrr
[Index
].Type
;
2429 VariableSetting
.Mask
= ((~(OriginalVariableMtrr
[Index
].Length
- 1)) & MtrrValidAddressMask
) | BIT11
;
2431 VariableSetting
.Base
= 0;
2432 VariableSetting
.Mask
= 0;
2434 if (MtrrSetting
!= NULL
) {
2435 CopyMem (&MtrrSetting
->Variables
.Mtrr
[Index
], &VariableSetting
, sizeof (VariableSetting
));
2437 if (!MtrrContextValid
) {
2438 MtrrLibPreMtrrChange (&MtrrContext
);
2439 MtrrContextValid
= TRUE
;
2442 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2443 VariableSetting
.Base
2446 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2447 VariableSetting
.Mask
2453 if (MtrrSetting
!= NULL
) {
2454 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.E
= 1;
2455 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER
*)&MtrrSetting
->MtrrDefType
)->Bits
.FE
= 1;
2457 if (MtrrContextValid
) {
2458 MtrrLibPostMtrrChange (&MtrrContext
);
2463 DEBUG ((DEBUG_CACHE
, " Result = %r\n", Status
));
2464 if (!RETURN_ERROR (Status
)) {
2465 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
2471 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2473 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2474 @param[in] BaseAddress The physical address that is the start address
2476 @param[in] Length The size in bytes of the memory range.
2477 @param[in] Attribute The bit mask of attributes to set for the
2480 @retval RETURN_SUCCESS The attributes were set for the memory range.
2481 @retval RETURN_INVALID_PARAMETER Length is zero.
2482 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2483 memory resource range specified by BaseAddress and Length.
2484 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2485 range specified by BaseAddress and Length.
2486 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2487 BaseAddress and Length cannot be modified.
2488 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2489 the memory resource range.
2490 Multiple memory range attributes setting by calling this API multiple
2491 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2492 the number of CPU MTRRs are too small to set such memory attributes.
2493 Pass the multiple memory range attributes to one call of
2494 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2495 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2496 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2497 external scratch buffer.
2501 MtrrSetMemoryAttributeInMtrrSettings (
2502 IN OUT MTRR_SETTINGS
*MtrrSetting
,
2503 IN PHYSICAL_ADDRESS BaseAddress
,
2505 IN MTRR_MEMORY_CACHE_TYPE Attribute
2508 UINT8 Scratch
[SCRATCH_BUFFER_SIZE
];
2510 MTRR_MEMORY_RANGE Range
;
2512 Range
.BaseAddress
= BaseAddress
;
2513 Range
.Length
= Length
;
2514 Range
.Type
= Attribute
;
2515 ScratchSize
= sizeof (Scratch
);
2516 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting
, Scratch
, &ScratchSize
, &Range
, 1);
2520 This function attempts to set the attributes for a memory range.
2522 @param[in] BaseAddress The physical address that is the start
2523 address of a memory range.
2524 @param[in] Length The size in bytes of the memory range.
2525 @param[in] Attributes The bit mask of attributes to set for the
2528 @retval RETURN_SUCCESS The attributes were set for the memory
2530 @retval RETURN_INVALID_PARAMETER Length is zero.
2531 @retval RETURN_UNSUPPORTED The processor does not support one or
2532 more bytes of the memory resource range
2533 specified by BaseAddress and Length.
2534 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2535 for the memory resource range specified
2536 by BaseAddress and Length.
2537 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2538 range specified by BaseAddress and Length
2540 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2541 modify the attributes of the memory
2543 Multiple memory range attributes setting by calling this API multiple
2544 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2545 the number of CPU MTRRs are too small to set such memory attributes.
2546 Pass the multiple memory range attributes to one call of
2547 MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2548 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
2549 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2550 external scratch buffer.
2554 MtrrSetMemoryAttribute (
2555 IN PHYSICAL_ADDRESS BaseAddress
,
2557 IN MTRR_MEMORY_CACHE_TYPE Attribute
2560 return MtrrSetMemoryAttributeInMtrrSettings (NULL
, BaseAddress
, Length
, Attribute
);
2564 Worker function setting variable MTRRs
2566 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2570 MtrrSetVariableMtrrWorker (
2571 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2575 UINT32 VariableMtrrCount
;
2577 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2578 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (VariableSettings
->Mtrr
));
2580 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2582 MSR_IA32_MTRR_PHYSBASE0
+ (Index
<< 1),
2583 VariableSettings
->Mtrr
[Index
].Base
2586 MSR_IA32_MTRR_PHYSMASK0
+ (Index
<< 1),
2587 VariableSettings
->Mtrr
[Index
].Mask
2594 This function sets variable MTRRs
2596 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2598 @return The pointer of VariableSettings
2601 MTRR_VARIABLE_SETTINGS
*
2603 MtrrSetVariableMtrr (
2604 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
2607 MTRR_CONTEXT MtrrContext
;
2609 if (!IsMtrrSupported ()) {
2610 return VariableSettings
;
2613 MtrrLibPreMtrrChange (&MtrrContext
);
2614 MtrrSetVariableMtrrWorker (VariableSettings
);
2615 MtrrLibPostMtrrChange (&MtrrContext
);
2616 MtrrDebugPrintAllMtrrs ();
2618 return VariableSettings
;
2622 Worker function setting fixed MTRRs
2624 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2628 MtrrSetFixedMtrrWorker (
2629 IN MTRR_FIXED_SETTINGS
*FixedSettings
2634 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
2636 mMtrrLibFixedMtrrTable
[Index
].Msr
,
2637 FixedSettings
->Mtrr
[Index
]
2644 This function sets fixed MTRRs
2646 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2648 @retval The pointer of FixedSettings
2651 MTRR_FIXED_SETTINGS
*
2654 IN MTRR_FIXED_SETTINGS
*FixedSettings
2657 MTRR_CONTEXT MtrrContext
;
2659 if (!IsMtrrSupported ()) {
2660 return FixedSettings
;
2663 MtrrLibPreMtrrChange (&MtrrContext
);
2664 MtrrSetFixedMtrrWorker (FixedSettings
);
2665 MtrrLibPostMtrrChange (&MtrrContext
);
2666 MtrrDebugPrintAllMtrrs ();
2668 return FixedSettings
;
2673 This function gets the content in all MTRRs (variable and fixed)
2675 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2677 @retval the pointer of MtrrSetting
2683 OUT MTRR_SETTINGS
*MtrrSetting
2686 if (!IsMtrrSupported ()) {
2693 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2696 // Get variable MTRRs
2698 MtrrGetVariableMtrrWorker (
2700 GetVariableMtrrCountWorker (),
2701 &MtrrSetting
->Variables
2705 // Get MTRR_DEF_TYPE value
2707 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE
);
2714 This function sets all MTRRs (variable and fixed)
2716 @param[in] MtrrSetting A buffer holding all MTRRs content.
2718 @retval The pointer of MtrrSetting
2724 IN MTRR_SETTINGS
*MtrrSetting
2727 MTRR_CONTEXT MtrrContext
;
2729 if (!IsMtrrSupported ()) {
2733 MtrrLibPreMtrrChange (&MtrrContext
);
2738 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2741 // Set variable MTRRs
2743 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2746 // Set MTRR_DEF_TYPE value
2748 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2750 MtrrLibPostMtrrChangeEnableCache (&MtrrContext
);
2757 Checks if MTRR is supported.
2759 @retval TRUE MTRR is supported.
2760 @retval FALSE MTRR is not supported.
2769 CPUID_VERSION_INFO_EDX Edx
;
2770 MSR_IA32_MTRRCAP_REGISTER MtrrCap
;
2773 // Check CPUID(1).EDX[12] for MTRR capability
2775 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
2776 if (Edx
.Bits
.MTRR
== 0) {
2781 // Check number of variable MTRRs and fixed MTRRs existence.
2782 // If number of variable MTRRs is zero, or fixed MTRRs do not
2783 // exist, return false.
2785 MtrrCap
.Uint64
= AsmReadMsr64 (MSR_IA32_MTRRCAP
);
2786 if ((MtrrCap
.Bits
.VCNT
== 0) || (MtrrCap
.Bits
.FIX
== 0)) {
2794 Worker function prints all MTRRs for debugging.
2796 If MtrrSetting is not NULL, print MTRR settings from input MTRR
2798 If MtrrSetting is NULL, print MTRR settings from MTRRs.
2800 @param MtrrSetting A buffer holding all MTRRs content.
2803 MtrrDebugPrintAllMtrrsWorker (
2804 IN MTRR_SETTINGS
*MtrrSetting
2808 MTRR_SETTINGS LocalMtrrs
;
2809 MTRR_SETTINGS
*Mtrrs
;
2812 UINT64 MtrrValidBitsMask
;
2813 UINT64 MtrrValidAddressMask
;
2814 UINT32 VariableMtrrCount
;
2815 BOOLEAN ContainVariableMtrr
;
2816 MTRR_MEMORY_RANGE Ranges
[
2817 ARRAY_SIZE (mMtrrLibFixedMtrrTable
) * sizeof (UINT64
) + 2 * ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
) + 1
2819 MTRR_MEMORY_RANGE RawVariableRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
2821 if (!IsMtrrSupported ()) {
2825 VariableMtrrCount
= GetVariableMtrrCountWorker ();
2827 if (MtrrSetting
!= NULL
) {
2828 Mtrrs
= MtrrSetting
;
2830 MtrrGetAllMtrrs (&LocalMtrrs
);
2831 Mtrrs
= &LocalMtrrs
;
2835 // Dump RAW MTRR contents
2837 DEBUG ((DEBUG_CACHE
, "MTRR Settings:\n"));
2838 DEBUG ((DEBUG_CACHE
, "=============\n"));
2839 DEBUG ((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
2840 for (Index
= 0; Index
< ARRAY_SIZE (mMtrrLibFixedMtrrTable
); Index
++) {
2841 DEBUG ((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
2843 ContainVariableMtrr
= FALSE
;
2844 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
2845 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
2847 // If mask is not valid, then do not display range
2851 ContainVariableMtrr
= TRUE
;
2852 DEBUG ((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2854 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
2855 Mtrrs
->Variables
.Mtrr
[Index
].Mask
2858 if (!ContainVariableMtrr
) {
2859 DEBUG ((DEBUG_CACHE
, "Variable MTRR : None.\n"));
2861 DEBUG((DEBUG_CACHE
, "\n"));
2864 // Dump MTRR setting in ranges
2866 DEBUG((DEBUG_CACHE
, "Memory Ranges:\n"));
2867 DEBUG((DEBUG_CACHE
, "====================================\n"));
2868 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
2869 Ranges
[0].BaseAddress
= 0;
2870 Ranges
[0].Length
= MtrrValidBitsMask
+ 1;
2871 Ranges
[0].Type
= MtrrGetDefaultMemoryTypeWorker (Mtrrs
);
2874 MtrrLibGetRawVariableRanges (
2875 &Mtrrs
->Variables
, VariableMtrrCount
,
2876 MtrrValidBitsMask
, MtrrValidAddressMask
, RawVariableRanges
2878 MtrrLibApplyVariableMtrrs (
2879 RawVariableRanges
, VariableMtrrCount
,
2880 Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
2883 MtrrLibApplyFixedMtrrs (&Mtrrs
->Fixed
, Ranges
, ARRAY_SIZE (Ranges
), &RangeCount
);
2885 for (Index
= 0; Index
< RangeCount
; Index
++) {
2886 DEBUG ((DEBUG_CACHE
, "%a:%016lx-%016lx\n",
2887 mMtrrMemoryCacheTypeShortName
[Ranges
[Index
].Type
],
2888 Ranges
[Index
].BaseAddress
, Ranges
[Index
].BaseAddress
+ Ranges
[Index
].Length
- 1
2895 This function prints all MTRRs for debugging.
2899 MtrrDebugPrintAllMtrrs (
2903 MtrrDebugPrintAllMtrrsWorker (NULL
);