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 an
304 internal array: VariableMtrr.
306 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
307 @param MtrrValidAddressMask The valid address mask for MTRR
308 @param VariableMtrr The array to shadow variable MTRRs content
310 @return The return value of this paramter indicates the
311 number of MTRRs which has been used.
316 MtrrGetMemoryAttributeInVariableMtrr (
317 IN UINT64 MtrrValidBitsMask
,
318 IN UINT64 MtrrValidAddressMask
,
319 OUT VARIABLE_MTRR
*VariableMtrr
325 UINT32 FirmwareVariableMtrrCount
;
326 UINT32 VariableMtrrEnd
;
328 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
329 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
331 ZeroMem (VariableMtrr
, sizeof (VARIABLE_MTRR
) * MTRR_NUMBER_OF_VARIABLE_MTRR
);
334 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
, Index
= 0;
336 (MsrNum
< VariableMtrrEnd
) &&
337 (Index
< FirmwareVariableMtrrCount
)
341 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) != 0) {
342 VariableMtrr
[Index
].Msr
= MsrNum
;
343 VariableMtrr
[Index
].BaseAddress
= (AsmReadMsr64 (MsrNum
) &
344 MtrrValidAddressMask
);
345 VariableMtrr
[Index
].Length
= ((~(AsmReadMsr64 (MsrNum
+ 1) &
346 MtrrValidAddressMask
)
350 VariableMtrr
[Index
].Type
= (AsmReadMsr64 (MsrNum
) & 0x0ff);
351 VariableMtrr
[Index
].Valid
= TRUE
;
352 VariableMtrr
[Index
].Used
= TRUE
;
353 UsedMtrr
= UsedMtrr
+ 1;
362 Checks overlap between given memory range and MTRRs.
364 @param Start The start address of memory range.
365 @param End The end address of memory range.
366 @param VariableMtrr The array to shadow variable MTRRs content
368 @retval TRUE Overlap exists.
369 @retval FALSE No overlap.
373 CheckMemoryAttributeOverlap (
374 IN PHYSICAL_ADDRESS Start
,
375 IN PHYSICAL_ADDRESS End
,
376 IN VARIABLE_MTRR
*VariableMtrr
381 for (Index
= 0; Index
< 6; Index
++) {
383 VariableMtrr
[Index
].Valid
&&
385 (Start
> (VariableMtrr
[Index
].BaseAddress
+
386 VariableMtrr
[Index
].Length
- 1)
388 (End
< VariableMtrr
[Index
].BaseAddress
)
400 Marks a variable MTRR as non-valid.
402 @param Index The index of the array VariableMtrr to be invalidated
403 @param VariableMtrr The array to shadow variable MTRRs content
404 @param UsedMtrr The number of MTRRs which has already been used
408 InvalidateShadowMtrr (
410 IN VARIABLE_MTRR
*VariableMtrr
,
414 VariableMtrr
[Index
].Valid
= FALSE
;
415 *UsedMtrr
= *UsedMtrr
- 1;
420 Combine memory attributes.
422 If overlap exists between given memory range and MTRRs, try to combine them.
424 @param Attributes The memory type to set.
425 @param Base The base address of memory range.
426 @param Length The length of memory range.
427 @param VariableMtrr The array to shadow variable MTRRs content
428 @param UsedMtrr The number of MTRRs which has already been used
429 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
431 @retval EFI_SUCCESS Memory region successfully combined.
432 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
436 CombineMemoryAttribute (
437 IN UINT64 Attributes
,
439 IN OUT UINT64
*Length
,
440 IN VARIABLE_MTRR
*VariableMtrr
,
441 IN OUT UINT32
*UsedMtrr
,
442 OUT BOOLEAN
*OverwriteExistingMtrr
450 UINT32 FirmwareVariableMtrrCount
;
452 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
454 *OverwriteExistingMtrr
= FALSE
;
455 EndAddress
= *Base
+*Length
- 1;
457 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
459 MtrrEnd
= VariableMtrr
[Index
].BaseAddress
+ VariableMtrr
[Index
].Length
- 1;
461 !VariableMtrr
[Index
].Valid
||
464 (EndAddress
< VariableMtrr
[Index
].BaseAddress
)
471 // Combine same attribute MTRR range
473 if (Attributes
== VariableMtrr
[Index
].Type
) {
475 // if the Mtrr range contain the request range, return RETURN_SUCCESS
477 if (VariableMtrr
[Index
].BaseAddress
<= *Base
&& MtrrEnd
>= EndAddress
) {
479 return RETURN_SUCCESS
;
482 // invalid this MTRR, and program the combine range
485 (*Base
) < VariableMtrr
[Index
].BaseAddress
?
487 VariableMtrr
[Index
].BaseAddress
;
488 CombineEnd
= EndAddress
> MtrrEnd
? EndAddress
: MtrrEnd
;
491 // Record the MTRR usage status in VariableMtrr array.
493 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
494 *Base
= CombineStart
;
495 *Length
= CombineEnd
- CombineStart
+ 1;
496 EndAddress
= CombineEnd
;
497 *OverwriteExistingMtrr
= TRUE
;
501 // The cache type is different, but the range is convered by one MTRR
503 if (VariableMtrr
[Index
].BaseAddress
== *Base
&& MtrrEnd
== EndAddress
) {
504 InvalidateShadowMtrr (Index
, VariableMtrr
, UsedMtrr
);
510 if ((Attributes
== MTRR_CACHE_WRITE_THROUGH
&&
511 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) ||
512 (Attributes
== MTRR_CACHE_WRITE_BACK
&&
513 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_THROUGH
) ||
514 (Attributes
== MTRR_CACHE_UNCACHEABLE
) ||
515 (VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
)
517 *OverwriteExistingMtrr
= TRUE
;
521 // Other type memory overlap is invalid
523 return RETURN_ACCESS_DENIED
;
526 return RETURN_SUCCESS
;
531 Calculate the maximum value which is a power of 2, but less the MemoryLength.
533 @param MemoryLength The number to pass in.
534 @return The maximum value which is align to power of 2 and less the MemoryLength
539 IN UINT64 MemoryLength
544 if (RShiftU64 (MemoryLength
, 32)) {
546 (UINT64
) GetPowerOfTwo32 (
547 (UINT32
) RShiftU64 (MemoryLength
, 32)
552 Result
= (UINT64
) GetPowerOfTwo32 ((UINT32
) MemoryLength
);
560 Check the direction to program variable MTRRs.
562 This function determines which direction of programming the variable
563 MTRRs will use fewer MTRRs.
565 @param Input Length of Memory to program MTRR
566 @param MtrrNumber Pointer to the number of necessary MTRRs
568 @retval TRUE Positive direction is better.
569 FALSE Negtive direction is better.
587 TempQword
-= Power2MaxMemory (TempQword
);
589 } while (TempQword
!= 0);
591 TempQword
= Power2MaxMemory (LShiftU64 (Input
, 1)) - Input
;
594 TempQword
-= Power2MaxMemory (TempQword
);
596 } while (TempQword
!= 0);
598 if (Positive
<= Subtractive
) {
599 *MtrrNumber
= Positive
;
602 *MtrrNumber
= Subtractive
;
608 Invalid variable MTRRs according to the value in the shadow array.
610 This function programs MTRRs according to the values specified
613 @param VariableMtrr The array to shadow variable MTRRs content
619 IN VARIABLE_MTRR
*VariableMtrr
624 UINTN VariableMtrrCount
;
626 Cr4
= PreMtrrChange ();
628 VariableMtrrCount
= GetVariableMtrrCount ();
629 while (Index
< VariableMtrrCount
) {
630 if (VariableMtrr
[Index
].Valid
== FALSE
&& VariableMtrr
[Index
].Used
== TRUE
) {
631 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
, 0);
632 AsmWriteMsr64 (VariableMtrr
[Index
].Msr
+ 1, 0);
633 VariableMtrr
[Index
].Used
= FALSE
;
637 PostMtrrChange (Cr4
);
642 Programs variable MTRRs
644 This function programs variable MTRRs
646 @param MtrrNumber Index of MTRR to program.
647 @param BaseAddress Base address of memory region.
648 @param Length Length of memory region.
649 @param MemoryCacheType Memory type to set.
650 @param MtrrValidAddressMask The valid address mask for MTRR
655 ProgramVariableMtrr (
657 IN PHYSICAL_ADDRESS BaseAddress
,
659 IN UINT64 MemoryCacheType
,
660 IN UINT64 MtrrValidAddressMask
666 Cr4
= PreMtrrChange ();
669 // MTRR Physical Base
671 TempQword
= (BaseAddress
& MtrrValidAddressMask
) | MemoryCacheType
;
672 AsmWriteMsr64 ((UINT32
) MtrrNumber
, TempQword
);
675 // MTRR Physical Mask
677 TempQword
= ~(Length
- 1);
679 (UINT32
) (MtrrNumber
+ 1),
680 (TempQword
& MtrrValidAddressMask
) | MTRR_LIB_CACHE_MTRR_ENABLED
683 PostMtrrChange (Cr4
);
688 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
690 @param MtrrType MTRR memory type
692 @return The enum item in MTRR_MEMORY_CACHE_TYPE
696 MTRR_MEMORY_CACHE_TYPE
697 GetMemoryCacheTypeFromMtrrType (
702 case MTRR_CACHE_UNCACHEABLE
:
703 return CacheUncacheable
;
704 case MTRR_CACHE_WRITE_COMBINING
:
705 return CacheWriteCombining
;
706 case MTRR_CACHE_WRITE_THROUGH
:
707 return CacheWriteThrough
;
708 case MTRR_CACHE_WRITE_PROTECTED
:
709 return CacheWriteProtected
;
710 case MTRR_CACHE_WRITE_BACK
:
711 return CacheWriteBack
;
714 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
715 // no mtrr covers the range
717 return CacheUncacheable
;
722 Initializes the valid bits mask and valid address mask for MTRRs.
724 This function initializes the valid bits mask and valid address mask for MTRRs.
726 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
727 @param MtrrValidAddressMask The valid address mask for the MTRR
732 MtrrLibInitializeMtrrMask (
733 OUT UINT64
*MtrrValidBitsMask
,
734 OUT UINT64
*MtrrValidAddressMask
738 UINT8 PhysicalAddressBits
;
740 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
742 if (RegEax
>= 0x80000008) {
743 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
745 PhysicalAddressBits
= (UINT8
) RegEax
;
747 *MtrrValidBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
748 *MtrrValidAddressMask
= *MtrrValidBitsMask
& 0xfffffffffffff000ULL
;
750 *MtrrValidBitsMask
= MTRR_LIB_CACHE_VALID_ADDRESS
;
751 *MtrrValidAddressMask
= 0xFFFFFFFF;
757 Determing the real attribute of a memory range.
759 This function is to arbitrate the real attribute of the memory when
760 there are 2 MTRR covers the same memory range. For further details,
761 please refer the IA32 Software Developer's Manual, Volume 3,
764 @param MtrrType1 the first kind of Memory type
765 @param MtrrType2 the second kind of memory type
776 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
778 case MTRR_CACHE_UNCACHEABLE
:
779 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
781 case MTRR_CACHE_WRITE_COMBINING
:
783 MtrrType2
==MTRR_CACHE_WRITE_COMBINING
||
784 MtrrType2
==MTRR_CACHE_UNCACHEABLE
786 MtrrType
= MtrrType2
;
789 case MTRR_CACHE_WRITE_THROUGH
:
791 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
792 MtrrType2
==MTRR_CACHE_WRITE_BACK
794 MtrrType
= MTRR_CACHE_WRITE_THROUGH
;
795 } else if(MtrrType2
==MTRR_CACHE_UNCACHEABLE
) {
796 MtrrType
= MTRR_CACHE_UNCACHEABLE
;
799 case MTRR_CACHE_WRITE_PROTECTED
:
800 if (MtrrType2
== MTRR_CACHE_WRITE_PROTECTED
||
801 MtrrType2
== MTRR_CACHE_UNCACHEABLE
) {
802 MtrrType
= MtrrType2
;
805 case MTRR_CACHE_WRITE_BACK
:
807 MtrrType2
== MTRR_CACHE_UNCACHEABLE
||
808 MtrrType2
==MTRR_CACHE_WRITE_THROUGH
||
809 MtrrType2
== MTRR_CACHE_WRITE_BACK
811 MtrrType
= MtrrType2
;
814 case MTRR_CACHE_INVALID_TYPE
:
815 MtrrType
= MtrrType2
;
821 if (MtrrType2
== MTRR_CACHE_INVALID_TYPE
) {
822 MtrrType
= MtrrType1
;
829 This function attempts to set the attributes for a memory range.
831 @param BaseAddress The physical address that is the start
832 address of a memory region.
833 @param Length The size in bytes of the memory region.
834 @param Attributes The bit mask of attributes to set for the
837 @retval RETURN_SUCCESS The attributes were set for the memory
839 @retval RETURN_INVALID_PARAMETER Length is zero.
840 @retval RETURN_UNSUPPORTED The processor does not support one or
841 more bytes of the memory resource range
842 specified by BaseAddress and Length.
843 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
844 for the memory resource range specified
845 by BaseAddress and Length.
846 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
847 range specified by BaseAddress and Length
849 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
850 modify the attributes of the memory
856 MtrrSetMemoryAttribute (
857 IN PHYSICAL_ADDRESS BaseAddress
,
859 IN MTRR_MEMORY_CACHE_TYPE Attribute
863 RETURN_STATUS Status
;
870 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
872 UINT64 MtrrValidBitsMask
;
873 UINT64 MtrrValidAddressMask
;
875 BOOLEAN OverwriteExistingMtrr
;
876 UINT32 FirmwareVariableMtrrCount
;
877 UINT32 VariableMtrrEnd
;
879 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
880 VariableMtrrEnd
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (2 * GetVariableMtrrCount ()) - 1;
882 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
885 MemoryType
= (UINT64
)Attribute
;
886 OverwriteExistingMtrr
= FALSE
;
889 // Check for an invalid parameter
892 return RETURN_INVALID_PARAMETER
;
896 (BaseAddress
&~MtrrValidAddressMask
) != 0 ||
897 (Length
&~MtrrValidAddressMask
) != 0
899 return RETURN_UNSUPPORTED
;
903 // Check if Fixed MTRR
905 Status
= RETURN_SUCCESS
;
906 while ((BaseAddress
< BASE_1MB
) && (Length
> 0) && Status
== RETURN_SUCCESS
) {
907 Cr4
= PreMtrrChange ();
908 Status
= ProgramFixedMtrr (MemoryType
, &BaseAddress
, &Length
);
909 PostMtrrChange (Cr4
);
910 if (RETURN_ERROR (Status
)) {
917 // A Length of 0 can only make sense for fixed MTTR ranges.
918 // Since we just handled the fixed MTRRs, we can skip the
919 // variable MTRR section.
925 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
926 // we can set the bade to 0 to save variable MTRRs.
928 if (BaseAddress
== BASE_1MB
) {
934 // Check memory base address alignment
936 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (LShiftU64 (Length
, 1)), &Remainder
);
937 if (Remainder
!= 0) {
938 DivU64x64Remainder (BaseAddress
, Power2MaxMemory (Length
), &Remainder
);
939 if (Remainder
!= 0) {
940 Status
= RETURN_UNSUPPORTED
;
948 UsedMtrr
= MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask
, MtrrValidAddressMask
, VariableMtrr
);
949 OverLap
= CheckMemoryAttributeOverlap (BaseAddress
, BaseAddress
+ Length
- 1, VariableMtrr
);
951 Status
= CombineMemoryAttribute (MemoryType
, &BaseAddress
, &Length
, VariableMtrr
, &UsedMtrr
, &OverwriteExistingMtrr
);
952 if (RETURN_ERROR (Status
)) {
958 // Combined successfully
960 Status
= RETURN_SUCCESS
;
966 // Program Variable MTRRs
968 // Avoid hardcode here and read data dynamically
970 if (UsedMtrr
>= FirmwareVariableMtrrCount
) {
971 Status
= RETURN_OUT_OF_RESOURCES
;
976 // The memory type is the same with the type specified by
977 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
979 if ((!OverwriteExistingMtrr
) && (Attribute
== GetMtrrDefaultMemoryType ())) {
981 // Invalidate the now-unused MTRRs
983 InvalidateMtrr(VariableMtrr
);
990 if (TempQword
== Power2MaxMemory (TempQword
)) {
992 // Invalidate the now-unused MTRRs
994 InvalidateMtrr(VariableMtrr
);
997 // Find first unused MTRR
999 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1000 MsrNum
< VariableMtrrEnd
;
1003 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1008 ProgramVariableMtrr (
1013 MtrrValidAddressMask
1017 Positive
= GetDirection (TempQword
, &MtrrNumber
);
1019 if ((UsedMtrr
+ MtrrNumber
) > FirmwareVariableMtrrCount
) {
1020 Status
= RETURN_OUT_OF_RESOURCES
;
1025 // Invalidate the now-unused MTRRs
1027 InvalidateMtrr(VariableMtrr
);
1030 // Find first unused MTRR
1032 for (MsrNum
= MTRR_LIB_IA32_VARIABLE_MTRR_BASE
;
1033 MsrNum
< VariableMtrrEnd
;
1036 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1042 Length
= Power2MaxMemory (LShiftU64 (TempQword
, 1));
1043 ProgramVariableMtrr (
1048 MtrrValidAddressMask
1050 BaseAddress
+= Length
;
1051 TempQword
= Length
- TempQword
;
1052 MemoryType
= MTRR_CACHE_UNCACHEABLE
;
1059 for (; MsrNum
< VariableMtrrEnd
; MsrNum
+= 2) {
1060 if ((AsmReadMsr64 (MsrNum
+ 1) & MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1065 Length
= Power2MaxMemory (TempQword
);
1067 BaseAddress
-= Length
;
1070 ProgramVariableMtrr (
1075 MtrrValidAddressMask
1079 BaseAddress
+= Length
;
1081 TempQword
-= Length
;
1083 } while (TempQword
> 0);
1093 This function will get the memory cache type of the specific address.
1095 This function is mainly for debug purpose.
1097 @param Address The specific address
1099 @return Memory cache type of the sepcific address
1102 MTRR_MEMORY_CACHE_TYPE
1104 MtrrGetMemoryAttribute (
1105 IN PHYSICAL_ADDRESS Address
1112 UINT64 TempMtrrType
;
1113 MTRR_MEMORY_CACHE_TYPE CacheType
;
1114 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
1115 UINT64 MtrrValidBitsMask
;
1116 UINT64 MtrrValidAddressMask
;
1117 UINTN VariableMtrrCount
;
1120 // Check if MTRR is enabled, if not, return UC as attribute
1122 TempQword
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1123 MtrrType
= MTRR_CACHE_INVALID_TYPE
;
1125 if ((TempQword
& MTRR_LIB_CACHE_MTRR_ENABLED
) == 0) {
1126 return CacheUncacheable
;
1130 // If address is less than 1M, then try to go through the fixed MTRR
1132 if (Address
< BASE_1MB
) {
1133 if ((TempQword
& MTRR_LIB_CACHE_FIXED_MTRR_ENABLED
) != 0) {
1135 // Go through the fixed MTRR
1137 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1138 if (Address
>= MtrrLibFixedMtrrTable
[Index
].BaseAddress
&&
1140 MtrrLibFixedMtrrTable
[Index
].BaseAddress
+
1141 (MtrrLibFixedMtrrTable
[Index
].Length
* 8)
1145 ((UINTN
)Address
- MtrrLibFixedMtrrTable
[Index
].BaseAddress
) /
1146 MtrrLibFixedMtrrTable
[Index
].Length
;
1147 TempQword
= AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1148 MtrrType
= RShiftU64 (TempQword
, SubIndex
* 8) & 0xFF;
1149 return GetMemoryCacheTypeFromMtrrType (MtrrType
);
1154 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask
, &MtrrValidAddressMask
);
1155 MtrrGetMemoryAttributeInVariableMtrr(
1157 MtrrValidAddressMask
,
1162 // Go through the variable MTRR
1164 VariableMtrrCount
= GetVariableMtrrCount ();
1165 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1166 if (VariableMtrr
[Index
].Valid
) {
1167 if (Address
>= VariableMtrr
[Index
].BaseAddress
&&
1168 Address
< VariableMtrr
[Index
].BaseAddress
+VariableMtrr
[Index
].Length
) {
1169 TempMtrrType
= VariableMtrr
[Index
].Type
;
1170 MtrrType
= MtrrPrecedence (MtrrType
, TempMtrrType
);
1174 CacheType
= GetMemoryCacheTypeFromMtrrType (MtrrType
);
1181 This function will get the raw value in variable MTRRs
1183 @param VariableSettings A buffer to hold variable MTRRs content.
1185 @return The VariableSettings input pointer
1188 MTRR_VARIABLE_SETTINGS
*
1190 MtrrGetVariableMtrr (
1191 OUT MTRR_VARIABLE_SETTINGS
*VariableSettings
1195 UINT32 VariableMtrrCount
;
1197 VariableMtrrCount
= GetVariableMtrrCount ();
1198 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1199 VariableSettings
->Mtrr
[Index
].Base
=
1200 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1));
1201 VariableSettings
->Mtrr
[Index
].Mask
=
1202 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1);
1205 return VariableSettings
;
1210 Worker function setting variable MTRRs
1212 @param VariableSettings A buffer to hold variable MTRRs content.
1216 MtrrSetVariableMtrrWorker (
1217 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1221 UINT32 VariableMtrrCount
;
1223 VariableMtrrCount
= GetVariableMtrrCount ();
1224 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1226 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1),
1227 VariableSettings
->Mtrr
[Index
].Base
1230 MTRR_LIB_IA32_VARIABLE_MTRR_BASE
+ (Index
<< 1) + 1,
1231 VariableSettings
->Mtrr
[Index
].Mask
1238 This function sets variable MTRRs
1240 @param VariableSettings A buffer to hold variable MTRRs content.
1242 @return The pointer of VariableSettings
1245 MTRR_VARIABLE_SETTINGS
*
1247 MtrrSetVariableMtrr (
1248 IN MTRR_VARIABLE_SETTINGS
*VariableSettings
1253 Cr4
= PreMtrrChange ();
1254 MtrrSetVariableMtrrWorker (VariableSettings
);
1255 PostMtrrChange (Cr4
);
1256 return VariableSettings
;
1261 This function gets the content in fixed MTRRs
1263 @param FixedSettings A buffer to hold fixed Mtrrs content.
1265 @retval The pointer of FixedSettings
1268 MTRR_FIXED_SETTINGS
*
1271 OUT MTRR_FIXED_SETTINGS
*FixedSettings
1276 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1277 FixedSettings
->Mtrr
[Index
] =
1278 AsmReadMsr64 (MtrrLibFixedMtrrTable
[Index
].Msr
);
1281 return FixedSettings
;
1285 Worker function setting fixed MTRRs
1287 @param FixedSettings A buffer to hold fixed Mtrrs content.
1291 MtrrSetFixedMtrrWorker (
1292 IN MTRR_FIXED_SETTINGS
*FixedSettings
1297 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1299 MtrrLibFixedMtrrTable
[Index
].Msr
,
1300 FixedSettings
->Mtrr
[Index
]
1307 This function sets fixed MTRRs
1309 @param FixedSettings A buffer to hold fixed Mtrrs content.
1311 @retval The pointer of FixedSettings
1314 MTRR_FIXED_SETTINGS
*
1317 IN MTRR_FIXED_SETTINGS
*FixedSettings
1322 Cr4
= PreMtrrChange ();
1323 MtrrSetFixedMtrrWorker (FixedSettings
);
1324 PostMtrrChange (Cr4
);
1326 return FixedSettings
;
1331 This function gets the content in all MTRRs (variable and fixed)
1333 @param MtrrSetting A buffer to hold all Mtrrs content.
1335 @retval the pointer of MtrrSetting
1341 OUT MTRR_SETTINGS
*MtrrSetting
1347 MtrrGetFixedMtrr (&MtrrSetting
->Fixed
);
1350 // Get variable MTRRs
1352 MtrrGetVariableMtrr (&MtrrSetting
->Variables
);
1355 // Get MTRR_DEF_TYPE value
1357 MtrrSetting
->MtrrDefType
= AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
);
1364 This function sets all MTRRs (variable and fixed)
1366 @param MtrrSetting A buffer holding all MTRRs content.
1368 @retval The pointer of MtrrSetting
1374 IN MTRR_SETTINGS
*MtrrSetting
1379 Cr4
= PreMtrrChange ();
1384 MtrrSetFixedMtrrWorker (&MtrrSetting
->Fixed
);
1387 // Set variable MTRRs
1389 MtrrSetVariableMtrrWorker (&MtrrSetting
->Variables
);
1392 // Set MTRR_DEF_TYPE value
1394 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE
, MtrrSetting
->MtrrDefType
);
1396 PostMtrrChange (Cr4
);
1403 This function prints all MTRRs for debugging.
1406 MtrrDebugPrintAllMtrrs (
1411 MTRR_SETTINGS MtrrSettings
;
1413 UINTN VariableMtrrCount
;
1415 MtrrGetAllMtrrs (&MtrrSettings
);
1416 DEBUG((EFI_D_ERROR
, "DefaultType = %016lx\n", MtrrSettings
.MtrrDefType
));
1417 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
1419 EFI_D_ERROR
, "Fixed[%02d] = %016lx\n",
1421 MtrrSettings
.Fixed
.Mtrr
[Index
]
1425 VariableMtrrCount
= GetVariableMtrrCount ();
1426 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
1428 EFI_D_ERROR
, "Variable[%02d] = %016lx, %016lx\n",
1430 MtrrSettings
.Variables
.Mtrr
[Index
].Base
,
1431 MtrrSettings
.Variables
.Mtrr
[Index
].Mask