4 Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
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
27 // Context to save and restore when MTRRs are programmed
31 BOOLEAN InterruptState
;
35 // This table defines the offset, base and length of the fixed MTRRs
37 CONST FIXED_MTRR mMtrrLibFixedMtrrTable
[] = {
39 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
44 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
49 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
54 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
59 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
64 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
69 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
74 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
79 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
84 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
89 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
96 // Lookup table used to print MTRRs
98 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mMtrrMemoryCacheTypeShortName
[] = {
99 "UC", // CacheUncacheable
100 "WC", // CacheWriteCombining
103 "WT", // CacheWriteThrough
104 "WP", // CacheWriteProtected
105 "WB", // CacheWriteBack
110 Worker function returns the variable MTRR count for the CPU.
112 @return Variable MTRR count
116 GetVariableMtrrCountWorker (
120 UINT32 VariableMtrrCount
;
122 VariableMtrrCount
= (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
123 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
124 return VariableMtrrCount
;
128 Returns the variable MTRR count for the CPU.
130 @return Variable MTRR count
135 GetVariableMtrrCount (
139 if (!IsMtrrSupported ()) {
142 return GetVariableMtrrCountWorker ();
146 Worker function returns the firmware usable variable MTRR count for the CPU.
148 @return Firmware usable variable MTRR count
152 GetFirmwareVariableMtrrCountWorker (
156 UINT32 VariableMtrrCount
;
157 UINT32 ReservedMtrrNumber
;
159 VariableMtrrCount
= GetVariableMtrrCountWorker ();
160 ReservedMtrrNumber
= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs
);
161 if (VariableMtrrCount
< ReservedMtrrNumber
) {
165 return VariableMtrrCount
- ReservedMtrrNumber
;
169 Returns the firmware usable variable MTRR count for the CPU.
171 @return Firmware usable variable MTRR count
176 GetFirmwareVariableMtrrCount (
180 if (!IsMtrrSupported ()) {
183 return GetFirmwareVariableMtrrCountWorker ();
187 Worker function returns the default MTRR cache type for the system.
189 If MtrrSetting is not NULL, returns the default MTRR cache type from input
190 MTRR settings buffer.
191 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
193 @param[in] MtrrSetting A buffer holding all MTRRs content.
195 @return The default MTRR cache type.
198 MTRR_MEMORY_CACHE_TYPE
199 MtrrGetDefaultMemoryTypeWorker (
200 IN MTRR_SETTINGS
*MtrrSetting
203 if (MtrrSetting
== NULL
) {
204 return (MTRR_MEMORY_CACHE_TYPE
) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0x7);
206 return (MTRR_MEMORY_CACHE_TYPE
) (MtrrSetting
->MtrrDefType
& 0x7);
212 Returns the default MTRR cache type for the system.
214 @return The default MTRR cache type.
217 MTRR_MEMORY_CACHE_TYPE
219 MtrrGetDefaultMemoryType (
223 if (!IsMtrrSupported ()) {
224 return CacheUncacheable
;
226 return MtrrGetDefaultMemoryTypeWorker (NULL
);
230 Preparation before programming MTRR.
232 This function will do some preparation for programming MTRRs:
233 disable cache, invalid cache and disable MTRR caching functionality
235 @param[out] MtrrContext Pointer to context to save
240 OUT MTRR_CONTEXT
*MtrrContext
244 // Disable interrupts and save current interrupt state
246 MtrrContext
->InterruptState
= SaveAndDisableInterrupts();
249 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
254 // Save original CR4 value and clear PGE flag (Bit 7)
256 MtrrContext
->Cr4
= AsmReadCr4 ();
257 AsmWriteCr4 (MtrrContext
->Cr4
& (~BIT7
));
267 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
271 Cleaning up after programming MTRRs.
273 This function will do some clean up after programming MTRRs:
274 Flush all TLBs, re-enable caching, restore CR4.
276 @param[in] MtrrContext Pointer to context to restore
280 PostMtrrChangeEnableCache (
281 IN MTRR_CONTEXT
*MtrrContext
290 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
295 // Restore original CR4 value
297 AsmWriteCr4 (MtrrContext
->Cr4
);
300 // Restore original interrupt state
302 SetInterruptState (MtrrContext
->InterruptState
);
306 Cleaning up after programming MTRRs.
308 This function will do some clean up after programming MTRRs:
309 enable MTRR caching functionality, and enable cache
311 @param[in] MtrrContext Pointer to context to restore
316 IN MTRR_CONTEXT
*MtrrContext
322 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
324 PostMtrrChangeEnableCache (MtrrContext
);
328 Worker function gets the content in fixed MTRRs
330 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
332 @retval The pointer of FixedSettings
336 MtrrGetFixedMtrrWorker (
337 OUT MTRR_FIXED_SETTINGS
*FixedSettings
342 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
343 FixedSettings
->Mtrr
[Index
] =
344 AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
347 return FixedSettings
;
352 This function gets the content in fixed MTRRs
354 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
356 @retval The pointer of FixedSettings
362 OUT MTRR_FIXED_SETTINGS
*FixedSettings
365 if (!IsMtrrSupported ()) {
366 return FixedSettings
;
369 return MtrrGetFixedMtrrWorker (FixedSettings
);
374 Worker function will get the raw value in variable MTRRs
376 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
377 MTRR settings buffer.
378 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
380 @param[in] MtrrSetting A buffer holding all MTRRs content.
381 @param[in] VariableMtrrCount Number of variable MTRRs.
382 @param[out] VariableSettings A buffer to hold variable MTRRs content.
384 @return The VariableSettings input pointer
387 MTRR_VARIABLE_SETTINGS
*
388 MtrrGetVariableMtrrWorker (
389 IN MTRR_SETTINGS
*MtrrSetting
,
390 IN UINT32 VariableMtrrCount
,
391 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
396 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
398 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
399 if (MtrrSetting
== NULL
) {
400 VariableSettings
->Mtrr
[Index
].Base
=
401 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
402 VariableSettings
->Mtrr
[Index
].Mask
=
403 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
405 VariableSettings
->Mtrr
[Index
].Base
= MtrrSetting
->Variables
.Mtrr
[Index
].Base
;
406 VariableSettings
->Mtrr
[Index
].Mask
= MtrrSetting
->Variables
.Mtrr
[Index
].Mask
;
410 return VariableSettings
;
414 This function will get the raw value in variable MTRRs
416 @param[out] VariableSettings A buffer to hold variable MTRRs content.
418 @return The VariableSettings input pointer
421 MTRR_VARIABLE_SETTINGS
*
423 MtrrGetVariableMtrr (
424 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
427 if (!IsMtrrSupported ()) {
428 return VariableSettings
;
431 return MtrrGetVariableMtrrWorker (
433 GetVariableMtrrCountWorker (),
439 Programs fixed MTRRs registers.
441 @param[in] MemoryCacheType The memory type to set.
442 @param[in, out] Base The base address of memory range.
443 @param[in, out] Length The length of memory range.
444 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.
445 On return, the current index of the fixed MTRR MSR to program.
446 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
447 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
449 @retval RETURN_SUCCESS The cache type was updated successfully
450 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
456 IN UINT64 MemoryCacheType
,
458 IN OUT UINT64
*Length
,
459 IN OUT UINT32
*LastMsrNum
,
460 OUT UINT64
*ReturnClearMask
,
461 OUT UINT64
*ReturnOrMask
465 UINT32 LeftByteShift
;
466 UINT32 RightByteShift
;
472 // Find the fixed MTRR index to be programmed
474 for (MsrNum
= *LastMsrNum
+ 1; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
475 if ((*Base
>= mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
478 mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
479 (8 * mMtrrLibFixedMtrrTable
[MsrNum
].Length
)
487 if (MsrNum
>= MTRR_NUMBER_OF_FIXED_MTRR
) {
488 return RETURN_UNSUPPORTED
;
492 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
494 LeftByteShift
= ((UINT32
)*Base
- mMtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
)
495 / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
497 if (LeftByteShift
>= 8) {
498 return RETURN_UNSUPPORTED
;
502 // Find the end offset in fixed MTRR and calculate byte offset of right shift
504 SubLength
= mMtrrLibFixedMtrrTable
[MsrNum
].Length
* (8 - LeftByteShift
);
505 if (*Length
>= SubLength
) {
508 RightByteShift
= 8 - LeftByteShift
-
509 (UINT32
)(*Length
) / mMtrrLibFixedMtrrTable
[MsrNum
].Length
;
510 if ((LeftByteShift
>= 8) ||
511 (((UINT32
)(*Length
) % mMtrrLibFixedMtrrTable
[MsrNum
].Length
) != 0)
513 return RETURN_UNSUPPORTED
;
516 // Update SubLength by actual length
521 ClearMask
= CLEAR_SEED
;
522 OrMask
= MultU64x32 (OR_SEED
, (UINT32
)MemoryCacheType
);
524 if (LeftByteShift
!= 0) {
526 // Clear the low bits by LeftByteShift
528 ClearMask
&= LShiftU64 (ClearMask
, LeftByteShift
* 8);
529 OrMask
&= LShiftU64 (OrMask
, LeftByteShift
* 8);
532 if (RightByteShift
!= 0) {
534 // Clear the high bits by RightByteShift
536 ClearMask
&= RShiftU64 (ClearMask
, RightByteShift
* 8);
537 OrMask
&= RShiftU64 (OrMask
, RightByteShift
* 8);
540 *Length
-= SubLength
;
543 *LastMsrNum
= MsrNum
;
544 *ReturnClearMask
= ClearMask
;
545 *ReturnOrMask
= OrMask
;
547 return RETURN_SUCCESS
;
552 Worker function gets the attribute of variable MTRRs.
554 This function shadows the content of variable MTRRs into an
555 internal array: VariableMtrr.
557 @param[in] VariableSettings The variable MTRR values to shadow
558 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware
559 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
560 @param[in] MtrrValidAddressMask The valid address mask for MTRR
561 @param[out] VariableMtrr The array to shadow variable MTRRs content
563 @return The return value of this parameter indicates the
564 number of MTRRs which has been used.
568 MtrrGetMemoryAttributeInVariableMtrrWorker (
569 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
,
570 IN UINTN FirmwareVariableMtrrCount
,
571 IN UINT64 MtrrValidBitsMask
,
572 IN UINT64 MtrrValidAddressMask
,
573 OUT VARIABLE_MTRR
*VariableMtrr
579 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
580 for (Index
= 0, UsedMtrr
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
581 if ((VariableSettings
->Mtrr
[Index
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
582 VariableMtrr
[Index
].Msr
= (UINT32
)Index
;
583 VariableMtrr
[Index
].BaseAddress
= (VariableSettings
->Mtrr
[Index
].Base
& MtrrValidAddressMask
);
584 VariableMtrr
[Index
].Length
= ((~(VariableSettings
->Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
585 VariableMtrr
[Index
].Type
= (VariableSettings
->Mtrr
[Index
].Base
& 0x0ff);
586 VariableMtrr
[Index
].Valid
= TRUE
;
587 VariableMtrr
[Index
].Used
= TRUE
;
596 Gets the attribute of variable MTRRs.
598 This function shadows the content of variable MTRRs into an
599 internal array: VariableMtrr.
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 The return value of this paramter indicates the
606 number of MTRRs which has been used.
611 MtrrGetMemoryAttributeInVariableMtrr (
612 IN UINT64 MtrrValidBitsMask
,
613 IN UINT64 MtrrValidAddressMask
,
614 OUT VARIABLE_MTRR
*VariableMtrr
617 MTRR_VARIABLE_SETTINGS VariableSettings
;
619 if (!IsMtrrSupported ()) {
623 MtrrGetVariableMtrrWorker (
625 GetVariableMtrrCountWorker (),
629 return MtrrGetMemoryAttributeInVariableMtrrWorker (
631 GetFirmwareVariableMtrrCountWorker (),
633 MtrrValidAddressMask
,
640 Checks overlap between given memory range and MTRRs.
642 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available
644 @param[in] Start The start address of memory range.
645 @param[in] End The end address of memory range.
646 @param[in] VariableMtrr The array to shadow variable MTRRs content
648 @retval TRUE Overlap exists.
649 @retval FALSE No overlap.
653 CheckMemoryAttributeOverlap (
654 IN UINTN FirmwareVariableMtrrCount
,
655 IN PHYSICAL_ADDRESS Start
,
656 IN PHYSICAL_ADDRESS End
,
657 IN VARIABLE_MTRR
*VariableMtrr
662 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
664 VariableMtrr
[Index
].Valid
&&
666 (Start
> (VariableMtrr
[Index
].BaseAddress
+
667 VariableMtrr
[Index
].Length
- 1)
669 (End
< VariableMtrr
[Index
].BaseAddress
)
681 Marks a variable MTRR as non-valid.
683 @param[in] Index The index of the array VariableMtrr to be invalidated
684 @param[in] VariableMtrr The array to shadow variable MTRRs content
685 @param[out] UsedMtrr The number of MTRRs which has already been used
689 InvalidateShadowMtrr (
691 IN VARIABLE_MTRR
*VariableMtrr
,
695 VariableMtrr
[Index
].Valid
= FALSE
;
696 *UsedMtrr
= *UsedMtrr
- 1;
701 Combines memory attributes.
703 If overlap exists between given memory range and MTRRs, try to combine them.
705 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs
706 available to firmware.
707 @param[in] Attributes The memory type to set.
708 @param[in, out] Base The base address of memory range.
709 @param[in, out] Length The length of memory range.
710 @param[in] VariableMtrr The array to shadow variable MTRRs content
711 @param[in, out] UsedMtrr The number of MTRRs which has already been used
712 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
714 @retval EFI_SUCCESS Memory region successfully combined.
715 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
719 CombineMemoryAttribute (
720 IN UINT32 FirmwareVariableMtrrCount
,
721 IN UINT64 Attributes
,
723 IN OUT UINT64
*Length
,
724 IN VARIABLE_MTRR
*VariableMtrr
,
725 IN OUT UINT32
*UsedMtrr
,
726 OUT BOOLEAN
*OverwriteExistingMtrr
734 BOOLEAN CoveredByExistingMtrr
;
736 *OverwriteExistingMtrr
= FALSE
;
737 CoveredByExistingMtrr
= FALSE
;
738 EndAddress
= *Base
+*Length
- 1;
740 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
742 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
744 !VariableMtrr
[Index
].Valid
||
747 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
754 // Combine same attribute MTRR range
756 if (Attributes
== VariableMtrr
[Index
].Type
) {
758 // if the MTRR range contain the request range, set a flag, then continue to
759 // invalidate any MTRR of the same request range with higher priority cache type.
761 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
762 CoveredByExistingMtrr
= TRUE
;
766 // invalid this MTRR, and program the combine range
769 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
771 VariableMtrr
[Index
].BaseAddress
;
772 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
775 // Record the MTRR usage status in VariableMtrr array.
777 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
778 *Base
= CombineStart
;
779 *Length
= CombineEnd
- CombineStart
+ 1;
780 EndAddress
= CombineEnd
;
781 *OverwriteExistingMtrr
= TRUE
;
785 // The cache type is different, but the range is convered by one MTRR
787 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
788 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
794 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
795 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
796 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
797 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
798 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
799 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
801 *OverwriteExistingMtrr
= TRUE
;
805 // Other type memory overlap is invalid
807 return RETURN_ACCESS_DENIED
;
810 if (CoveredByExistingMtrr
) {
814 return RETURN_SUCCESS
;
819 Calculates the maximum value which is a power of 2, but less the MemoryLength.
821 @param[in] MemoryLength The number to pass in.
823 @return The maximum value which is align to power of 2 and less the MemoryLength
828 IN UINT64 MemoryLength
833 if (RShiftU64 (MemoryLength
, 32) != 0) {
835 (UINT64
) GetPowerOfTwo32 (
836 (UINT32
) RShiftU64 (MemoryLength
, 32)
841 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
849 Determines the MTRR numbers used to program a memory range.
851 This function first checks the alignment of the base address.
852 If the alignment of the base address <= Length, cover the memory range
853 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
854 Length -= alignment. Repeat the step until alignment > Length.
856 Then this function determines which direction of programming the variable
857 MTRRs for the remaining length will use fewer MTRRs.
859 @param[in] BaseAddress Length of Memory to program MTRR
860 @param[in] Length Length of Memory to program MTRR
861 @param[in] MtrrNumber Pointer to the number of necessary MTRRs
863 @retval TRUE Positive direction is better.
864 FALSE Negative direction is better.
868 GetMtrrNumberAndDirection (
869 IN UINT64 BaseAddress
,
881 if (BaseAddress
!= 0) {
884 // Calculate the alignment of the base address.
886 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
888 if (Alignment
> Length
) {
893 BaseAddress
+= Alignment
;
907 TempQword
-= Power2MaxMemory (TempQword
);
909 } while (TempQword
!= 0);
911 TempQword
= Power2MaxMemory (LShiftU64 (Length
, 1)) - Length
;
914 TempQword
-= Power2MaxMemory (TempQword
);
916 } while (TempQword
!= 0);
918 if (Positive
<= Subtractive
) {
919 *MtrrNumber
+= Positive
;
922 *MtrrNumber
+= Subtractive
;
928 Invalid variable MTRRs according to the value in the shadow array.
930 This function programs MTRRs according to the values specified
933 @param[in, out] VariableSettings Variable MTRR settings
934 @param[in] VariableMtrrCount Number of variable MTRRs
935 @param[in, out] VariableMtrr Shadow of variable MTRR contents
940 IN OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
,
941 IN UINTN VariableMtrrCount
,
942 IN OUT VARIABLE_MTRR
*VariableMtrr
947 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
948 if (!VariableMtrr
[Index
].Valid
&& VariableMtrr
[Index
].Used
) {
949 VariableSettings
->Mtrr
[Index
].Base
= 0;
950 VariableSettings
->Mtrr
[Index
].Mask
= 0;
951 VariableMtrr
[Index
].Used
= FALSE
;
958 Programs variable MTRRs
960 This function programs variable MTRRs
962 @param[in, out] VariableSettings Variable MTRR settings.
963 @param[in] MtrrNumber Index of MTRR to program.
964 @param[in] BaseAddress Base address of memory region.
965 @param[in] Length Length of memory region.
966 @param[in] MemoryCacheType Memory type to set.
967 @param[in] MtrrValidAddressMask The valid address mask for MTRR
971 ProgramVariableMtrr (
972 IN OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
,
974 IN PHYSICAL_ADDRESS BaseAddress
,
976 IN UINT64 MemoryCacheType
,
977 IN UINT64 MtrrValidAddressMask
983 // MTRR Physical Base
985 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
986 VariableSettings
->Mtrr
[MtrrNumber
].Base
= TempQword
;
989 // MTRR Physical Mask
991 TempQword
= ~(Length
- 1);
992 VariableSettings
->Mtrr
[MtrrNumber
].Mask
= (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
;
997 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
999 If MtrrSetting is not NULL, gets the default memory attribute from input
1000 MTRR settings buffer.
1001 If MtrrSetting is NULL, gets the default memory attribute from MSR.
1003 @param[in] MtrrSetting A buffer holding all MTRRs content.
1004 @param[in] MtrrType MTRR memory type
1006 @return The enum item in MTRR_MEMORY_CACHE_TYPE
1009 MTRR_MEMORY_CACHE_TYPE
1010 GetMemoryCacheTypeFromMtrrType (
1011 IN MTRR_SETTINGS
*MtrrSetting
,
1016 case MTRR_CACHE_UNCACHEABLE
:
1017 return CacheUncacheable
;
1018 case MTRR_CACHE_WRITE_COMBINING
:
1019 return CacheWriteCombining
;
1020 case MTRR_CACHE_WRITE_THROUGH
:
1021 return CacheWriteThrough
;
1022 case MTRR_CACHE_WRITE_PROTECTED
:
1023 return CacheWriteProtected
;
1024 case MTRR_CACHE_WRITE_BACK
:
1025 return CacheWriteBack
;
1028 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
1029 // no MTRR covers the range
1031 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting
);
1036 Initializes the valid bits mask and valid address mask for MTRRs.
1038 This function initializes the valid bits mask and valid address mask for MTRRs.
1040 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
1041 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
1045 MtrrLibInitializeMtrrMask (
1046 OUT UINT64
*MtrrValidBitsMask
,
1047 OUT UINT64
*MtrrValidAddressMask
1051 UINT8 PhysicalAddressBits
;
1053 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1055 if (RegEax
>= 0x80000008) {
1056 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1058 PhysicalAddressBits
= (UINT8
) RegEax
;
1060 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
1061 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
1063 *MtrrValidBitsMask
= MTRR_LIB_MSR_VALID_MASK
;
1064 *MtrrValidAddressMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
1070 Determines the real attribute of a memory range.
1072 This function is to arbitrate the real attribute of the memory when
1073 there are 2 MTRRs covers the same memory range. For further details,
1074 please refer the IA32 Software Developer's Manual, Volume 3,
1077 @param[in] MtrrType1 The first kind of Memory type
1078 @param[in] MtrrType2 The second kind of memory type
1083 IN UINT64 MtrrType1
,
1089 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1090 switch (MtrrType1
) {
1091 case MTRR_CACHE_UNCACHEABLE
:
1092 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
1094 case MTRR_CACHE_WRITE_COMBINING
:
1096 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
1097 MtrrType2
==MTRR_CACHE_UNCACHEABLE
1099 MtrrType
= MtrrType2
;
1102 case MTRR_CACHE_WRITE_THROUGH
:
1104 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
1105 MtrrType2
==MTRR_CACHE_WRITE_BACK
1107 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
1108 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
1109 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
1112 case MTRR_CACHE_WRITE_PROTECTED
:
1113 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
1114 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
1115 MtrrType
= MtrrType2
;
1118 case MTRR_CACHE_WRITE_BACK
:
1120 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
1121 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
1122 MtrrType2
== MTRR_CACHE_WRITE_BACK
1124 MtrrType
= MtrrType2
;
1127 case MTRR_CACHE_INVALID_TYPE
:
1128 MtrrType
= MtrrType2
;
1134 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
1135 MtrrType
= MtrrType1
;
1141 Worker function will get the memory cache type of the specific address.
1143 If MtrrSetting is not NULL, gets the memory cache type from input
1144 MTRR settings buffer.
1145 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1147 @param[in] MtrrSetting A buffer holding all MTRRs content.
1148 @param[in] Address The specific address
1150 @return Memory cache type of the specific address
1153 MTRR_MEMORY_CACHE_TYPE
1154 MtrrGetMemoryAttributeByAddressWorker (
1155 IN MTRR_SETTINGS
*MtrrSetting
,
1156 IN PHYSICAL_ADDRESS Address
1163 UINT64 TempMtrrType
;
1164 MTRR_MEMORY_CACHE_TYPE CacheType
;
1165 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1166 UINT64 MtrrValidBitsMask
;
1167 UINT64 MtrrValidAddressMask
;
1168 UINTN VariableMtrrCount
;
1169 MTRR_VARIABLE_SETTINGS VariableSettings
;
1172 // Check if MTRR is enabled, if not, return UC as attribute
1174 if (MtrrSetting
== NULL
) {
1175 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1177 TempQword
= MtrrSetting
->MtrrDefType
;
1179 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1181 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1182 return CacheUncacheable
;
1186 // If address is less than 1M, then try to go through the fixed MTRR
1188 if (Address
< BASE_1MB
) {
1189 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1191 // Go through the fixed MTRR
1193 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1194 if (Address
>= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1196 mMtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1197 (mMtrrLibFixedMtrrTable
[Index
].Length
* 8)
1201 ((UINTN
)Address
- mMtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1202 mMtrrLibFixedMtrrTable
[Index
].Length
;
1203 if (MtrrSetting
== NULL
) {
1204 TempQword
= AsmReadMsr64 (mMtrrLibFixedMtrrTable
[Index
].Msr
);
1206 TempQword
= MtrrSetting
->Fixed
.Mtrr
[Index
];
1208 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1209 return GetMemoryCacheTypeFromMtrrType (MtrrSetting
, MtrrType
);
1214 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1216 MtrrGetVariableMtrrWorker (
1218 GetVariableMtrrCountWorker (),
1222 MtrrGetMemoryAttributeInVariableMtrrWorker (
1224 GetFirmwareVariableMtrrCountWorker (),
1226 MtrrValidAddressMask
,
1231 // Go through the variable MTRR
1233 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1234 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1236 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1237 if (VariableMtrr
[Index
].Valid
) {
1238 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1239 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1240 TempMtrrType
= VariableMtrr
[Index
].Type
;
1241 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1245 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrSetting
, MtrrType
);
1252 This function will get the memory cache type of the specific address.
1254 This function is mainly for debug purpose.
1256 @param[in] Address The specific address
1258 @return Memory cache type of the specific address
1261 MTRR_MEMORY_CACHE_TYPE
1263 MtrrGetMemoryAttribute (
1264 IN PHYSICAL_ADDRESS Address
1267 if (!IsMtrrSupported ()) {
1268 return CacheUncacheable
;
1271 return MtrrGetMemoryAttributeByAddressWorker (NULL
, Address
);
1275 Worker function prints all MTRRs for debugging.
1277 If MtrrSetting is not NULL, print MTRR settings from from input MTRR
1279 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1281 @param MtrrSetting A buffer holding all MTRRs content.
1284 MtrrDebugPrintAllMtrrsWorker (
1285 IN MTRR_SETTINGS
*MtrrSetting
1289 MTRR_SETTINGS LocalMtrrs
;
1290 MTRR_SETTINGS
*Mtrrs
;
1293 UINTN VariableMtrrCount
;
1301 UINT64 NoRangeLimit
;
1304 UINTN PreviousMemoryType
;
1307 if (!IsMtrrSupported ()) {
1311 DEBUG((DEBUG_CACHE
, "MTRR Settings\n"));
1312 DEBUG((DEBUG_CACHE
, "=============\n"));
1314 if (MtrrSetting
!= NULL
) {
1315 Mtrrs
= MtrrSetting
;
1317 MtrrGetAllMtrrs (&LocalMtrrs
);
1318 Mtrrs
= &LocalMtrrs
;
1321 DEBUG((DEBUG_CACHE
, "MTRR Default Type: %016lx\n", Mtrrs
->MtrrDefType
));
1322 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1323 DEBUG((DEBUG_CACHE
, "Fixed MTRR[%02d] : %016lx\n", Index
, Mtrrs
->Fixed
.Mtrr
[Index
]));
1326 VariableMtrrCount
= GetVariableMtrrCount ();
1327 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1328 DEBUG((DEBUG_CACHE
, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1330 Mtrrs
->Variables
.Mtrr
[Index
].Base
,
1331 Mtrrs
->Variables
.Mtrr
[Index
].Mask
1334 DEBUG((DEBUG_CACHE
, "\n"));
1335 DEBUG((DEBUG_CACHE
, "MTRR Ranges\n"));
1336 DEBUG((DEBUG_CACHE
, "====================================\n"));
1339 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1340 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1341 Base
= mMtrrLibFixedMtrrTable
[Index
].BaseAddress
;
1342 for (Index1
= 0; Index1
< 8; Index1
++) {
1343 MemoryType
= (UINTN
)(RShiftU64 (Mtrrs
->Fixed
.Mtrr
[Index
], Index1
* 8) & 0xff);
1344 if (MemoryType
> CacheWriteBack
) {
1345 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1347 if (MemoryType
!= PreviousMemoryType
) {
1348 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1349 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1351 PreviousMemoryType
= MemoryType
;
1352 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1354 Base
+= mMtrrLibFixedMtrrTable
[Index
].Length
;
1357 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1359 VariableMtrrCount
= GetVariableMtrrCount ();
1362 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
1363 if (RegEax
>= 0x80000008) {
1364 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
1365 Limit
= LShiftU64 (1, RegEax
& 0xff) - 1;
1368 PreviousMemoryType
= MTRR_CACHE_INVALID_TYPE
;
1370 MemoryType
= MtrrGetMemoryAttributeByAddressWorker (Mtrrs
, Base
);
1371 if (MemoryType
> CacheWriteBack
) {
1372 MemoryType
= MTRR_CACHE_INVALID_TYPE
;
1375 if (MemoryType
!= PreviousMemoryType
) {
1376 if (PreviousMemoryType
!= MTRR_CACHE_INVALID_TYPE
) {
1377 DEBUG((DEBUG_CACHE
, "%016lx\n", Base
- 1));
1379 PreviousMemoryType
= MemoryType
;
1380 DEBUG((DEBUG_CACHE
, "%a:%016lx-", mMtrrMemoryCacheTypeShortName
[MemoryType
], Base
));
1383 RangeBase
= BASE_1MB
;
1384 NoRangeBase
= BASE_1MB
;
1386 NoRangeLimit
= Limit
;
1388 for (Index
= 0, Found
= FALSE
; Index
< VariableMtrrCount
; Index
++) {
1389 if ((Mtrrs
->Variables
.Mtrr
[Index
].Mask
& BIT11
) == 0) {
1391 // If mask is not valid, then do not display range
1395 MtrrBase
= (Mtrrs
->Variables
.Mtrr
[Index
].Base
& (~(SIZE_4KB
- 1)));
1396 MtrrLimit
= MtrrBase
+ ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& (~(SIZE_4KB
- 1)))) & Limit
);
1398 if (Base
>= MtrrBase
&& Base
< MtrrLimit
) {
1402 if (Base
>= MtrrBase
&& MtrrBase
> RangeBase
) {
1403 RangeBase
= MtrrBase
;
1405 if (Base
> MtrrLimit
&& MtrrLimit
> RangeBase
) {
1406 RangeBase
= MtrrLimit
+ 1;
1408 if (Base
< MtrrBase
&& MtrrBase
< RangeLimit
) {
1409 RangeLimit
= MtrrBase
- 1;
1411 if (Base
< MtrrLimit
&& MtrrLimit
<= RangeLimit
) {
1412 RangeLimit
= MtrrLimit
;
1415 if (Base
> MtrrLimit
&& NoRangeBase
< MtrrLimit
) {
1416 NoRangeBase
= MtrrLimit
+ 1;
1418 if (Base
< MtrrBase
&& NoRangeLimit
> MtrrBase
) {
1419 NoRangeLimit
= MtrrBase
- 1;
1424 Base
= RangeLimit
+ 1;
1426 Base
= NoRangeLimit
+ 1;
1428 } while (Base
< Limit
);
1429 DEBUG((DEBUG_CACHE
, "%016lx\n\n", Base
- 1));
1435 This function prints all MTRRs for debugging.
1439 MtrrDebugPrintAllMtrrs (
1443 MtrrDebugPrintAllMtrrsWorker (NULL
);
1448 Worker function attempts to set the attributes for a memory range.
1450 If MtrrSettings is not NULL, set the attributes into the input MTRR
1452 If MtrrSettings is NULL, set the attributes into MTRRs registers.
1454 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1455 @param[in] BaseAddress The physical address that is the start
1456 address of a memory region.
1457 @param[in] Length The size in bytes of the memory region.
1458 @param[in] Attribute The bit mask of attributes to set for the
1461 @retval RETURN_SUCCESS The attributes were set for the memory
1463 @retval RETURN_INVALID_PARAMETER Length is zero.
1464 @retval RETURN_UNSUPPORTED The processor does not support one or
1465 more bytes of the memory resource range
1466 specified by BaseAddress and Length.
1467 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
1468 for the memory resource range specified
1469 by BaseAddress and Length.
1470 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
1471 range specified by BaseAddress and Length
1473 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1474 modify the attributes of the memory
1479 MtrrSetMemoryAttributeWorker (
1480 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1481 IN PHYSICAL_ADDRESS BaseAddress
,
1483 IN MTRR_MEMORY_CACHE_TYPE Attribute
1487 RETURN_STATUS Status
;
1494 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1496 UINT64 MtrrValidBitsMask
;
1497 UINT64 MtrrValidAddressMask
;
1498 BOOLEAN OverwriteExistingMtrr
;
1499 UINT32 FirmwareVariableMtrrCount
;
1500 MTRR_CONTEXT MtrrContext
;
1501 BOOLEAN MtrrContextValid
;
1502 BOOLEAN FixedSettingsValid
[MTRR_NUMBER_OF_FIXED_MTRR
];
1503 BOOLEAN FixedSettingsModified
[MTRR_NUMBER_OF_FIXED_MTRR
];
1504 MTRR_FIXED_SETTINGS WorkingFixedSettings
;
1505 UINT32 VariableMtrrCount
;
1506 MTRR_VARIABLE_SETTINGS OriginalVariableSettings
;
1507 BOOLEAN ProgramVariableSettings
;
1508 MTRR_VARIABLE_SETTINGS WorkingVariableSettings
;
1513 MTRR_VARIABLE_SETTINGS
*VariableSettings
;
1515 MtrrContextValid
= FALSE
;
1516 VariableMtrrCount
= 0;
1517 ZeroMem (&WorkingFixedSettings
, sizeof (WorkingFixedSettings
));
1518 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1519 FixedSettingsValid
[Index
] = FALSE
;
1520 FixedSettingsModified
[Index
] = FALSE
;
1522 ProgramVariableSettings
= FALSE
;
1524 if (!IsMtrrSupported ()) {
1525 Status
= RETURN_UNSUPPORTED
;
1529 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1532 MemoryType
= (UINT64
)Attribute
;
1533 OverwriteExistingMtrr
= FALSE
;
1536 // Check for an invalid parameter
1539 Status
= RETURN_INVALID_PARAMETER
;
1544 (BaseAddress
& ~MtrrValidAddressMask
) != 0 ||
1545 (Length
& ~MtrrValidAddressMask
) != 0
1547 Status
= RETURN_UNSUPPORTED
;
1552 // Check if Fixed MTRR
1554 Status
= RETURN_SUCCESS
;
1555 if (BaseAddress
< BASE_1MB
) {
1556 MsrNum
= (UINT32
)-1;
1557 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
1558 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
, &MsrNum
, &ClearMask
, &OrMask
);
1559 if (RETURN_ERROR (Status
)) {
1562 if (MtrrSetting
!= NULL
) {
1563 MtrrSetting
->Fixed
.Mtrr
[MsrNum
] = (MtrrSetting
->Fixed
.Mtrr
[MsrNum
] & ~ClearMask
) | OrMask
;
1564 MtrrSetting
->MtrrDefType
|= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
;
1566 if (!FixedSettingsValid
[MsrNum
]) {
1567 WorkingFixedSettings
.Mtrr
[MsrNum
] = AsmReadMsr64 (mMtrrLibFixedMtrrTable
[MsrNum
].Msr
);
1568 FixedSettingsValid
[MsrNum
] = TRUE
;
1570 NewValue
= (WorkingFixedSettings
.Mtrr
[MsrNum
] & ~ClearMask
) | OrMask
;
1571 if (WorkingFixedSettings
.Mtrr
[MsrNum
] != NewValue
) {
1572 WorkingFixedSettings
.Mtrr
[MsrNum
] = NewValue
;
1573 FixedSettingsModified
[MsrNum
] = TRUE
;
1580 // A Length of 0 can only make sense for fixed MTTR ranges.
1581 // Since we just handled the fixed MTRRs, we can skip the
1582 // variable MTRR section.
1589 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1590 // we can set the base to 0 to save variable MTRRs.
1592 if (BaseAddress
== BASE_1MB
) {
1598 // Read all variable MTRRs
1600 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1601 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCountWorker ();
1602 if (MtrrSetting
!= NULL
) {
1603 VariableSettings
= &MtrrSetting
->Variables
;
1605 MtrrGetVariableMtrrWorker (NULL
, VariableMtrrCount
, &OriginalVariableSettings
);
1606 CopyMem (&WorkingVariableSettings
, &OriginalVariableSettings
, sizeof (WorkingVariableSettings
));
1607 ProgramVariableSettings
= TRUE
;
1608 VariableSettings
= &WorkingVariableSettings
;
1612 // Check for overlap
1614 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrrWorker (
1616 FirmwareVariableMtrrCount
,
1618 MtrrValidAddressMask
,
1621 OverLap
= CheckMemoryAttributeOverlap (
1622 FirmwareVariableMtrrCount
,
1624 BaseAddress
+ Length
- 1,
1628 Status
= CombineMemoryAttribute (
1629 FirmwareVariableMtrrCount
,
1635 &OverwriteExistingMtrr
1637 if (RETURN_ERROR (Status
)) {
1643 // Combined successfully, invalidate the now-unused MTRRs
1645 InvalidateMtrr (VariableSettings
, VariableMtrrCount
, VariableMtrr
);
1646 Status
= RETURN_SUCCESS
;
1652 // The memory type is the same with the type specified by
1653 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1655 if ((!OverwriteExistingMtrr
) && (Attribute
== MtrrGetDefaultMemoryTypeWorker (MtrrSetting
))) {
1657 // Invalidate the now-unused MTRRs
1659 InvalidateMtrr (VariableSettings
, VariableMtrrCount
, VariableMtrr
);
1663 Positive
= GetMtrrNumberAndDirection (BaseAddress
, Length
, &MtrrNumber
);
1665 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1666 Status
= RETURN_OUT_OF_RESOURCES
;
1671 // Invalidate the now-unused MTRRs
1673 InvalidateMtrr (VariableSettings
, VariableMtrrCount
, VariableMtrr
);
1676 // Find first unused MTRR
1678 for (MsrNum
= 0; MsrNum
< VariableMtrrCount
; MsrNum
++) {
1679 if ((VariableSettings
->Mtrr
[MsrNum
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1684 if (BaseAddress
!= 0) {
1687 // Calculate the alignment of the base address.
1689 Alignment
= LShiftU64 (1, (UINTN
)LowBitSet64 (BaseAddress
));
1691 if (Alignment
> Length
) {
1698 for (; MsrNum
< VariableMtrrCount
; MsrNum
++) {
1699 if ((VariableSettings
->Mtrr
[MsrNum
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1704 ProgramVariableMtrr (
1710 MtrrValidAddressMask
1712 BaseAddress
+= Alignment
;
1713 Length
-= Alignment
;
1724 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1729 for (; MsrNum
< VariableMtrrCount
; MsrNum
++) {
1730 if ((VariableSettings
->Mtrr
[MsrNum
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1735 ProgramVariableMtrr (
1741 MtrrValidAddressMask
1743 BaseAddress
+= Length
;
1744 TempQword
= Length
- TempQword
;
1745 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1752 for (; MsrNum
< VariableMtrrCount
; MsrNum
++) {
1753 if ((VariableSettings
->Mtrr
[MsrNum
].Mask
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1758 Length
= Power2MaxMemory (TempQword
);
1760 BaseAddress
-= Length
;
1763 ProgramVariableMtrr (
1769 MtrrValidAddressMask
1773 BaseAddress
+= Length
;
1775 TempQword
-= Length
;
1777 } while (TempQword
> 0);
1782 // Write fixed MTRRs that have been modified
1784 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1785 if (FixedSettingsModified
[Index
]) {
1786 if (!MtrrContextValid
) {
1787 PreMtrrChange (&MtrrContext
);
1788 MtrrContextValid
= TRUE
;
1791 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1792 WorkingFixedSettings
.Mtrr
[Index
]
1798 // Write variable MTRRs
1800 if (ProgramVariableSettings
) {
1801 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1802 if (WorkingVariableSettings
.Mtrr
[Index
].Base
!= OriginalVariableSettings
.Mtrr
[Index
].Base
||
1803 WorkingVariableSettings
.Mtrr
[Index
].Mask
!= OriginalVariableSettings
.Mtrr
[Index
].Mask
) {
1804 if (!MtrrContextValid
) {
1805 PreMtrrChange (&MtrrContext
);
1806 MtrrContextValid
= TRUE
;
1809 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1810 WorkingVariableSettings
.Mtrr
[Index
].Base
1813 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1814 WorkingVariableSettings
.Mtrr
[Index
].Mask
1819 if (MtrrContextValid
) {
1820 PostMtrrChange (&MtrrContext
);
1823 DEBUG((DEBUG_CACHE
, " Status = %r\n", Status
));
1824 if (!RETURN_ERROR (Status
)) {
1825 if (MtrrSetting
!= NULL
) {
1826 MtrrSetting
->MtrrDefType
|= MTRR_LIB_CACHE_MTRR_ENABLED
;
1828 MtrrDebugPrintAllMtrrsWorker (MtrrSetting
);
1835 This function attempts to set the attributes for a memory range.
1837 @param[in] BaseAddress The physical address that is the start
1838 address of a memory region.
1839 @param[in] Length The size in bytes of the memory region.
1840 @param[in] Attributes The bit mask of attributes to set for the
1843 @retval RETURN_SUCCESS The attributes were set for the memory
1845 @retval RETURN_INVALID_PARAMETER Length is zero.
1846 @retval RETURN_UNSUPPORTED The processor does not support one or
1847 more bytes of the memory resource range
1848 specified by BaseAddress and Length.
1849 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
1850 for the memory resource range specified
1851 by BaseAddress and Length.
1852 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
1853 range specified by BaseAddress and Length
1855 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1856 modify the attributes of the memory
1862 MtrrSetMemoryAttribute (
1863 IN PHYSICAL_ADDRESS BaseAddress
,
1865 IN MTRR_MEMORY_CACHE_TYPE Attribute
1868 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
1869 return MtrrSetMemoryAttributeWorker (
1878 This function attempts to set the attributes into MTRR setting buffer for a memory range.
1880 @param[in, out] MtrrSetting MTRR setting buffer to be set.
1881 @param[in] BaseAddress The physical address that is the start address
1883 @param[in] Length The size in bytes of the memory region.
1884 @param[in] Attribute The bit mask of attributes to set for the
1887 @retval RETURN_SUCCESS The attributes were set for the memory region.
1888 @retval RETURN_INVALID_PARAMETER Length is zero.
1889 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
1890 memory resource range specified by BaseAddress and Length.
1891 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
1892 range specified by BaseAddress and Length.
1893 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
1894 BaseAddress and Length cannot be modified.
1895 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
1896 the memory resource range.
1901 MtrrSetMemoryAttributeInMtrrSettings (
1902 IN OUT MTRR_SETTINGS
*MtrrSetting
,
1903 IN PHYSICAL_ADDRESS BaseAddress
,
1905 IN MTRR_MEMORY_CACHE_TYPE Attribute
1908 DEBUG((DEBUG_CACHE
, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting
, mMtrrMemoryCacheTypeShortName
[Attribute
], BaseAddress
, Length
));
1909 return MtrrSetMemoryAttributeWorker (
1918 Worker function setting variable MTRRs
1920 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1924 MtrrSetVariableMtrrWorker (
1925 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1929 UINT32 VariableMtrrCount
;
1931 VariableMtrrCount
= GetVariableMtrrCountWorker ();
1932 ASSERT (VariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
1934 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1936 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1937 VariableSettings
->Mtrr
[Index
].Base
1940 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1941 VariableSettings
->Mtrr
[Index
].Mask
1948 This function sets variable MTRRs
1950 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1952 @return The pointer of VariableSettings
1955 MTRR_VARIABLE_SETTINGS
*
1957 MtrrSetVariableMtrr (
1958 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1961 MTRR_CONTEXT MtrrContext
;
1963 if (!IsMtrrSupported ()) {
1964 return VariableSettings
;
1967 PreMtrrChange (&MtrrContext
);
1968 MtrrSetVariableMtrrWorker (VariableSettings
);
1969 PostMtrrChange (&MtrrContext
);
1970 MtrrDebugPrintAllMtrrs ();
1972 return VariableSettings
;
1976 Worker function setting fixed MTRRs
1978 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
1982 MtrrSetFixedMtrrWorker (
1983 IN MTRR_FIXED_SETTINGS
*FixedSettings
1988 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1990 mMtrrLibFixedMtrrTable
[Index
].Msr
,
1991 FixedSettings
->Mtrr
[Index
]
1998 This function sets fixed MTRRs
2000 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2002 @retval The pointer of FixedSettings
2005 MTRR_FIXED_SETTINGS
*
2008 IN MTRR_FIXED_SETTINGS
*FixedSettings
2011 MTRR_CONTEXT MtrrContext
;
2013 if (!IsMtrrSupported ()) {
2014 return FixedSettings
;
2017 PreMtrrChange (&MtrrContext
);
2018 MtrrSetFixedMtrrWorker (FixedSettings
);
2019 PostMtrrChange (&MtrrContext
);
2020 MtrrDebugPrintAllMtrrs ();
2022 return FixedSettings
;
2027 This function gets the content in all MTRRs (variable and fixed)
2029 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2031 @retval the pointer of MtrrSetting
2037 OUT MTRR_SETTINGS
*MtrrSetting
2040 if (!IsMtrrSupported ()) {
2047 MtrrGetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2050 // Get variable MTRRs
2052 MtrrGetVariableMtrrWorker (
2054 GetVariableMtrrCountWorker (),
2055 &MtrrSetting
->Variables
2059 // Get MTRR_DEF_TYPE value
2061 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
2068 This function sets all MTRRs (variable and fixed)
2070 @param[in] MtrrSetting A buffer holding all MTRRs content.
2072 @retval The pointer of MtrrSetting
2078 IN MTRR_SETTINGS
*MtrrSetting
2081 MTRR_CONTEXT MtrrContext
;
2083 if (!IsMtrrSupported ()) {
2087 PreMtrrChange (&MtrrContext
);
2092 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
2095 // Set variable MTRRs
2097 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
2100 // Set MTRR_DEF_TYPE value
2102 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
2104 PostMtrrChangeEnableCache (&MtrrContext
);
2111 Checks if MTRR is supported.
2113 @retval TRUE MTRR is supported.
2114 @retval FALSE MTRR is not supported.
2127 // Check CPUID(1).EDX[12] for MTRR capability
2129 AsmCpuid (1, NULL
, NULL
, NULL
, &RegEdx
);
2130 if (BitFieldRead32 (RegEdx
, 12, 12) == 0) {
2135 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
2136 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
2137 // exist, return false.
2139 MtrrCap
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
);
2140 if ((BitFieldRead64 (MtrrCap
, 0, 7) == 0) || (BitFieldRead64 (MtrrCap
, 8, 8) == 0)) {