4 Copyright (c) 2008 - 2010, Intel Corporation
5 All rights reserved. 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>
24 // This table defines the offset, base and length of the fixed MTRRs
27 FIXED_MTRR MtrrLibFixedMtrrTable
[] = {
29 MTRR_LIB_IA32_MTRR_FIX64K_00000
,
34 MTRR_LIB_IA32_MTRR_FIX16K_80000
,
39 MTRR_LIB_IA32_MTRR_FIX16K_A0000
,
44 MTRR_LIB_IA32_MTRR_FIX4K_C0000
,
49 MTRR_LIB_IA32_MTRR_FIX4K_C8000
,
54 MTRR_LIB_IA32_MTRR_FIX4K_D0000
,
59 MTRR_LIB_IA32_MTRR_FIX4K_D8000
,
64 MTRR_LIB_IA32_MTRR_FIX4K_E0000
,
69 MTRR_LIB_IA32_MTRR_FIX4K_E8000
,
74 MTRR_LIB_IA32_MTRR_FIX4K_F0000
,
79 MTRR_LIB_IA32_MTRR_FIX4K_F8000
,
86 Returns the variable MTRR count for the CPU.
88 @return Variable MTRR count
92 GetVariableMtrrCount (
96 return (UINT32
)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP
) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK
);
100 Returns the firmware usable variable MTRR count for the CPU.
102 @return Firmware usable variable MTRR count
106 GetFirmwareVariableMtrrCount (
110 return GetVariableMtrrCount () - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER
;
114 Returns the default MTRR cache type for the system.
116 @return MTRR default type
120 GetMtrrDefaultMemoryType (
124 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
) & 0xff);
129 Preparation before programming MTRR.
131 This function will do some preparation for programming MTRRs:
132 disable cache, invalid cache and disable MTRR caching functionality
134 @return CR4 value before changing.
145 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
147 Value
= AsmReadCr0 ();
148 Value
= (UINTN
) BitFieldWrite64 (Value
, 30, 30, 1);
149 Value
= (UINTN
) BitFieldWrite64 (Value
, 29, 29, 0);
156 // Clear PGE flag Bit 7
158 Value
= AsmReadCr4 ();
159 AsmWriteCr4 ((UINTN
) BitFieldWrite64 (Value
, 7, 7, 0));
167 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 0);
174 Cleaning up after programming MTRRs.
176 This function will do some clean up after programming MTRRs:
177 enable MTRR caching functionality, and enable cache
179 @param Cr4 CR4 value to restore
192 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, 10, 11, 3);
195 // Flush all TLBs and cache the second time
201 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
203 Value
= AsmReadCr0 ();
204 Value
= (UINTN
) BitFieldWrite64 (Value
, 30, 30, 0);
205 Value
= (UINTN
) BitFieldWrite64 (Value
, 29, 29, 0);
215 Programs fixed MTRRs registers.
217 @param MemoryCacheType The memory type to set.
218 @param Base The base address of memory range.
219 @param Length The length of memory range.
221 @retval RETURN_SUCCESS The cache type was updated successfully
222 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
228 IN UINT64 MemoryCacheType
,
230 IN OUT UINT64
*Length
243 for (MsrNum
= 0; MsrNum
< MTRR_NUMBER_OF_FIXED_MTRR
; MsrNum
++) {
244 if ((*Base
>= MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
) &&
247 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
248 (8 * MtrrLibFixedMtrrTable
[MsrNum
].Length
)
256 if (MsrNum
== MTRR_NUMBER_OF_FIXED_MTRR
) {
257 return RETURN_UNSUPPORTED
;
261 // We found the fixed MTRR to be programmed
263 for (ByteShift
= 0; ByteShift
< 8; ByteShift
++) {
266 MtrrLibFixedMtrrTable
[MsrNum
].BaseAddress
+
267 (ByteShift
* MtrrLibFixedMtrrTable
[MsrNum
].Length
)
274 if (ByteShift
== 8) {
275 return RETURN_UNSUPPORTED
;
280 ((ByteShift
< 8) && (*Length
>= MtrrLibFixedMtrrTable
[MsrNum
].Length
));
283 OrMask
|= LShiftU64 ((UINT64
) MemoryCacheType
, (UINT32
) (ByteShift
* 8));
284 ClearMask
|= LShiftU64 ((UINT64
) 0xFF, (UINT32
) (ByteShift
* 8));
285 *Length
-= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
286 *Base
+= MtrrLibFixedMtrrTable
[MsrNum
].Length
;
289 if (ByteShift
< 8 && (*Length
!= 0)) {
290 return RETURN_UNSUPPORTED
;
294 (AsmReadMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
) & ~ClearMask
) | OrMask
;
295 AsmWriteMsr64 (MtrrLibFixedMtrrTable
[MsrNum
].Msr
, TempQword
);
296 return RETURN_SUCCESS
;
301 Get the attribute of variable MTRRs.
303 This function shadows the content of variable MTRRs into
304 an internal array: VariableMtrr
306 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
307 @param MtrrValidAddressMask The valid address mask for MTRR since the base address in
308 MTRR must align to 4K, so valid address mask equal to
309 MtrrValidBitsMask & 0xfffffffffffff000ULL
310 @param VariableMtrrCount On input, it means the array number of variable MTRRs passed in.
311 On output, it means the number of MTRRs which has been used if EFI_SUCCESS,
312 or the number of MTRR required if BUFFER_TOO_SMALL.
313 @param VariableMtrr The array to shadow variable MTRRs content
315 @retval RETURN_SUCCESS The variable MTRRs are returned.
316 @retval RETURN_BUFFER_TOO_SMALL The input buffer is too small to hold the variable MTRRs.
321 MtrrGetMemoryAttributeInVariableMtrr (
322 IN UINT64 MtrrValidBitsMask
,
323 IN UINT64 MtrrValidAddressMask
,
324 IN OUT UINT32
*VariableMtrrCount
,
325 OUT VARIABLE_MTRR
*VariableMtrr
331 UINTN FirmwareVariableMtrrCount
;
332 UINT32 VariableMtrrEnd
;
335 // Check if input buffer is large enough
337 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
338 if (*VariableMtrrCount
< FirmwareVariableMtrrCount
) {
339 *VariableMtrrCount
= (UINT32
)FirmwareVariableMtrrCount
;
340 return RETURN_BUFFER_TOO_SMALL
;
343 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
345 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * (*VariableMtrrCount
));
348 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
350 (MsrNum
< VariableMtrrEnd
) &&
351 (Index
< FirmwareVariableMtrrCount
)
355 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
356 VariableMtrr
[Index
].Msr
= MsrNum
;
357 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
358 MtrrValidAddressMask
);
359 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
360 MtrrValidAddressMask
)
364 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
365 VariableMtrr
[Index
].Valid
= TRUE
;
366 VariableMtrr
[Index
].Used
= TRUE
;
367 UsedMtrr
= UsedMtrr
+ 1;
371 *VariableMtrrCount
= UsedMtrr
;
372 return RETURN_SUCCESS
;
377 Checks overlap between given memory range and MTRRs.
379 @param Start The start address of memory range.
380 @param End The end address of memory range.
381 @param VariableMtrr The array to shadow variable MTRRs content
383 @retval TRUE Overlap exists.
384 @retval FALSE No overlap.
388 CheckMemoryAttributeOverlap (
389 IN PHYSICAL_ADDRESS Start
,
390 IN PHYSICAL_ADDRESS End
,
391 IN VARIABLE_MTRR
*VariableMtrr
396 for (Index
= 0; Index
< 6; Index
++) {
398 VariableMtrr
[Index
].Valid
&&
400 (Start
> (VariableMtrr
[Index
].BaseAddress
+
401 VariableMtrr
[Index
].Length
- 1)
403 (End
< VariableMtrr
[Index
].BaseAddress
)
415 Marks a variable MTRR as non-valid.
417 @param Index The index of the array VariableMtrr to be invalidated
418 @param VariableMtrr The array to shadow variable MTRRs content
419 @param UsedMtrr The number of MTRRs which has already been used
423 InvalidateShadowMtrr (
425 IN VARIABLE_MTRR
*VariableMtrr
,
429 VariableMtrr
[Index
].Valid
= FALSE
;
430 *UsedMtrr
= *UsedMtrr
- 1;
435 Combine memory attributes.
437 If overlap exists between given memory range and MTRRs, try to combine them.
439 @param Attributes The memory type to set.
440 @param Base The base address of memory range.
441 @param Length The length of memory range.
442 @param VariableMtrr The array to shadow variable MTRRs content
443 @param UsedMtrr The number of MTRRs which has already been used
444 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
446 @retval EFI_SUCCESS Memory region successfully combined.
447 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
451 CombineMemoryAttribute (
452 IN UINT64 Attributes
,
454 IN OUT UINT64
*Length
,
455 IN VARIABLE_MTRR
*VariableMtrr
,
456 IN OUT UINT32
*UsedMtrr
,
457 OUT BOOLEAN
*OverwriteExistingMtrr
465 UINT32 FirmwareVariableMtrrCount
;
467 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
469 *OverwriteExistingMtrr
= FALSE
;
470 EndAddress
= *Base
+*Length
- 1;
472 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
474 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
476 !VariableMtrr
[Index
].Valid
||
479 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
486 // Combine same attribute MTRR range
488 if (Attributes
== VariableMtrr
[Index
].Type
) {
490 // if the Mtrr range contain the request range, return RETURN_SUCCESS
492 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
494 return RETURN_SUCCESS
;
497 // invalid this MTRR, and program the combine range
500 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
502 VariableMtrr
[Index
].BaseAddress
;
503 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
506 // Record the MTRR usage status in VariableMtrr array.
508 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
509 *Base
= CombineStart
;
510 *Length
= CombineEnd
- CombineStart
+ 1;
511 EndAddress
= CombineEnd
;
512 *OverwriteExistingMtrr
= TRUE
;
516 // The cache type is different, but the range is convered by one MTRR
518 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
519 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
525 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
526 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
527 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
528 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
529 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
530 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
532 *OverwriteExistingMtrr
= TRUE
;
536 // Other type memory overlap is invalid
538 return RETURN_ACCESS_DENIED
;
541 return RETURN_SUCCESS
;
546 Calculate the maximum value which is a power of 2, but less the MemoryLength.
548 @param MemoryLength The number to pass in.
549 @return The maximum value which is align to power of 2 and less the MemoryLength
554 IN UINT64 MemoryLength
559 if (RShiftU64 (MemoryLength
, 32)) {
561 (UINT64
) GetPowerOfTwo32 (
562 (UINT32
) RShiftU64 (MemoryLength
, 32)
567 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
575 Check the direction to program variable MTRRs.
577 This function determines which direction of programming the variable
578 MTRRs will use fewer MTRRs.
580 @param Input Length of Memory to program MTRR
581 @param MtrrNumber Pointer to the number of necessary MTRRs
583 @retval TRUE Positive direction is better.
584 FALSE Negtive direction is better.
602 TempQword
-= Power2MaxMemory (TempQword
);
604 } while (TempQword
!= 0);
606 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
609 TempQword
-= Power2MaxMemory (TempQword
);
611 } while (TempQword
!= 0);
613 if (Positive
<= Subtractive
) {
614 *MtrrNumber
= Positive
;
617 *MtrrNumber
= Subtractive
;
623 Invalid variable MTRRs according to the value in the shadow array.
625 This function programs MTRRs according to the values specified
628 @param VariableMtrr The array to shadow variable MTRRs content
634 IN VARIABLE_MTRR
*VariableMtrr
639 UINTN VariableMtrrCount
;
641 Cr4
= PreMtrrChange ();
643 VariableMtrrCount
= GetVariableMtrrCount ();
644 while (Index
< VariableMtrrCount
) {
645 if (VariableMtrr
[Index
].Valid
== FALSE
&& VariableMtrr
[Index
].Used
== TRUE
) {
646 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
647 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
648 VariableMtrr
[Index
].Used
= FALSE
;
652 PostMtrrChange (Cr4
);
657 Programs variable MTRRs
659 This function programs variable MTRRs
661 @param MtrrNumber Index of MTRR to program.
662 @param BaseAddress Base address of memory region.
663 @param Length Length of memory region.
664 @param MemoryCacheType Memory type to set.
665 @param MtrrValidAddressMask The valid address mask for MTRR
670 ProgramVariableMtrr (
672 IN PHYSICAL_ADDRESS BaseAddress
,
674 IN UINT64 MemoryCacheType
,
675 IN UINT64 MtrrValidAddressMask
681 Cr4
= PreMtrrChange ();
684 // MTRR Physical Base
686 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
687 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
690 // MTRR Physical Mask
692 TempQword
= ~(Length
- 1);
694 (UINT32
) (MtrrNumber
+ 1),
695 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
698 PostMtrrChange (Cr4
);
703 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
705 @param MtrrType MTRR memory type
707 @return The enum item in MTRR_MEMORY_CACHE_TYPE
711 MTRR_MEMORY_CACHE_TYPE
712 GetMemoryCacheTypeFromMtrrType (
717 case MTRR_CACHE_UNCACHEABLE
:
718 return CacheUncacheable
;
719 case MTRR_CACHE_WRITE_COMBINING
:
720 return CacheWriteCombining
;
721 case MTRR_CACHE_WRITE_THROUGH
:
722 return CacheWriteThrough
;
723 case MTRR_CACHE_WRITE_PROTECTED
:
724 return CacheWriteProtected
;
725 case MTRR_CACHE_WRITE_BACK
:
726 return CacheWriteBack
;
729 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
730 // no mtrr covers the range
732 return CacheUncacheable
;
737 Initializes the valid bits mask and valid address mask for MTRRs.
739 This function initializes the valid bits mask and valid address mask for MTRRs.
741 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
742 @param MtrrValidAddressMask The valid address mask for the MTRR
747 MtrrLibInitializeMtrrMask (
748 OUT UINT64
*MtrrValidBitsMask
,
749 OUT UINT64
*MtrrValidAddressMask
753 UINT8 PhysicalAddressBits
;
755 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
757 if (RegEax
>= 0x80000008) {
758 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
760 PhysicalAddressBits
= (UINT8
) RegEax
;
762 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
763 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
765 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
766 *MtrrValidAddressMask
= 0xFFFFFFFF;
772 Determing the real attribute of a memory range.
774 This function is to arbitrate the real attribute of the memory when
775 there are 2 MTRR covers the same memory range. For further details,
776 please refer the IA32 Software Developer's Manual, Volume 3,
779 @param MtrrType1 the first kind of Memory type
780 @param MtrrType2 the second kind of memory type
791 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
793 case MTRR_CACHE_UNCACHEABLE
:
794 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
796 case MTRR_CACHE_WRITE_COMBINING
:
798 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
799 MtrrType2
==MTRR_CACHE_UNCACHEABLE
801 MtrrType
= MtrrType2
;
804 case MTRR_CACHE_WRITE_THROUGH
:
806 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
807 MtrrType2
==MTRR_CACHE_WRITE_BACK
809 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
810 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
811 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
814 case MTRR_CACHE_WRITE_PROTECTED
:
815 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
816 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
817 MtrrType
= MtrrType2
;
820 case MTRR_CACHE_WRITE_BACK
:
822 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
823 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
824 MtrrType2
== MTRR_CACHE_WRITE_BACK
826 MtrrType
= MtrrType2
;
829 case MTRR_CACHE_INVALID_TYPE
:
830 MtrrType
= MtrrType2
;
836 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
837 MtrrType
= MtrrType1
;
844 This function attempts to set the attributes for a memory range.
846 @param BaseAddress The physical address that is the start
847 address of a memory region.
848 @param Length The size in bytes of the memory region.
849 @param Attributes The bit mask of attributes to set for the
852 @retval RETURN_SUCCESS The attributes were set for the memory
854 @retval RETURN_INVALID_PARAMETER Length is zero.
855 @retval RETURN_UNSUPPORTED The processor does not support one or
856 more bytes of the memory resource range
857 specified by BaseAddress and Length.
858 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
859 for the memory resource range specified
860 by BaseAddress and Length.
861 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
862 range specified by BaseAddress and Length
864 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
865 modify the attributes of the memory
871 MtrrSetMemoryAttribute (
872 IN PHYSICAL_ADDRESS BaseAddress
,
874 IN MTRR_MEMORY_CACHE_TYPE Attribute
878 RETURN_STATUS Status
;
885 VARIABLE_MTRR VariableMtrr
[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR
];
887 UINT64 MtrrValidBitsMask
;
888 UINT64 MtrrValidAddressMask
;
890 BOOLEAN OverwriteExistingMtrr
;
891 UINT32 FirmwareVariableMtrrCount
;
892 UINT32 VariableMtrrEnd
;
894 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
895 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
897 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
900 MemoryType
= (UINT64
)Attribute
;
901 OverwriteExistingMtrr
= FALSE
;
904 // Check for an invalid parameter
907 return RETURN_INVALID_PARAMETER
;
911 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
912 (Length
&~MtrrValidAddressMask
) != 0
914 return RETURN_UNSUPPORTED
;
918 // Check if Fixed MTRR
920 Status
= RETURN_SUCCESS
;
921 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
922 Cr4
= PreMtrrChange ();
923 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
924 PostMtrrChange (Cr4
);
925 if (RETURN_ERROR (Status
)) {
932 // A Length of 0 can only make sense for fixed MTTR ranges.
933 // Since we just handled the fixed MTRRs, we can skip the
934 // variable MTRR section.
940 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
941 // we can set the bade to 0 to save variable MTRRs.
943 if (BaseAddress
== BASE_1MB
) {
949 // Check memory base address alignment
951 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
952 if (Remainder
!= 0) {
953 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
954 if (Remainder
!= 0) {
955 Status
= RETURN_UNSUPPORTED
;
963 UsedMtrr
= MAX_MTRR_NUMBER_OF_VARIABLE_MTRR
;
964 MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, &UsedMtrr
, VariableMtrr
);
965 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
967 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
968 if (RETURN_ERROR (Status
)) {
974 // Combined successfully
976 Status
= RETURN_SUCCESS
;
982 // Program Variable MTRRs
984 // Avoid hardcode here and read data dynamically
986 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
987 Status
= RETURN_OUT_OF_RESOURCES
;
992 // The memory type is the same with the type specified by
993 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
995 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
997 // Invalidate the now-unused MTRRs
999 InvalidateMtrr(VariableMtrr
);
1006 if (TempQword
== Power2MaxMemory (TempQword
)) {
1008 // Invalidate the now-unused MTRRs
1010 InvalidateMtrr(VariableMtrr
);
1013 // Find first unused MTRR
1015 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1016 MsrNum
< VariableMtrrEnd
;
1019 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1024 ProgramVariableMtrr (
1029 MtrrValidAddressMask
1033 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1035 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1036 Status
= RETURN_OUT_OF_RESOURCES
;
1041 // Invalidate the now-unused MTRRs
1043 InvalidateMtrr(VariableMtrr
);
1046 // Find first unused MTRR
1048 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1049 MsrNum
< VariableMtrrEnd
;
1052 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1058 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1059 ProgramVariableMtrr (
1064 MtrrValidAddressMask
1066 BaseAddress
+= Length
;
1067 TempQword
= Length
- TempQword
;
1068 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1075 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1076 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1081 Length
= Power2MaxMemory (TempQword
);
1083 BaseAddress
-= Length
;
1086 ProgramVariableMtrr (
1091 MtrrValidAddressMask
1095 BaseAddress
+= Length
;
1097 TempQword
-= Length
;
1099 } while (TempQword
> 0);
1109 This function will get the memory cache type of the specific address.
1111 This function is mainly for debug purpose.
1113 @param Address The specific address
1115 @return Memory cache type of the sepcific address
1118 MTRR_MEMORY_CACHE_TYPE
1120 MtrrGetMemoryAttribute (
1121 IN PHYSICAL_ADDRESS Address
1128 UINT64 TempMtrrType
;
1129 MTRR_MEMORY_CACHE_TYPE CacheType
;
1130 VARIABLE_MTRR VariableMtrr
[MAX_MTRR_NUMBER_OF_VARIABLE_MTRR
];
1131 UINT64 MtrrValidBitsMask
;
1132 UINT64 MtrrValidAddressMask
;
1133 UINTN VariableMtrrCount
;
1137 // Check if MTRR is enabled, if not, return UC as attribute
1139 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1140 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1142 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1143 return CacheUncacheable
;
1147 // If address is less than 1M, then try to go through the fixed MTRR
1149 if (Address
< BASE_1MB
) {
1150 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1152 // Go through the fixed MTRR
1154 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1155 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1157 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1158 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1162 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1163 MtrrLibFixedMtrrTable
[Index
].Length
;
1164 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1165 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1166 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1171 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1172 UsedMtrr
= MAX_MTRR_NUMBER_OF_VARIABLE_MTRR
;
1173 MtrrGetMemoryAttributeInVariableMtrr(
1175 MtrrValidAddressMask
,
1181 // Go through the variable MTRR
1183 VariableMtrrCount
= GetVariableMtrrCount ();
1184 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1185 if (VariableMtrr
[Index
].Valid
) {
1186 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1187 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1188 TempMtrrType
= VariableMtrr
[Index
].Type
;
1189 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1193 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1200 This function will get the raw value in variable MTRRs
1202 @param VariableSettings A buffer to hold variable MTRRs content.
1204 @return The VariableSettings input pointer
1207 MTRR_VARIABLE_SETTINGS
*
1209 MtrrGetVariableMtrr (
1210 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1214 UINT32 VariableMtrrCount
;
1216 VariableMtrrCount
= GetVariableMtrrCount ();
1217 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1218 VariableSettings
->Mtrr
[Index
].Base
=
1219 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1220 VariableSettings
->Mtrr
[Index
].Mask
=
1221 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1224 return VariableSettings
;
1229 Worker function setting variable MTRRs
1231 @param VariableSettings A buffer to hold variable MTRRs content.
1235 MtrrSetVariableMtrrWorker (
1236 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1240 UINT32 VariableMtrrCount
;
1242 VariableMtrrCount
= GetVariableMtrrCount ();
1243 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1245 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1246 VariableSettings
->Mtrr
[Index
].Base
1249 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1250 VariableSettings
->Mtrr
[Index
].Mask
1257 This function sets variable MTRRs
1259 @param VariableSettings A buffer to hold variable MTRRs content.
1261 @return The pointer of VariableSettings
1264 MTRR_VARIABLE_SETTINGS
*
1266 MtrrSetVariableMtrr (
1267 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1272 Cr4
= PreMtrrChange ();
1273 MtrrSetVariableMtrrWorker (VariableSettings
);
1274 PostMtrrChange (Cr4
);
1275 return VariableSettings
;
1280 This function gets the content in fixed MTRRs
1282 @param FixedSettings A buffer to hold fixed Mtrrs content.
1284 @retval The pointer of FixedSettings
1287 MTRR_FIXED_SETTINGS
*
1290 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1295 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1296 FixedSettings
->Mtrr
[Index
] =
1297 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1300 return FixedSettings
;
1304 Worker function setting fixed MTRRs
1306 @param FixedSettings A buffer to hold fixed Mtrrs content.
1310 MtrrSetFixedMtrrWorker (
1311 IN MTRR_FIXED_SETTINGS
*FixedSettings
1316 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1318 MtrrLibFixedMtrrTable
[Index
].Msr
,
1319 FixedSettings
->Mtrr
[Index
]
1326 This function sets fixed MTRRs
1328 @param FixedSettings A buffer to hold fixed Mtrrs content.
1330 @retval The pointer of FixedSettings
1333 MTRR_FIXED_SETTINGS
*
1336 IN MTRR_FIXED_SETTINGS
*FixedSettings
1341 Cr4
= PreMtrrChange ();
1342 MtrrSetFixedMtrrWorker (FixedSettings
);
1343 PostMtrrChange (Cr4
);
1345 return FixedSettings
;
1350 This function gets the content in all MTRRs (variable and fixed)
1352 @param MtrrSetting A buffer to hold all Mtrrs content.
1354 @retval the pointer of MtrrSetting
1360 OUT MTRR_SETTINGS
*MtrrSetting
1366 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1369 // Get variable MTRRs
1371 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1374 // Get MTRR_DEF_TYPE value
1376 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1383 This function sets all MTRRs (variable and fixed)
1385 @param MtrrSetting A buffer holding all MTRRs content.
1387 @retval The pointer of MtrrSetting
1393 IN MTRR_SETTINGS
*MtrrSetting
1398 Cr4
= PreMtrrChange ();
1403 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1406 // Set variable MTRRs
1408 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1411 // Set MTRR_DEF_TYPE value
1413 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1415 PostMtrrChange (Cr4
);
1422 This function prints all MTRRs for debugging.
1425 MtrrDebugPrintAllMtrrs (
1430 MTRR_SETTINGS MtrrSettings
;
1432 UINTN VariableMtrrCount
;
1434 MtrrGetAllMtrrs (&MtrrSettings
);
1435 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1436 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1438 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1440 MtrrSettings
.Fixed
.Mtrr
[Index
]
1444 VariableMtrrCount
= GetVariableMtrrCount ();
1445 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1447 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1449 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1450 MtrrSettings
.Variables
.Mtrr
[Index
].Mask