/** @file EFI 2.0 PEIM to initialize the cache and load the BSP microcode @copyright Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. This file contains an 'Intel Pre-EFI Module' and is licensed for Intel CPUs and Chipsets under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to additional terms of the license agreement **/ #if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) #include "EdkIIGluePeim.h" #include "CpuAccess.h" #include "CpuInitPeim.h" #include EFI_PPI_PRODUCER (Cache) #define ALIGNED_SEED 0x01010101 #endif INT8 CheckDirection ( IN UINT64 Input ); UINT64 PeiPower2MaxMemory ( IN UINT64 MemoryLength ); VOID EfiDisableCacheMtrr ( IN UINT64 *OldMtrr ); VOID EfiRecoverCacheMtrr ( IN BOOLEAN EnableMtrr, IN UINT64 OldMtrr ); VOID EfiProgramMtrr ( IN PEI_CACHE_PPI *This, IN UINTN MtrrNumber, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, IN UINT64 ValidMtrrAddressMask ); EFI_STATUS EFIAPI PeiResetCacheAttributes ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This ); EFI_STATUS EFIAPI PeiActivateCache ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This ); EFI_STATUS EFIAPI PeiSetCacheAttributes ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType ); EFI_STATUS SearchForExactMtrr ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN UINT64 ValidMtrrAddressMask, OUT UINT32 *UsedMsrNum, OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType ); BOOLEAN IsDefaultType ( IN EFI_MEMORY_CACHE_TYPE MemoryCacheType ); EFI_STATUS DisableCacheAsRam ( VOID ); typedef struct _ALIGNED_DWORD { UINT32 High; UINT32 Low; } ALIGNED_DWORD; typedef union _ALIGNED { UINT64 AlignedQword; ALIGNED_DWORD AlignedDword; } ALIGNED; typedef struct { UINT32 Msr; UINT32 BaseAddress; UINT32 Length; } FIXED_MTRR; FIXED_MTRR mFixedMtrrTable[] = { { IA32_MTRR_FIX64K_00000, 0, 0x10000 }, { IA32_MTRR_FIX16K_80000, 0x80000, 0x4000 }, { IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000 }, { IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000 }, { IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000 }, { IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000 }, { IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000 }, { IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000 }, { IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000 }, { IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000 }, { IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000 }, { 0, 0x100000, 0 } }; PEI_CACHE_PPI mCachePpi = { PeiSetCacheAttributes, PeiResetCacheAttributes, PeiActivateCache }; /** Update MTRR setting to memory buffer @param[in] This - Current instance of Pei Cache PPI. @param[in] MsrNum - offset 0-10 maps to Fixed MTRR table offset above 0x200 maps to Variable MTRR table @param[in] UpdateValue - MTRR setting **/ VOID WriteMsrToBuffer ( IN PEI_CACHE_PPI *This, IN UINT32 MsrNum, IN UINT64 UpdateValue ) { CACHE_PPI_INSTANCE *CachePpiInstance; CachePpiInstance = PEI_CACHE_PPI_INSTANCE_FROM_THIS (This); if (MsrNum >= CACHE_VARIABLE_MTRR_BASE) { if ((MsrNum - CACHE_VARIABLE_MTRR_BASE) >= V_MAXIMUM_VARIABLE_MTRR_NUMBER * 2) { ASSERT (FALSE); return; } CachePpiInstance->VariableMtrrChanged = TRUE; CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].Changed = TRUE; CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].MsrValue = UpdateValue; } else { if (MsrNum >= V_FIXED_MTRR_NUMBER) { ASSERT (FALSE); return; } CachePpiInstance->FixedMtrrChanged = TRUE; CachePpiInstance->FixedMtrrValue[MsrNum].Changed = TRUE; CachePpiInstance->FixedMtrrValue[MsrNum].MsrValue = UpdateValue; } } /** Read MTRR from Buffer. If buffer not ready, read from real MSR instead. @param[in] This - Current instance of Pei Cache PPI. @param[in] MsrNum - offset 0-10 maps to Fixed MTRR table offset above 0x200 maps to Variable MTRR table @retval Return MTRR setting **/ UINT64 ReadMsrFromBuffer ( IN PEI_CACHE_PPI *This, IN UINT32 MsrNum ) { UINT64 MtrrVal; CACHE_PPI_INSTANCE *CachePpiInstance; CachePpiInstance = PEI_CACHE_PPI_INSTANCE_FROM_THIS (This); if (MsrNum >= CACHE_VARIABLE_MTRR_BASE) { if ((MsrNum - CACHE_VARIABLE_MTRR_BASE) >= V_MAXIMUM_VARIABLE_MTRR_NUMBER * 2) { ASSERT (FALSE); return 0; } if (CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].Changed) { MtrrVal = CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].MsrValue; } else { MtrrVal = AsmReadMsr64 (MsrNum); } } else { if (MsrNum >= V_FIXED_MTRR_NUMBER) { ASSERT (FALSE); return 0; } if (CachePpiInstance->FixedMtrrValue[MsrNum].Changed) { MtrrVal = CachePpiInstance->FixedMtrrValue[MsrNum].MsrValue; } else { MtrrVal = AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr); } } return MtrrVal; } /** Disable cache and its mtrr @param[in] OldMtrr - To return the Old MTRR value **/ VOID EfiDisableCacheMtrr ( OUT UINT64 *OldMtrr ) { UINT64 TempQword; EfiDisableCache (); /// /// Disable Cache MTRR /// *OldMtrr = AsmReadMsr64 (CACHE_IA32_MTRR_DEF_TYPE); TempQword = (*OldMtrr) &~B_CACHE_MTRR_VALID &~B_CACHE_FIXED_MTRR_VALID; AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, TempQword); return; } /** Recover cache MTRR @param[in] EnableMtrr - Whether to enable the MTRR @param[in] OldMtrr - The saved old MTRR value to restore when not to enable the MTRR **/ VOID EfiRecoverCacheMtrr ( IN BOOLEAN EnableMtrr, IN UINT64 OldMtrr ) { UINT64 TempQword; TempQword = 0; /// /// Enable Cache MTRR /// if (EnableMtrr) { TempQword = AsmReadMsr64 (CACHE_IA32_MTRR_DEF_TYPE); TempQword |= (B_CACHE_MTRR_VALID | B_CACHE_FIXED_MTRR_VALID); } else { TempQword = OldMtrr; } AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, TempQword); EfiEnableCache (); return; } /** Programming MTRR according to Memory address, length, and type. @param[in] This - Pointer to PEI_CACHE_PPI @param[in] MtrrNumber - the variable MTRR index number @param[in] MemoryAddress - the address of target memory @param[in] MemoryLength - the length of target memory @param[in] MemoryCacheType - the cache type of target memory @param[in] ValidMtrrAddressMask - the MTRR address mask **/ VOID EfiProgramMtrr ( IN PEI_CACHE_PPI *This, IN UINT32 MtrrNumber, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, IN UINT64 ValidMtrrAddressMask ) { UINT64 TempQword; /// /// MTRR Physical Base /// TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType; WriteMsrToBuffer (This, MtrrNumber, TempQword); /// /// MTRR Physical Mask /// TempQword = ~(MemoryLength - 1); WriteMsrToBuffer (This, MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_CACHE_MTRR_VALID); return; } /** Calculate max memory of power 2 @param[in] MemoryLength - Memory length that will be calculated @retval Max memory **/ UINT64 PeiPower2MaxMemory ( IN UINT64 MemoryLength ) { UINT64 Result; UINT32 *ResultPointer; UINT32 *MemoryLengthPointer; MemoryLengthPointer = (UINT32 *) &MemoryLength; ResultPointer = (UINT32 *) &Result; Result = 0; if (MemoryLengthPointer[1] != 0) { ResultPointer[1] = GetPowerOfTwo32 (MemoryLengthPointer[1]); } else { ResultPointer[0] = GetPowerOfTwo32 (MemoryLengthPointer[0]); } return Result; } /** Program the unaligned MTRR register. @param[in] This - Pointer to PEI_CACHE_PPI @param[in] AlignedQword - The aligned 64-bit cache type. @param[in] MsrNum - The index of current MTRR. @param[in] UnalignedBase - Base Address of the current unaligned MTRR. @param[in] UnalignedLimit - Limit Address of the current unaligned MTRR. @retval EFI_SUCCESS - The unaligned MTRR is set successfully. @retval EFI_DEVICE_ERROR - The unaligned address is not the multiple of the basic length of MTRR. **/ EFI_STATUS PeiProgramUnalignedMtrr ( IN PEI_CACHE_PPI *This, IN UINT64 AlignedQword, IN UINTN MsrNum, IN UINT32 UnalignedBase, IN UINT32 UnalignedLimit ) { UINT32 UnalignedOffset; UINT64 TempQword; UINT64 Mask; UINT8 ByteShift; UnalignedOffset = UnalignedBase - mFixedMtrrTable[MsrNum].BaseAddress; if (UnalignedOffset % mFixedMtrrTable[MsrNum].Length != 0) { return EFI_DEVICE_ERROR; } ByteShift = (UINT8) (UnalignedOffset / mFixedMtrrTable[MsrNum].Length); Mask = ~(LShiftU64 (1, ByteShift * 8) - 1); if (UnalignedLimit < mFixedMtrrTable[MsrNum + 1].BaseAddress) { UnalignedOffset = UnalignedLimit - mFixedMtrrTable[MsrNum].BaseAddress; if (UnalignedOffset % mFixedMtrrTable[MsrNum].Length != 0) { return EFI_DEVICE_ERROR; } ByteShift = (UINT8) (UnalignedOffset / mFixedMtrrTable[MsrNum].Length); Mask &= LShiftU64 (1, ByteShift * 8) - 1; } TempQword = ReadMsrFromBuffer (This, MsrNum) &~Mask; TempQword |= AlignedQword & Mask; WriteMsrToBuffer (This, MsrNum, TempQword); return EFI_SUCCESS; } /** Given the low memory range ( <= 1MB) and cache type, program the MTRRs. @param[in] This - Current instance of Pei Cache PPI. @param[in] MemoryCacheType - Cache Type. @param[in] MemoryBase - Base Address of Memory to program MTRR. @param[in] MemoryLimit - Limit Address of Memory to program MTRR. @retval EFI_SUCCESS - Low memory MTRR is set successfully. @retval others - An error occurs when setting Low memory MTRR. **/ EFI_STATUS PeiProgramLowMemoryMtrr ( IN PEI_CACHE_PPI *This, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, IN UINT32 MemoryBase, IN UINT32 MemoryLimit ) { EFI_STATUS Status; ALIGNED Aligned; UINTN MsrNum; Status = EFI_SUCCESS; Aligned.AlignedDword.High = MemoryCacheType * ALIGNED_SEED; Aligned.AlignedDword.Low = Aligned.AlignedDword.High; for (MsrNum = 0; mFixedMtrrTable[MsrNum].BaseAddress < MemoryBase; MsrNum++) { ; } if (MemoryBase < mFixedMtrrTable[MsrNum].BaseAddress) { Status = PeiProgramUnalignedMtrr (This, Aligned.AlignedQword, MsrNum - 1, MemoryBase, MemoryLimit); if (EFI_ERROR (Status)) { goto Done; } } while (MsrNum < V_FIXED_MTRR_NUMBER && MemoryLimit >= mFixedMtrrTable[MsrNum + 1].BaseAddress) { /// /// Program aligned MTRR /// WriteMsrToBuffer (This, MsrNum, Aligned.AlignedQword); MsrNum++; } if (MemoryLimit > mFixedMtrrTable[MsrNum].BaseAddress) { Status = PeiProgramUnalignedMtrr ( This, Aligned.AlignedQword, MsrNum, mFixedMtrrTable[MsrNum].BaseAddress, MemoryLimit ); } Done: return Status; } /** Given the memory range and cache type, programs the MTRRs. @param[in] PeiServices - General purpose services available to every PEIM. @param[in] This - Current instance of Pei Cache PPI. @param[in] MemoryAddress - Base Address of Memory to program MTRR. @param[in] MemoryLength - Length of Memory to program MTRR. @param[in] MemoryCacheType - Cache Type. @retval EFI_SUCCESS - Mtrr are set successfully. @retval EFI_LOAD_ERROR - No empty MTRRs to use. @retval EFI_INVALID_PARAMETER - The input parameter is not valid. @retval others - An error occurs when setting MTTR. **/ EFI_STATUS EFIAPI PeiSetCacheAttributes ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType ) { EFI_STATUS Status; UINT32 MsrNum; UINT64 TempQword; UINT32 UsedMsrNum; EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType; UINT64 ValidMtrrAddressMask; EFI_CPUID_REGISTER FeatureInfo; UINT64 Power2Length[8]; UINT64 LengthArray[8]; UINTN LengthSize; UINTN Index; UINTN Count; UINT32 Remainder; UINT32 VariableMtrrLimit; UINT32 *TempQwordPointer; UINT32 *Power2LengthPointer; TempQwordPointer = (UINT32 *) &TempQword; VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); if (VariableMtrrLimit > V_MAXIMUM_VARIABLE_MTRR_NUMBER) { VariableMtrrLimit = V_MAXIMUM_VARIABLE_MTRR_NUMBER; } ValidMtrrAddressMask = 0x1000000000ULL; AsmCpuid ( CPUID_EXTENDED_FUNCTION, &FeatureInfo.RegEax, &FeatureInfo.RegEbx, &FeatureInfo.RegEcx, &FeatureInfo.RegEdx ); if (FeatureInfo.RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) { AsmCpuid ( CPUID_VIR_PHY_ADDRESS_SIZE, &FeatureInfo.RegEax, &FeatureInfo.RegEbx, &FeatureInfo.RegEcx, &FeatureInfo.RegEdx ); ValidMtrrAddressMask = (LShiftU64 ((UINT64) 1, FeatureInfo.RegEax & 0xFF) - 1) & (~(UINT64) 0x0FFF); } /// /// Check for invalid parameter /// if ((MemoryAddress &~ValidMtrrAddressMask) != 0 || (MemoryLength &~ValidMtrrAddressMask) != 0) { return EFI_INVALID_PARAMETER; } switch (MemoryCacheType) { case EfiCacheTypeUncacheable: case EfiCacheTypeWriteCombining: case EfiCacheTypeWriteThrough: case EfiCacheTypeWriteProtected: case EfiCacheTypeWriteBack: break; default: return EFI_INVALID_PARAMETER; } /// /// Check if Fixed MTRR /// if ((MemoryAddress + MemoryLength) <= (1 << 20)) { Status = PeiProgramLowMemoryMtrr ( This, MemoryCacheType, (UINT32) MemoryAddress, (UINT32) (MemoryAddress + MemoryLength) ); return Status; } /// /// Special case for 1 MB base address /// if (MemoryAddress == 0x100000) { MemoryAddress = 0; MemoryLength += 0x100000; } /// /// Split MemoryLength into a sum of power of 2 /// ZeroMem (Power2Length, sizeof (Power2Length)); LengthSize = 0; TempQword = MemoryLength; do { Power2Length[LengthSize] = PeiPower2MaxMemory (TempQword); TempQword -= Power2Length[LengthSize]; LengthSize++; } while (TempQword != 0 && LengthSize < 8); if (TempQword != 0) { return EFI_LOAD_ERROR; } /// /// Work out an order of splitted power of 2 /// so that Base and Length are suitable for MTRR /// setting constraints. /// Count = 0; TempQword = MemoryAddress; do { for (Index = 0; Index < LengthSize; Index++) { Power2LengthPointer = (UINT32 *) &Power2Length[Index]; if (Power2Length[Index] != 0) { if (Power2LengthPointer[1] != 0) { Remainder = (UINT32) TempQword; if (Remainder == 0) { DivU64x32Remainder ( TempQwordPointer[1], Power2LengthPointer[1], &Remainder ); } } else { DivU64x32Remainder (TempQword, (UINT32) Power2Length[Index], &Remainder); } if (Remainder == 0) { LengthArray[Count] = Power2Length[Index]; TempQword += Power2Length[Index]; Power2Length[Index] = 0; Count++; break; } } } if (Index == LengthSize) { return EFI_LOAD_ERROR; } } while (Count < LengthSize); /// /// Begin setting the MTRR according to the order /// for (Index = 0; Index < LengthSize; Index++, MemoryAddress += MemoryLength) { MemoryLength = LengthArray[Index]; /// /// Search if the range attribute has been set before /// Status = SearchForExactMtrr ( PeiServices, This, MemoryAddress, MemoryLength, ValidMtrrAddressMask, &UsedMsrNum, &UsedMemoryCacheType ); if (!EFI_ERROR (Status)) { /// /// Compare if it has the same type as current setting /// if (UsedMemoryCacheType != MemoryCacheType) { /// /// Different type /// /// /// Check if the set type is the same as default type /// if (IsDefaultType (MemoryCacheType)) { /// /// Clear the mtrr /// WriteMsrToBuffer (This, UsedMsrNum, 0); WriteMsrToBuffer (This, UsedMsrNum + 1, 0); } else { /// /// Modify the mtrr type /// EfiProgramMtrr ( This, UsedMsrNum, MemoryAddress, MemoryLength, MemoryCacheType, ValidMtrrAddressMask ); } } continue; } /// /// Find first unused MTRR /// for (MsrNum = CACHE_VARIABLE_MTRR_BASE; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2); MsrNum += 2) { if (ReadMsrFromBuffer (This, MsrNum + 1) == 0) { break; } } /// /// Check if we ran out of variable-range MTRRs /// if (MsrNum >= (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2)) { return EFI_LOAD_ERROR; } EfiProgramMtrr ( This, MsrNum, MemoryAddress, MemoryLength, MemoryCacheType, ValidMtrrAddressMask ); } return EFI_SUCCESS; } /** Update MTRR setting from buffer to MSR. Disable NEM when NEM is not disabled yet. @param[in] PeiServices - General purpose services available to every PEIM. @param[in] This - Current instance of Pei Cache PPI. @retval EFI_SUCCESS - Mtrr are set successfully. **/ EFI_STATUS EFIAPI PeiActivateCache ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This ) { UINT32 VariableMtrrLimit; UINT32 MsrNum; UINT64 OldMtrr; UINT16 Index; CACHE_PPI_INSTANCE *CachePpiInstance; CachePpiInstance = PEI_CACHE_PPI_INSTANCE_FROM_THIS (This); VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); if (VariableMtrrLimit > V_MAXIMUM_VARIABLE_MTRR_NUMBER) { VariableMtrrLimit = V_MAXIMUM_VARIABLE_MTRR_NUMBER; } /// /// Disable NEM when NEM is not disabled yet /// if (!CachePpiInstance->NemDisabledDone) { DisableCacheAsRam (); CachePpiInstance->NemDisabledDone = TRUE; } /// /// Disable/Enable cache only when MTRR configuration is changed in MTRR buffer /// if (CachePpiInstance->FixedMtrrChanged || CachePpiInstance->VariableMtrrChanged) { EfiDisableCacheMtrr (&OldMtrr); if (CachePpiInstance->FixedMtrrChanged) { for (Index = 0; Index < V_FIXED_MTRR_NUMBER; Index++) { if (CachePpiInstance->FixedMtrrValue[Index].Changed) { AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, CachePpiInstance->FixedMtrrValue[Index].MsrValue); CachePpiInstance->FixedMtrrValue[Index].Changed = FALSE; } } CachePpiInstance->FixedMtrrChanged = FALSE; } if (CachePpiInstance->VariableMtrrChanged) { for (MsrNum = CACHE_VARIABLE_MTRR_BASE; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2); MsrNum++) { if (CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].Changed) { AsmWriteMsr64 (MsrNum, CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].MsrValue); CachePpiInstance->VariableMtrrValue[MsrNum - CACHE_VARIABLE_MTRR_BASE].Changed = FALSE; } CachePpiInstance->VariableMtrrChanged = FALSE; } } EfiRecoverCacheMtrr (TRUE, OldMtrr); } return EFI_SUCCESS; } /** Reset all the MTRRs to a known state. @param[in] PeiServices - General purpose services available to every PEIM. @param[in] This - Pointer to the instance of the PEI_CACHE_PPI. @retval EFI_SUCCESS - All MTRRs have been reset successfully. **/ EFI_STATUS EFIAPI PeiResetCacheAttributes ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This ) { UINT32 MsrNum; UINT16 Index; UINT32 VariableMtrrLimit; VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); if (VariableMtrrLimit > V_MAXIMUM_VARIABLE_MTRR_NUMBER) { VariableMtrrLimit = V_MAXIMUM_VARIABLE_MTRR_NUMBER; } Index = 0; /// /// Reset Fixed Mtrrs /// while (mFixedMtrrTable[Index].Msr != 0) { WriteMsrToBuffer (This, Index, 0); Index++; } /// /// Reset Variable Mtrrs /// for (MsrNum = CACHE_VARIABLE_MTRR_BASE; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2); MsrNum++) { WriteMsrToBuffer (This, MsrNum, 0); } return EFI_SUCCESS; } /** Search the memory cache type for specific memory from MTRR. @param[in] PeiServices - General purpose services available to every PEIM. @param[in] This - Current instance of Pei Cache PPI. @param[in] MemoryAddress - the address of target memory @param[in] MemoryLength - the length of target memory @param[in] ValidMtrrAddressMask - the MTRR address mask @param[in] UsedMsrNum - the used MSR number @param[in] UsedMemoryCacheType - the cache type for the target memory @retval EFI_SUCCESS - The memory is found in MTRR and cache type is returned @retval EFI_NOT_FOUND - The memory is not found in MTRR **/ EFI_STATUS SearchForExactMtrr ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_CACHE_PPI *This, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN UINT64 ValidMtrrAddressMask, OUT UINT32 *UsedMsrNum, OUT EFI_MEMORY_CACHE_TYPE *UsedMemoryCacheType ) { UINT32 MsrNum; UINT64 TempQword; UINT32 VariableMtrrLimit; VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); if (VariableMtrrLimit > V_MAXIMUM_VARIABLE_MTRR_NUMBER) { VariableMtrrLimit = V_MAXIMUM_VARIABLE_MTRR_NUMBER; } for (MsrNum = CACHE_VARIABLE_MTRR_BASE; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2 - 1); MsrNum += 2) { TempQword = ReadMsrFromBuffer (This, MsrNum + 1); if ((TempQword & B_CACHE_MTRR_VALID) == 0) { continue; } if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) { continue; } TempQword = ReadMsrFromBuffer (This, MsrNum); if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) { continue; } *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE) (TempQword & 0xFF); *UsedMsrNum = MsrNum; return EFI_SUCCESS; } return EFI_NOT_FOUND; } /** Compares provided Cache type to default type @param[in] MemoryCacheType - Memory type for testing @retval TRUE - Memory type instance is the default type @retval FALSE - Memory type instance is not the default type **/ BOOLEAN IsDefaultType ( IN EFI_MEMORY_CACHE_TYPE MemoryCacheType ) { if ((AsmReadMsr64 (CACHE_IA32_MTRR_DEF_TYPE) & 0xFF) != MemoryCacheType) { return FALSE; } else { return TRUE; } } /** Install CacheInitPpi @retval EFI_OUT_OF_RESOURCES - failed to allocate required pool **/ EFI_STATUS CacheInitPpiInit ( VOID ) { EFI_STATUS Status; CACHE_PPI_INSTANCE *CachePpiInstance; CachePpiInstance = AllocateZeroPool (sizeof (CACHE_PPI_INSTANCE)); ASSERT (CachePpiInstance != NULL); if (CachePpiInstance == NULL) { return EFI_OUT_OF_RESOURCES; } CachePpiInstance->Ppi.SetCache = PeiSetCacheAttributes; CachePpiInstance->Ppi.ResetCache = PeiResetCacheAttributes; CachePpiInstance->Ppi.ActivateCache = PeiActivateCache; CachePpiInstance->PpiDesc.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; CachePpiInstance->PpiDesc.Guid = &gPeiCachePpiGuid; CachePpiInstance->PpiDesc.Ppi = &CachePpiInstance->Ppi; /// /// Install PPI /// Status = PeiServicesInstallPpi (&CachePpiInstance->PpiDesc); ASSERT_EFI_ERROR (Status); return Status; } VOID CacheInvd ( VOID ); /** Disable NEM (cache-as-ram) @retval EFI_SUCCESS - always return success **/ EFI_STATUS DisableCacheAsRam ( VOID ) { UINT64 CacheAsRamMsr; UINT64 McStatus; UINT32 McIndex; UINT32 McCounter; UINT64 TempQword; UINT64 OldMtrr; CacheAsRamMsr = AsmReadMsr64 (NO_EVICT_MODE); /// /// Check if CAR has already been disabled. We should not /// execute CacheInvd() after cache has been enabled. This /// check will avoid that. /// if ((CacheAsRamMsr & B_NO_EVICT_MODE_RUN) == 0) { return EFI_SUCCESS; } CacheInvd (); /// /// Step 3: Disable No-Eviction Mode Run State by clearing /// NO_EVICT_MODE MSR 2E0h bit [1] = 0 /// CacheAsRamMsr &= ~B_NO_EVICT_MODE_RUN; AsmWriteMsr64 (NO_EVICT_MODE, CacheAsRamMsr); /// /// Step 4: Disable No-Eviction Mode Setup State by clearing /// NO_EVICT_MODE MSR 2E0h bit [0] = 0 /// CacheAsRamMsr &= ~B_NO_EVICT_MODE_SETUP; AsmWriteMsr64 (NO_EVICT_MODE, CacheAsRamMsr); /// /// Disable Cache MTRR by cleaning IA32_MTRR_DEF_TYPE.E or IA32_MTRR_DEF_TYPE.GE /// OldMtrr = AsmReadMsr64 (CACHE_IA32_MTRR_DEF_TYPE); TempQword = OldMtrr &~B_CACHE_MTRR_VALID; AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, TempQword); /// /// After NEM is disabled, BIOS must clear any Machine Check Bank 5-8 errors that may /// have occurred as the result of ... MLC to to LLC Evictions. /// McStatus = 0; McCounter = (UINT32) (AsmReadMsr64 (IA32_MCG_CAP) & 0x0f); for (McIndex = 5; McIndex < McCounter; McIndex++) { if (McIndex <= 8) { AsmWriteMsr64 (IA32_MC0_STATUS + McIndex * 4, McStatus); } } return EFI_SUCCESS; }