summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c')
-rw-r--r--ReferenceCode/Haswell/CpuInit/Pei/CachePeim.c1045
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;
+}