GetMemoryCacheTypeFromMtrrType () should return the default memory type instead of UC type for MTRR_CACHE_INVALID_TYPE. Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15053 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1720 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1720 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   MTRR setting library
 | |
| 
 | |
|   Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <Base.h>
 | |
| 
 | |
| #include <Library/MtrrLib.h>
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/CpuLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| 
 | |
| //
 | |
| // Context to save and restore when MTRRs are programmed
 | |
| //
 | |
| typedef struct {
 | |
|   UINTN    Cr4;
 | |
|   BOOLEAN  InterruptState;
 | |
| } MTRR_CONTEXT;
 | |
| 
 | |
| //
 | |
| // This table defines the offset, base and length of the fixed MTRRs
 | |
| //
 | |
| CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX64K_00000,
 | |
|     0,
 | |
|     SIZE_64KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX16K_80000,
 | |
|     0x80000,
 | |
|     SIZE_16KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX16K_A0000,
 | |
|     0xA0000,
 | |
|     SIZE_16KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_C0000,
 | |
|     0xC0000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_C8000,
 | |
|     0xC8000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_D0000,
 | |
|     0xD0000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_D8000,
 | |
|     0xD8000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_E0000,
 | |
|     0xE0000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_E8000,
 | |
|     0xE8000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_F0000,
 | |
|     0xF0000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
|   {
 | |
|     MTRR_LIB_IA32_MTRR_FIX4K_F8000,
 | |
|     0xF8000,
 | |
|     SIZE_4KB
 | |
|   },
 | |
| };
 | |
| 
 | |
| //
 | |
| // Lookup table used to print MTRRs
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
 | |
|   "UC",  // CacheUncacheable
 | |
|   "WC",  // CacheWriteCombining
 | |
|   "R*",  // Invalid
 | |
|   "R*",  // Invalid
 | |
|   "WT",  // CacheWriteThrough
 | |
|   "WP",  // CacheWriteProtected
 | |
|   "WB",  // CacheWriteBack
 | |
|   "R*"   // Invalid
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Returns the variable MTRR count for the CPU.
 | |
| 
 | |
|   @return Variable MTRR count
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| GetVariableMtrrCount (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32  VariableMtrrCount;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
 | |
|   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
 | |
| 
 | |
|   return VariableMtrrCount;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns the firmware usable variable MTRR count for the CPU.
 | |
| 
 | |
|   @return Firmware usable variable MTRR count
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| GetFirmwareVariableMtrrCount (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32  VariableMtrrCount;
 | |
| 
 | |
|   VariableMtrrCount = GetVariableMtrrCount ();
 | |
|   if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns the default MTRR cache type for the system.
 | |
| 
 | |
|   @return  The default MTRR cache type.
 | |
| 
 | |
| **/
 | |
| MTRR_MEMORY_CACHE_TYPE
 | |
| EFIAPI
 | |
| MtrrGetDefaultMemoryType (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return CacheUncacheable;
 | |
|   }
 | |
| 
 | |
|   return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Preparation before programming MTRR.
 | |
| 
 | |
|   This function will do some preparation for programming MTRRs:
 | |
|   disable cache, invalid cache and disable MTRR caching functionality
 | |
| 
 | |
|   @param[out] MtrrContext  Pointer to context to save
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PreMtrrChange (
 | |
|   OUT MTRR_CONTEXT  *MtrrContext
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Disable interrupts and save current interrupt state
 | |
|   //
 | |
|   MtrrContext->InterruptState = SaveAndDisableInterrupts();
 | |
|   
 | |
|   //
 | |
|   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
 | |
|   //
 | |
|   AsmDisableCache ();
 | |
| 
 | |
|   //
 | |
|   // Save original CR4 value and clear PGE flag (Bit 7)
 | |
|   //
 | |
|   MtrrContext->Cr4 = AsmReadCr4 ();
 | |
|   AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
 | |
| 
 | |
|   //
 | |
|   // Flush all TLBs
 | |
|   //
 | |
|   CpuFlushTlb ();
 | |
| 
 | |
|   //
 | |
|   // Disable Mtrrs
 | |
|   //
 | |
|   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cleaning up after programming MTRRs.
 | |
| 
 | |
|   This function will do some clean up after programming MTRRs:
 | |
|   Flush all TLBs,  re-enable caching, restore CR4.
 | |
| 
 | |
|   @param[in] MtrrContext  Pointer to context to restore
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PostMtrrChangeEnableCache (
 | |
|   IN MTRR_CONTEXT  *MtrrContext
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Flush all TLBs 
 | |
|   //
 | |
|   CpuFlushTlb ();
 | |
| 
 | |
|   //
 | |
|   // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
 | |
|   //
 | |
|   AsmEnableCache ();
 | |
| 
 | |
|   //
 | |
|   // Restore original CR4 value
 | |
|   //
 | |
|   AsmWriteCr4 (MtrrContext->Cr4);
 | |
|   
 | |
|   //
 | |
|   // Restore original interrupt state
 | |
|   //
 | |
|   SetInterruptState (MtrrContext->InterruptState);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cleaning up after programming MTRRs.
 | |
| 
 | |
|   This function will do some clean up after programming MTRRs:
 | |
|   enable MTRR caching functionality, and enable cache
 | |
| 
 | |
|   @param[in] MtrrContext  Pointer to context to restore
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PostMtrrChange (
 | |
|   IN MTRR_CONTEXT  *MtrrContext
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Enable Cache MTRR
 | |
|   //
 | |
|   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
 | |
| 
 | |
|   PostMtrrChangeEnableCache (MtrrContext);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Programs fixed MTRRs registers.
 | |
| 
 | |
|   @param  MemoryCacheType  The memory type to set.
 | |
|   @param  Base             The base address of memory range.
 | |
|   @param  Length           The length of memory range.
 | |
| 
 | |
|   @retval RETURN_SUCCESS      The cache type was updated successfully
 | |
|   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
 | |
|                               for the fixed MTRRs.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| ProgramFixedMtrr (
 | |
|   IN     UINT64     MemoryCacheType,
 | |
|   IN OUT UINT64     *Base,
 | |
|   IN OUT UINT64     *Length
 | |
|   )
 | |
| {
 | |
|   UINT32  MsrNum;
 | |
|   UINT32  ByteShift;
 | |
|   UINT64  TempQword;
 | |
|   UINT64  OrMask;
 | |
|   UINT64  ClearMask;
 | |
| 
 | |
|   TempQword = 0;
 | |
|   OrMask    = 0;
 | |
|   ClearMask = 0;
 | |
| 
 | |
|   for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
 | |
|     if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
 | |
|         (*Base <
 | |
|             (
 | |
|               mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
 | |
|               (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
 | |
|             )
 | |
|           )
 | |
|         ) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
 | |
|     return RETURN_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // We found the fixed MTRR to be programmed
 | |
|   //
 | |
|   for (ByteShift = 0; ByteShift < 8; ByteShift++) {
 | |
|     if (*Base ==
 | |
|          (
 | |
|            mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
 | |
|            (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
 | |
|          )
 | |
|        ) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ByteShift == 8) {
 | |
|     return RETURN_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   for (
 | |
|         ;
 | |
|         ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
 | |
|         ByteShift++
 | |
|       ) {
 | |
|     OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
 | |
|     ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
 | |
|     *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
 | |
|     *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
 | |
|   }
 | |
| 
 | |
|   if (ByteShift < 8 && (*Length != 0)) {
 | |
|     return RETURN_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   TempQword =
 | |
|     (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;
 | |
|   AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the attribute of variable MTRRs.
 | |
| 
 | |
|   This function shadows the content of variable MTRRs into an
 | |
|   internal array: VariableMtrr.
 | |
| 
 | |
|   @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR
 | |
|   @param  MtrrValidAddressMask  The valid address mask for MTRR
 | |
|   @param  VariableMtrr          The array to shadow variable MTRRs content
 | |
| 
 | |
|   @return                       The return value of this paramter indicates the
 | |
|                                 number of MTRRs which has been used.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| MtrrGetMemoryAttributeInVariableMtrr (
 | |
|   IN  UINT64                    MtrrValidBitsMask,
 | |
|   IN  UINT64                    MtrrValidAddressMask,
 | |
|   OUT VARIABLE_MTRR             *VariableMtrr
 | |
|   )
 | |
| {
 | |
|   UINTN   Index;
 | |
|   UINT32  MsrNum;
 | |
|   UINT32  UsedMtrr;
 | |
|   UINT32  FirmwareVariableMtrrCount;
 | |
|   UINT32  VariableMtrrEnd;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
 | |
|   VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
 | |
| 
 | |
|   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
 | |
|   UsedMtrr = 0;
 | |
| 
 | |
|   for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;
 | |
|        (
 | |
|          (MsrNum < VariableMtrrEnd) &&
 | |
|          (Index < FirmwareVariableMtrrCount)
 | |
|        );
 | |
|        MsrNum += 2
 | |
|       ) {
 | |
|     if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
 | |
|       VariableMtrr[Index].Msr          = MsrNum;
 | |
|       VariableMtrr[Index].BaseAddress  = (AsmReadMsr64 (MsrNum) &
 | |
|                                           MtrrValidAddressMask);
 | |
|       VariableMtrr[Index].Length       = ((~(AsmReadMsr64 (MsrNum + 1) &
 | |
|                                              MtrrValidAddressMask)
 | |
|                                           ) &
 | |
|                                           MtrrValidBitsMask
 | |
|                                          ) + 1;
 | |
|       VariableMtrr[Index].Type         = (AsmReadMsr64 (MsrNum) & 0x0ff);
 | |
|       VariableMtrr[Index].Valid        = TRUE;
 | |
|       VariableMtrr[Index].Used         = TRUE;
 | |
|       UsedMtrr = UsedMtrr  + 1;
 | |
|       Index++;
 | |
|     }
 | |
|   }
 | |
|   return UsedMtrr;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Checks overlap between given memory range and MTRRs.
 | |
| 
 | |
|   @param  Start            The start address of memory range.
 | |
|   @param  End              The end address of memory range.
 | |
|   @param  VariableMtrr     The array to shadow variable MTRRs content
 | |
| 
 | |
|   @retval TRUE             Overlap exists.
 | |
|   @retval FALSE            No overlap.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| CheckMemoryAttributeOverlap (
 | |
|   IN PHYSICAL_ADDRESS     Start,
 | |
|   IN PHYSICAL_ADDRESS     End,
 | |
|   IN VARIABLE_MTRR      *VariableMtrr
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
| 
 | |
|   for (Index = 0; Index < 6; Index++) {
 | |
|     if (
 | |
|          VariableMtrr[Index].Valid &&
 | |
|          !(
 | |
|            (Start > (VariableMtrr[Index].BaseAddress +
 | |
|                      VariableMtrr[Index].Length - 1)
 | |
|            ) ||
 | |
|            (End < VariableMtrr[Index].BaseAddress)
 | |
|          )
 | |
|        ) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Marks a variable MTRR as non-valid.
 | |
| 
 | |
|   @param  Index         The index of the array VariableMtrr to be invalidated
 | |
|   @param  VariableMtrr  The array to shadow variable MTRRs content
 | |
|   @param  UsedMtrr      The number of MTRRs which has already been used
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| InvalidateShadowMtrr (
 | |
|   IN   UINTN              Index,
 | |
|   IN   VARIABLE_MTRR      *VariableMtrr,
 | |
|   OUT  UINT32             *UsedMtrr
 | |
|   )
 | |
| {
 | |
|   VariableMtrr[Index].Valid = FALSE;
 | |
|   *UsedMtrr = *UsedMtrr - 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Combine memory attributes.
 | |
| 
 | |
|   If overlap exists between given memory range and MTRRs, try to combine them.
 | |
| 
 | |
|   @param  Attributes             The memory type to set.
 | |
|   @param  Base                   The base address of memory range.
 | |
|   @param  Length                 The length of memory range.
 | |
|   @param  VariableMtrr           The array to shadow variable MTRRs content
 | |
|   @param  UsedMtrr               The number of MTRRs which has already been used
 | |
|   @param  OverwriteExistingMtrr  Returns whether an existing MTRR was used
 | |
| 
 | |
|   @retval EFI_SUCCESS            Memory region successfully combined.
 | |
|   @retval EFI_ACCESS_DENIED      Memory region cannot be combined.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| CombineMemoryAttribute (
 | |
|   IN     UINT64             Attributes,
 | |
|   IN OUT UINT64             *Base,
 | |
|   IN OUT UINT64             *Length,
 | |
|   IN     VARIABLE_MTRR      *VariableMtrr,
 | |
|   IN OUT UINT32             *UsedMtrr,
 | |
|   OUT    BOOLEAN            *OverwriteExistingMtrr
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT64  CombineStart;
 | |
|   UINT64  CombineEnd;
 | |
|   UINT64  MtrrEnd;
 | |
|   UINT64  EndAddress;
 | |
|   UINT32  FirmwareVariableMtrrCount;
 | |
|   BOOLEAN CoveredByExistingMtrr;
 | |
| 
 | |
|   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
 | |
| 
 | |
|   *OverwriteExistingMtrr = FALSE;
 | |
|   CoveredByExistingMtrr = FALSE;
 | |
|   EndAddress = *Base +*Length - 1;
 | |
| 
 | |
|   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
 | |
| 
 | |
|     MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
 | |
|     if (
 | |
|          !VariableMtrr[Index].Valid ||
 | |
|          (
 | |
|            *Base > (MtrrEnd) ||
 | |
|            (EndAddress < VariableMtrr[Index].BaseAddress)
 | |
|          )
 | |
|        ) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Combine same attribute MTRR range
 | |
|     //
 | |
|     if (Attributes == VariableMtrr[Index].Type) {
 | |
|       //
 | |
|       // if the Mtrr range contain the request range, set a flag, then continue to 
 | |
|       // invalidate any MTRR of the same request range with higher priority cache type.
 | |
|       //
 | |
|       if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
 | |
|         CoveredByExistingMtrr = TRUE;
 | |
|         continue;
 | |
|       }
 | |
|       //
 | |
|       // invalid this MTRR, and program the combine range
 | |
|       //
 | |
|       CombineStart  =
 | |
|         (*Base) < VariableMtrr[Index].BaseAddress ?
 | |
|           (*Base) :
 | |
|           VariableMtrr[Index].BaseAddress;
 | |
|       CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
 | |
| 
 | |
|       //
 | |
|       // Record the MTRR usage status in VariableMtrr array.
 | |
|       //
 | |
|       InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
 | |
|       *Base       = CombineStart;
 | |
|       *Length     = CombineEnd - CombineStart + 1;
 | |
|       EndAddress  = CombineEnd;
 | |
|       *OverwriteExistingMtrr = TRUE;
 | |
|       continue;
 | |
|     } else {
 | |
|       //
 | |
|       // The cache type is different, but the range is convered by one MTRR
 | |
|       //
 | |
|       if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
 | |
|         InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
 | |
|          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
 | |
|         (Attributes == MTRR_CACHE_WRITE_BACK &&
 | |
|          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
 | |
|         (Attributes == MTRR_CACHE_UNCACHEABLE) ||
 | |
|         (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
 | |
|      ) {
 | |
|       *OverwriteExistingMtrr = TRUE;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Other type memory overlap is invalid
 | |
|     //
 | |
|     return RETURN_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (CoveredByExistingMtrr) {
 | |
|     *Length = 0;
 | |
|   }
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Calculate the maximum value which is a power of 2, but less the MemoryLength.
 | |
| 
 | |
|   @param  MemoryLength        The number to pass in.
 | |
|   @return The maximum value which is align to power of 2 and less the MemoryLength
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| Power2MaxMemory (
 | |
|   IN UINT64                     MemoryLength
 | |
|   )
 | |
| {
 | |
|   UINT64  Result;
 | |
| 
 | |
|   if (RShiftU64 (MemoryLength, 32) != 0) {
 | |
|     Result = LShiftU64 (
 | |
|                (UINT64) GetPowerOfTwo32 (
 | |
|                           (UINT32) RShiftU64 (MemoryLength, 32)
 | |
|                           ),
 | |
|                32
 | |
|                );
 | |
|   } else {
 | |
|     Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
 | |
|   }
 | |
| 
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Determine the MTRR numbers used to program a memory range.
 | |
| 
 | |
|   This function first checks the alignment of the base address. If the alignment of the base address <= Length,
 | |
|   cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
 | |
|   Repeat the step until alignment > Length.
 | |
| 
 | |
|   Then this function determines which direction of programming the variable MTRRs for the remaining length
 | |
|   will use fewer MTRRs.
 | |
| 
 | |
|   @param  BaseAddress Length of Memory to program MTRR
 | |
|   @param  Length      Length of Memory to program MTRR
 | |
|   @param  MtrrNumber  Pointer to the number of necessary MTRRs
 | |
| 
 | |
|   @retval TRUE        Positive direction is better.
 | |
|           FALSE       Negtive direction is better.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| GetMtrrNumberAndDirection (
 | |
|   IN UINT64      BaseAddress,
 | |
|   IN UINT64      Length,
 | |
|   IN UINTN       *MtrrNumber
 | |
|   )
 | |
| {
 | |
|   UINT64  TempQword;
 | |
|   UINT64  Alignment;
 | |
|   UINT32  Positive;
 | |
|   UINT32  Subtractive;
 | |
| 
 | |
|   *MtrrNumber = 0;
 | |
| 
 | |
|   if (BaseAddress != 0) {
 | |
|     do {
 | |
|       //
 | |
|       // Calculate the alignment of the base address.
 | |
|       //
 | |
|       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
 | |
| 
 | |
|       if (Alignment > Length) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       (*MtrrNumber)++;
 | |
|       BaseAddress += Alignment;
 | |
|       Length -= Alignment;
 | |
|     } while (TRUE);
 | |
| 
 | |
|     if (Length == 0) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   TempQword   = Length;
 | |
|   Positive    = 0;
 | |
|   Subtractive = 0;
 | |
| 
 | |
|   do {
 | |
|     TempQword -= Power2MaxMemory (TempQword);
 | |
|     Positive++;
 | |
|   } while (TempQword != 0);
 | |
| 
 | |
|   TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
 | |
|   Subtractive++;
 | |
|   do {
 | |
|     TempQword -= Power2MaxMemory (TempQword);
 | |
|     Subtractive++;
 | |
|   } while (TempQword != 0);
 | |
| 
 | |
|   if (Positive <= Subtractive) {
 | |
|     *MtrrNumber += Positive;
 | |
|     return TRUE;
 | |
|   } else {
 | |
|     *MtrrNumber += Subtractive;
 | |
|     return FALSE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Invalid variable MTRRs according to the value in the shadow array.
 | |
| 
 | |
|   This function programs MTRRs according to the values specified
 | |
|   in the shadow array.
 | |
| 
 | |
|   @param  VariableMtrr   The array to shadow variable MTRRs content
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| InvalidateMtrr (
 | |
|    IN     VARIABLE_MTRR      *VariableMtrr
 | |
|    )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   UINTN         VariableMtrrCount;
 | |
|   MTRR_CONTEXT  MtrrContext;
 | |
| 
 | |
|   PreMtrrChange (&MtrrContext);
 | |
|   Index = 0;
 | |
|   VariableMtrrCount = GetVariableMtrrCount ();
 | |
|   while (Index < VariableMtrrCount) {
 | |
|     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
 | |
|        AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
 | |
|        AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
 | |
|        VariableMtrr[Index].Used = FALSE;
 | |
|     }
 | |
|     Index ++;
 | |
|   }
 | |
|   PostMtrrChange (&MtrrContext);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Programs variable MTRRs
 | |
| 
 | |
|   This function programs variable MTRRs
 | |
| 
 | |
|   @param  MtrrNumber            Index of MTRR to program.
 | |
|   @param  BaseAddress           Base address of memory region.
 | |
|   @param  Length                Length of memory region.
 | |
|   @param  MemoryCacheType       Memory type to set.
 | |
|   @param  MtrrValidAddressMask  The valid address mask for MTRR
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ProgramVariableMtrr (
 | |
|   IN UINTN                    MtrrNumber,
 | |
|   IN PHYSICAL_ADDRESS         BaseAddress,
 | |
|   IN UINT64                   Length,
 | |
|   IN UINT64                   MemoryCacheType,
 | |
|   IN UINT64                   MtrrValidAddressMask
 | |
|   )
 | |
| {
 | |
|   UINT64        TempQword;
 | |
|   MTRR_CONTEXT  MtrrContext;
 | |
| 
 | |
|   PreMtrrChange (&MtrrContext);
 | |
| 
 | |
|   //
 | |
|   // MTRR Physical Base
 | |
|   //
 | |
|   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
 | |
|   AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
 | |
| 
 | |
|   //
 | |
|   // MTRR Physical Mask
 | |
|   //
 | |
|   TempQword = ~(Length - 1);
 | |
|   AsmWriteMsr64 (
 | |
|     (UINT32) (MtrrNumber + 1),
 | |
|     (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
 | |
|     );
 | |
| 
 | |
|   PostMtrrChange (&MtrrContext);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
 | |
| 
 | |
|   @param  MtrrType  MTRR memory type
 | |
| 
 | |
|   @return The enum item in MTRR_MEMORY_CACHE_TYPE
 | |
| 
 | |
| **/
 | |
| MTRR_MEMORY_CACHE_TYPE
 | |
| GetMemoryCacheTypeFromMtrrType (
 | |
|   IN UINT64                MtrrType
 | |
|   )
 | |
| {
 | |
|   switch (MtrrType) {
 | |
|   case MTRR_CACHE_UNCACHEABLE:
 | |
|     return CacheUncacheable;
 | |
|   case MTRR_CACHE_WRITE_COMBINING:
 | |
|     return CacheWriteCombining;
 | |
|   case MTRR_CACHE_WRITE_THROUGH:
 | |
|     return CacheWriteThrough;
 | |
|   case MTRR_CACHE_WRITE_PROTECTED:
 | |
|     return CacheWriteProtected;
 | |
|   case MTRR_CACHE_WRITE_BACK:
 | |
|     return CacheWriteBack;
 | |
|   default:
 | |
|     //
 | |
|     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
 | |
|     // no mtrr covers the range
 | |
|     //
 | |
|     return MtrrGetDefaultMemoryType ();
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initializes the valid bits mask and valid address mask for MTRRs.
 | |
| 
 | |
|   This function initializes the valid bits mask and valid address mask for MTRRs.
 | |
| 
 | |
|   @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR
 | |
|   @param  MtrrValidAddressMask  The valid address mask for the MTRR
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MtrrLibInitializeMtrrMask (
 | |
|   OUT UINT64 *MtrrValidBitsMask,
 | |
|   OUT UINT64 *MtrrValidAddressMask
 | |
|   )
 | |
| {
 | |
|   UINT32  RegEax;
 | |
|   UINT8   PhysicalAddressBits;
 | |
| 
 | |
|   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 | |
| 
 | |
|   if (RegEax >= 0x80000008) {
 | |
|     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 | |
| 
 | |
|     PhysicalAddressBits = (UINT8) RegEax;
 | |
| 
 | |
|     *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
 | |
|     *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
 | |
|   } else {
 | |
|     *MtrrValidBitsMask    = MTRR_LIB_CACHE_VALID_ADDRESS;
 | |
|     *MtrrValidAddressMask = 0xFFFFFFFF;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Determing the real attribute of a memory range.
 | |
| 
 | |
|   This function is to arbitrate the real attribute of the memory when
 | |
|   there are 2 MTRR covers the same memory range.  For further details,
 | |
|   please refer the IA32 Software Developer's Manual, Volume 3,
 | |
|   Section 10.11.4.1.
 | |
| 
 | |
|   @param  MtrrType1    the first kind of Memory type
 | |
|   @param  MtrrType2    the second kind of memory type
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| MtrrPrecedence (
 | |
|   UINT64    MtrrType1,
 | |
|   UINT64    MtrrType2
 | |
|   )
 | |
| {
 | |
|   UINT64 MtrrType;
 | |
| 
 | |
|   MtrrType = MTRR_CACHE_INVALID_TYPE;
 | |
|   switch (MtrrType1) {
 | |
|   case MTRR_CACHE_UNCACHEABLE:
 | |
|     MtrrType = MTRR_CACHE_UNCACHEABLE;
 | |
|     break;
 | |
|   case MTRR_CACHE_WRITE_COMBINING:
 | |
|     if (
 | |
|          MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
 | |
|          MtrrType2==MTRR_CACHE_UNCACHEABLE
 | |
|        ) {
 | |
|       MtrrType = MtrrType2;
 | |
|     }
 | |
|     break;
 | |
|   case MTRR_CACHE_WRITE_THROUGH:
 | |
|     if (
 | |
|          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
 | |
|          MtrrType2==MTRR_CACHE_WRITE_BACK
 | |
|        ) {
 | |
|       MtrrType = MTRR_CACHE_WRITE_THROUGH;
 | |
|     } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
 | |
|       MtrrType = MTRR_CACHE_UNCACHEABLE;
 | |
|     }
 | |
|     break;
 | |
|   case MTRR_CACHE_WRITE_PROTECTED:
 | |
|     if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
 | |
|         MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
 | |
|       MtrrType = MtrrType2;
 | |
|     }
 | |
|     break;
 | |
|   case MTRR_CACHE_WRITE_BACK:
 | |
|     if (
 | |
|          MtrrType2== MTRR_CACHE_UNCACHEABLE ||
 | |
|          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
 | |
|          MtrrType2== MTRR_CACHE_WRITE_BACK
 | |
|        ) {
 | |
|       MtrrType = MtrrType2;
 | |
|     }
 | |
|     break;
 | |
|   case MTRR_CACHE_INVALID_TYPE:
 | |
|     MtrrType = MtrrType2;
 | |
|     break;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
 | |
|     MtrrType = MtrrType1;
 | |
|   }
 | |
|   return MtrrType;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function attempts to set the attributes for a memory range.
 | |
| 
 | |
|   @param  BaseAddress            The physical address that is the start
 | |
|                                  address of a memory region.
 | |
|   @param  Length                 The size in bytes of the memory region.
 | |
|   @param  Attributes             The bit mask of attributes to set for the
 | |
|                                  memory region.
 | |
| 
 | |
|   @retval RETURN_SUCCESS            The attributes were set for the memory
 | |
|                                     region.
 | |
|   @retval RETURN_INVALID_PARAMETER  Length is zero.
 | |
|   @retval RETURN_UNSUPPORTED        The processor does not support one or
 | |
|                                     more bytes of the memory resource range
 | |
|                                     specified by BaseAddress and Length.
 | |
|   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
 | |
|                                     for the memory resource range specified
 | |
|                                     by BaseAddress and Length.
 | |
|   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
 | |
|                                     range specified by BaseAddress and Length
 | |
|                                     cannot be modified.
 | |
|   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
 | |
|                                     modify the attributes of the memory
 | |
|                                     resource range.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| MtrrSetMemoryAttribute (
 | |
|   IN PHYSICAL_ADDRESS        BaseAddress,
 | |
|   IN UINT64                  Length,
 | |
|   IN MTRR_MEMORY_CACHE_TYPE  Attribute
 | |
|   )
 | |
| {
 | |
|   UINT64                    TempQword;
 | |
|   RETURN_STATUS             Status;
 | |
|   UINT64                    MemoryType;
 | |
|   UINT64                    Alignment;
 | |
|   BOOLEAN                   OverLap;
 | |
|   BOOLEAN                   Positive;
 | |
|   UINT32                    MsrNum;
 | |
|   UINTN                     MtrrNumber;
 | |
|   VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
 | |
|   UINT32                    UsedMtrr;
 | |
|   UINT64                    MtrrValidBitsMask;
 | |
|   UINT64                    MtrrValidAddressMask;
 | |
|   BOOLEAN                   OverwriteExistingMtrr;
 | |
|   UINT32                    FirmwareVariableMtrrCount;
 | |
|   UINT32                    VariableMtrrEnd;
 | |
|   MTRR_CONTEXT              MtrrContext;
 | |
| 
 | |
|   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     Status = RETURN_UNSUPPORTED;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
 | |
|   VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
 | |
| 
 | |
|   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
 | |
| 
 | |
|   TempQword = 0;
 | |
|   MemoryType = (UINT64)Attribute;
 | |
|   OverwriteExistingMtrr = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Check for an invalid parameter
 | |
|   //
 | |
|   if (Length == 0) {
 | |
|     Status = RETURN_INVALID_PARAMETER;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (
 | |
|        (BaseAddress & ~MtrrValidAddressMask) != 0 ||
 | |
|        (Length & ~MtrrValidAddressMask) != 0
 | |
|      ) {
 | |
|     Status = RETURN_UNSUPPORTED;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check if Fixed MTRR
 | |
|   //
 | |
|   Status = RETURN_SUCCESS;
 | |
|   while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
 | |
|     PreMtrrChange (&MtrrContext);
 | |
|     Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);
 | |
|     PostMtrrChange (&MtrrContext);
 | |
|     if (RETURN_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Length == 0) {
 | |
|     //
 | |
|     // A Length of 0 can only make sense for fixed MTTR ranges.
 | |
|     // Since we just handled the fixed MTRRs, we can skip the
 | |
|     // variable MTRR section.
 | |
|     //
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
 | |
|   // we can set the base to 0 to save variable MTRRs.
 | |
|   //
 | |
|   if (BaseAddress == BASE_1MB) {
 | |
|     BaseAddress = 0;
 | |
|     Length += SIZE_1MB;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check for overlap
 | |
|   //
 | |
|   UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);
 | |
|   OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);
 | |
|   if (OverLap) {
 | |
|     Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);
 | |
|     if (RETURN_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (Length == 0) {
 | |
|       //
 | |
|       // Combined successfully, invalidate the now-unused MTRRs
 | |
|       //
 | |
|       InvalidateMtrr(VariableMtrr);
 | |
|       Status = RETURN_SUCCESS;
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The memory type is the same with the type specified by
 | |
|   // MTRR_LIB_IA32_MTRR_DEF_TYPE.
 | |
|   //
 | |
|   if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {
 | |
|     //
 | |
|     // Invalidate the now-unused MTRRs
 | |
|     //
 | |
|     InvalidateMtrr(VariableMtrr);
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
 | |
| 
 | |
|   if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
 | |
|     Status = RETURN_OUT_OF_RESOURCES;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Invalidate the now-unused MTRRs
 | |
|   //
 | |
|   InvalidateMtrr(VariableMtrr);
 | |
| 
 | |
|   //
 | |
|   // Find first unused MTRR
 | |
|   //
 | |
|   for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
 | |
|        MsrNum < VariableMtrrEnd;
 | |
|        MsrNum += 2
 | |
|       ) {
 | |
|     if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (BaseAddress != 0) {
 | |
|     do {
 | |
|       //
 | |
|       // Calculate the alignment of the base address.
 | |
|       //
 | |
|       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
 | |
| 
 | |
|       if (Alignment > Length) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Find unused MTRR
 | |
|       //
 | |
|       for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
 | |
|         if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       ProgramVariableMtrr (
 | |
|         MsrNum,
 | |
|         BaseAddress,
 | |
|         Alignment,
 | |
|         MemoryType,
 | |
|         MtrrValidAddressMask
 | |
|         );
 | |
|       BaseAddress += Alignment;
 | |
|       Length -= Alignment;
 | |
|     } while (TRUE);
 | |
| 
 | |
|     if (Length == 0) {
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   TempQword = Length;
 | |
| 
 | |
|   if (!Positive) {
 | |
|     Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
 | |
| 
 | |
|     //
 | |
|     // Find unused MTRR
 | |
|     //
 | |
|     for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
 | |
|       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     ProgramVariableMtrr (
 | |
|       MsrNum,
 | |
|       BaseAddress,
 | |
|       Length,
 | |
|       MemoryType,
 | |
|       MtrrValidAddressMask
 | |
|       );
 | |
|     BaseAddress += Length;
 | |
|     TempQword   = Length - TempQword;
 | |
|     MemoryType  = MTRR_CACHE_UNCACHEABLE;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     // Find unused MTRR
 | |
|     //
 | |
|     for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
 | |
|       if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Length = Power2MaxMemory (TempQword);
 | |
|     if (!Positive) {
 | |
|       BaseAddress -= Length;
 | |
|     }
 | |
| 
 | |
|     ProgramVariableMtrr (
 | |
|       MsrNum,
 | |
|       BaseAddress,
 | |
|       Length,
 | |
|       MemoryType,
 | |
|       MtrrValidAddressMask
 | |
|       );
 | |
| 
 | |
|     if (Positive) {
 | |
|       BaseAddress += Length;
 | |
|     }
 | |
|     TempQword -= Length;
 | |
| 
 | |
|   } while (TempQword > 0);
 | |
| 
 | |
| Done:
 | |
|   DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));
 | |
|   if (!RETURN_ERROR (Status)) {
 | |
|     MtrrDebugPrintAllMtrrs ();
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function will get the memory cache type of the specific address.
 | |
| 
 | |
|   This function is mainly for debug purpose.
 | |
| 
 | |
|   @param  Address   The specific address
 | |
| 
 | |
|   @return Memory cache type of the sepcific address
 | |
| 
 | |
| **/
 | |
| MTRR_MEMORY_CACHE_TYPE
 | |
| EFIAPI
 | |
| MtrrGetMemoryAttribute (
 | |
|   IN PHYSICAL_ADDRESS   Address
 | |
|   )
 | |
| {
 | |
|   UINT64                  TempQword;
 | |
|   UINTN                   Index;
 | |
|   UINTN                   SubIndex;
 | |
|   UINT64                  MtrrType;
 | |
|   UINT64                  TempMtrrType;
 | |
|   MTRR_MEMORY_CACHE_TYPE  CacheType;
 | |
|   VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
 | |
|   UINT64                  MtrrValidBitsMask;
 | |
|   UINT64                  MtrrValidAddressMask;
 | |
|   UINTN                   VariableMtrrCount;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return CacheUncacheable;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check if MTRR is enabled, if not, return UC as attribute
 | |
|   //
 | |
|   TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
 | |
|   MtrrType = MTRR_CACHE_INVALID_TYPE;
 | |
| 
 | |
|   if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
 | |
|     return CacheUncacheable;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If address is less than 1M, then try to go through the fixed MTRR
 | |
|   //
 | |
|   if (Address < BASE_1MB) {
 | |
|     if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
 | |
|       //
 | |
|       // Go through the fixed MTRR
 | |
|       //
 | |
|       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
 | |
|          if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
 | |
|              Address  < (
 | |
|                           mMtrrLibFixedMtrrTable[Index].BaseAddress +
 | |
|                           (mMtrrLibFixedMtrrTable[Index].Length * 8)
 | |
|                         )
 | |
|             ) {
 | |
|            SubIndex =
 | |
|              ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
 | |
|                mMtrrLibFixedMtrrTable[Index].Length;
 | |
|            TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
 | |
|            MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
 | |
|            return GetMemoryCacheTypeFromMtrrType (MtrrType);
 | |
|          }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
 | |
|   MtrrGetMemoryAttributeInVariableMtrr(
 | |
|     MtrrValidBitsMask,
 | |
|     MtrrValidAddressMask,
 | |
|     VariableMtrr
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Go through the variable MTRR
 | |
|   //
 | |
|   VariableMtrrCount = GetVariableMtrrCount ();
 | |
|   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
 | |
| 
 | |
|   for (Index = 0; Index < VariableMtrrCount; Index++) {
 | |
|     if (VariableMtrr[Index].Valid) {
 | |
|       if (Address >= VariableMtrr[Index].BaseAddress &&
 | |
|           Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
 | |
|         TempMtrrType = VariableMtrr[Index].Type;
 | |
|         MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
 | |
| 
 | |
|   return CacheType;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function will get the raw value in variable MTRRs
 | |
| 
 | |
|   @param  VariableSettings   A buffer to hold variable MTRRs content.
 | |
| 
 | |
|   @return The VariableSettings input pointer
 | |
| 
 | |
| **/
 | |
| MTRR_VARIABLE_SETTINGS*
 | |
| EFIAPI
 | |
| MtrrGetVariableMtrr (
 | |
|   OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  VariableMtrrCount;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return VariableSettings;
 | |
|   }
 | |
| 
 | |
|   VariableMtrrCount = GetVariableMtrrCount ();
 | |
|   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
 | |
| 
 | |
|   for (Index = 0; Index < VariableMtrrCount; Index++) {
 | |
|     VariableSettings->Mtrr[Index].Base =
 | |
|       AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
 | |
|     VariableSettings->Mtrr[Index].Mask =
 | |
|       AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
 | |
|   }
 | |
| 
 | |
|   return  VariableSettings;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Worker function setting variable MTRRs
 | |
| 
 | |
|   @param  VariableSettings   A buffer to hold variable MTRRs content.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MtrrSetVariableMtrrWorker (
 | |
|   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  VariableMtrrCount;
 | |
| 
 | |
|   VariableMtrrCount = GetVariableMtrrCount ();
 | |
|   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
 | |
| 
 | |
|   for (Index = 0; Index < VariableMtrrCount; Index++) {
 | |
|     AsmWriteMsr64 (
 | |
|       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
 | |
|       VariableSettings->Mtrr[Index].Base
 | |
|       );
 | |
|     AsmWriteMsr64 (
 | |
|       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
 | |
|       VariableSettings->Mtrr[Index].Mask
 | |
|       );
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function sets variable MTRRs
 | |
| 
 | |
|   @param  VariableSettings   A buffer to hold variable MTRRs content.
 | |
| 
 | |
|   @return The pointer of VariableSettings
 | |
| 
 | |
| **/
 | |
| MTRR_VARIABLE_SETTINGS*
 | |
| EFIAPI
 | |
| MtrrSetVariableMtrr (
 | |
|   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
 | |
|   )
 | |
| {
 | |
|   MTRR_CONTEXT  MtrrContext;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return VariableSettings;
 | |
|   }
 | |
| 
 | |
|   PreMtrrChange (&MtrrContext);
 | |
|   MtrrSetVariableMtrrWorker (VariableSettings);
 | |
|   PostMtrrChange (&MtrrContext);
 | |
|   return  VariableSettings;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function gets the content in fixed MTRRs
 | |
| 
 | |
|   @param  FixedSettings  A buffer to hold fixed Mtrrs content.
 | |
| 
 | |
|   @retval The pointer of FixedSettings
 | |
| 
 | |
| **/
 | |
| MTRR_FIXED_SETTINGS*
 | |
| EFIAPI
 | |
| MtrrGetFixedMtrr (
 | |
|   OUT MTRR_FIXED_SETTINGS         *FixedSettings
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return FixedSettings;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
 | |
|       FixedSettings->Mtrr[Index] =
 | |
|         AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
 | |
|   };
 | |
| 
 | |
|   return FixedSettings;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function setting fixed MTRRs
 | |
| 
 | |
|   @param  FixedSettings  A buffer to hold fixed Mtrrs content.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MtrrSetFixedMtrrWorker (
 | |
|   IN MTRR_FIXED_SETTINGS          *FixedSettings
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
| 
 | |
|   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
 | |
|      AsmWriteMsr64 (
 | |
|        mMtrrLibFixedMtrrTable[Index].Msr,
 | |
|        FixedSettings->Mtrr[Index]
 | |
|        );
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function sets fixed MTRRs
 | |
| 
 | |
|   @param  FixedSettings  A buffer to hold fixed Mtrrs content.
 | |
| 
 | |
|   @retval The pointer of FixedSettings
 | |
| 
 | |
| **/
 | |
| MTRR_FIXED_SETTINGS*
 | |
| EFIAPI
 | |
| MtrrSetFixedMtrr (
 | |
|   IN MTRR_FIXED_SETTINGS          *FixedSettings
 | |
|   )
 | |
| {
 | |
|   MTRR_CONTEXT  MtrrContext;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return FixedSettings;
 | |
|   }
 | |
| 
 | |
|   PreMtrrChange (&MtrrContext);
 | |
|   MtrrSetFixedMtrrWorker (FixedSettings);
 | |
|   PostMtrrChange (&MtrrContext);
 | |
| 
 | |
|   return FixedSettings;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function gets the content in all MTRRs (variable and fixed)
 | |
| 
 | |
|   @param  MtrrSetting  A buffer to hold all Mtrrs content.
 | |
| 
 | |
|   @retval the pointer of MtrrSetting
 | |
| 
 | |
| **/
 | |
| MTRR_SETTINGS *
 | |
| EFIAPI
 | |
| MtrrGetAllMtrrs (
 | |
|   OUT MTRR_SETTINGS                *MtrrSetting
 | |
|   )
 | |
| {
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return MtrrSetting;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get fixed MTRRs
 | |
|   //
 | |
|   MtrrGetFixedMtrr (&MtrrSetting->Fixed);
 | |
| 
 | |
|   //
 | |
|   // Get variable MTRRs
 | |
|   //
 | |
|   MtrrGetVariableMtrr (&MtrrSetting->Variables);
 | |
| 
 | |
|   //
 | |
|   // Get MTRR_DEF_TYPE value
 | |
|   //
 | |
|   MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
 | |
| 
 | |
|   return MtrrSetting;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function sets all MTRRs (variable and fixed)
 | |
| 
 | |
|   @param  MtrrSetting  A buffer holding all MTRRs content.
 | |
| 
 | |
|   @retval The pointer of MtrrSetting
 | |
| 
 | |
| **/
 | |
| MTRR_SETTINGS *
 | |
| EFIAPI
 | |
| MtrrSetAllMtrrs (
 | |
|   IN MTRR_SETTINGS                *MtrrSetting
 | |
|   )
 | |
| {
 | |
|   MTRR_CONTEXT  MtrrContext;
 | |
| 
 | |
|   if (!IsMtrrSupported ()) {
 | |
|     return MtrrSetting;
 | |
|   }
 | |
| 
 | |
|   PreMtrrChange (&MtrrContext);
 | |
| 
 | |
|   //
 | |
|   // Set fixed MTRRs
 | |
|   //
 | |
|   MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
 | |
| 
 | |
|   //
 | |
|   // Set variable MTRRs
 | |
|   //
 | |
|   MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
 | |
| 
 | |
|   //
 | |
|   // Set MTRR_DEF_TYPE value
 | |
|   //
 | |
|   AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
 | |
| 
 | |
|   PostMtrrChangeEnableCache (&MtrrContext);
 | |
| 
 | |
|   return MtrrSetting;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function prints all MTRRs for debugging.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| MtrrDebugPrintAllMtrrs (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   DEBUG_CODE (
 | |
|     MTRR_SETTINGS  MtrrSettings;
 | |
|     UINTN          Index;
 | |
|     UINTN          Index1;
 | |
|     UINTN          VariableMtrrCount;
 | |
|     UINT64         Base;
 | |
|     UINT64         Limit;
 | |
|     UINT64         MtrrBase;
 | |
|     UINT64         MtrrLimit;
 | |
|     UINT64         RangeBase;
 | |
|     UINT64         RangeLimit;
 | |
|     UINT64         NoRangeBase;
 | |
|     UINT64         NoRangeLimit;
 | |
|     UINT32         RegEax;
 | |
|     UINTN          MemoryType;
 | |
|     UINTN          PreviousMemoryType;
 | |
|     BOOLEAN        Found;
 | |
| 
 | |
|     if (!IsMtrrSupported ()) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
 | |
|     DEBUG((DEBUG_CACHE, "=============\n"));
 | |
|     
 | |
|     MtrrGetAllMtrrs (&MtrrSettings);
 | |
|     DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));
 | |
|     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
 | |
|       DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));
 | |
|     }
 | |
| 
 | |
|     VariableMtrrCount = GetVariableMtrrCount ();
 | |
|     for (Index = 0; Index < VariableMtrrCount; Index++) {
 | |
|       DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
 | |
|         Index,
 | |
|         MtrrSettings.Variables.Mtrr[Index].Base,
 | |
|         MtrrSettings.Variables.Mtrr[Index].Mask
 | |
|         ));
 | |
|     }
 | |
|     DEBUG((DEBUG_CACHE, "\n"));
 | |
|     DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
 | |
|     DEBUG((DEBUG_CACHE, "====================================\n"));
 | |
| 
 | |
|     Base = 0;
 | |
|     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
 | |
|     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
 | |
|       Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
 | |
|       for (Index1 = 0; Index1 < 8; Index1++) {
 | |
|       MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);
 | |
|         if (MemoryType > CacheWriteBack) {
 | |
|           MemoryType = MTRR_CACHE_INVALID_TYPE;
 | |
|         }            
 | |
|         if (MemoryType != PreviousMemoryType) {
 | |
|           if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
 | |
|             DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
 | |
|           }
 | |
|           PreviousMemoryType = MemoryType;
 | |
|           DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
 | |
|         }
 | |
|         Base += mMtrrLibFixedMtrrTable[Index].Length;
 | |
|       }
 | |
|     }
 | |
|     DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
 | |
| 
 | |
|     VariableMtrrCount = GetVariableMtrrCount ();
 | |
| 
 | |
|     Limit        = BIT36 - 1;
 | |
|     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 | |
|     if (RegEax >= 0x80000008) {
 | |
|       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 | |
|       Limit = LShiftU64 (1, RegEax & 0xff) - 1;
 | |
|     }
 | |
|     Base = BASE_1MB;
 | |
|     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
 | |
|     do {
 | |
|       MemoryType = MtrrGetMemoryAttribute (Base);
 | |
|       if (MemoryType > CacheWriteBack) {
 | |
|         MemoryType = MTRR_CACHE_INVALID_TYPE;
 | |
|       }
 | |
| 
 | |
|       if (MemoryType != PreviousMemoryType) {
 | |
|         if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
 | |
|           DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
 | |
|         }
 | |
|         PreviousMemoryType = MemoryType;
 | |
|         DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
 | |
|       }
 | |
|       
 | |
|       RangeBase    = BASE_1MB;        
 | |
|       NoRangeBase  = BASE_1MB;
 | |
|       RangeLimit   = Limit;
 | |
|       NoRangeLimit = Limit;
 | |
|       
 | |
|       for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
 | |
|         if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {
 | |
|           //
 | |
|           // If mask is not valid, then do not display range
 | |
|           //
 | |
|           continue;
 | |
|         }
 | |
|         MtrrBase  = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
 | |
|         MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
 | |
| 
 | |
|         if (Base >= MtrrBase && Base < MtrrLimit) {
 | |
|           Found = TRUE;
 | |
|         }
 | |
|         
 | |
|         if (Base >= MtrrBase && MtrrBase > RangeBase) {
 | |
|           RangeBase = MtrrBase;
 | |
|         }
 | |
|         if (Base > MtrrLimit && MtrrLimit > RangeBase) {
 | |
|           RangeBase = MtrrLimit + 1;
 | |
|         }
 | |
|         if (Base < MtrrBase && MtrrBase < RangeLimit) {
 | |
|           RangeLimit = MtrrBase - 1;
 | |
|         }
 | |
|         if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
 | |
|           RangeLimit = MtrrLimit;
 | |
|         }
 | |
|         
 | |
|         if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
 | |
|           NoRangeBase = MtrrLimit + 1;
 | |
|         }
 | |
|         if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
 | |
|           NoRangeLimit = MtrrBase - 1;
 | |
|         }
 | |
|       }
 | |
|       
 | |
|       if (Found) {
 | |
|         Base = RangeLimit + 1;
 | |
|       } else {
 | |
|         Base = NoRangeLimit + 1;
 | |
|       }
 | |
|     } while (Base < Limit);
 | |
|     DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Checks if MTRR is supported.
 | |
| 
 | |
|   @retval TRUE  MTRR is supported.
 | |
|   @retval FALSE MTRR is not supported.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| IsMtrrSupported (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32  RegEdx;
 | |
|   UINT64  MtrrCap;
 | |
| 
 | |
|   //
 | |
|   // Check CPUID(1).EDX[12] for MTRR capability
 | |
|   //
 | |
|   AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
 | |
|   if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
 | |
|   // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
 | |
|   // exist, return false.
 | |
|   //
 | |
|   MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
 | |
|   if  ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 |