diff options
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c')
-rw-r--r-- | ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c b/ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c new file mode 100644 index 0000000..959c58e --- /dev/null +++ b/ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c @@ -0,0 +1,1045 @@ +/** @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; +} |