1051 lines
28 KiB
C
1051 lines
28 KiB
C
/** @file
|
|
Function definitions for Cache and MTRR operations.
|
|
|
|
@copyright
|
|
Copyright (c) 1999 - 2015 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 the
|
|
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 Peripheral Driver' and is uniquely
|
|
identified as "Intel Reference 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.
|
|
|
|
@par Specification
|
|
**/
|
|
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PeiServicesLib.h>
|
|
|
|
#include <Register/Msr.h>
|
|
#include "CpuAccess.h"
|
|
#include "CacheInitPei.h"
|
|
#include <Ppi/Cache.h>
|
|
#include <Register/Cpuid.h>
|
|
|
|
#define ALIGNED_SEED 0x01010101
|
|
|
|
// @todo Remove these MSR defines and use UefiCpuPkg names instead
|
|
#define IA32_MTRR_CAP 0x000000FE
|
|
#define B_IA32_MTRR_VARIABLE_SUPPORT 0xFF
|
|
#define CACHE_VARIABLE_MTRR_BASE 0x00000200
|
|
#define IA32_MTRR_FIX64K_00000 0x00000250
|
|
#define IA32_MTRR_FIX16K_80000 0x00000258
|
|
#define IA32_MTRR_FIX16K_A0000 0x00000259
|
|
#define IA32_MTRR_FIX4K_C0000 0x00000268
|
|
#define IA32_MTRR_FIX4K_C8000 0x00000269
|
|
#define IA32_MTRR_FIX4K_D0000 0x0000026A
|
|
#define IA32_MTRR_FIX4K_D8000 0x0000026B
|
|
#define IA32_MTRR_FIX4K_E0000 0x0000026C
|
|
#define IA32_MTRR_FIX4K_E8000 0x0000026D
|
|
#define IA32_MTRR_FIX4K_F0000 0x0000026E
|
|
#define IA32_MTRR_FIX4K_F8000 0x0000026F
|
|
#define IA32_MCG_CAP 0x00000179
|
|
#define IA32_MC0_STATUS 0x00000401
|
|
|
|
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 PEI_CACHE_PPI *This
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeiActivateCache (
|
|
IN PEI_CACHE_PPI *This
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeiSetCacheAttributes (
|
|
IN PEI_CACHE_PPI *This,
|
|
IN EFI_PHYSICAL_ADDRESS MemoryAddress,
|
|
IN UINT64 MemoryLength,
|
|
IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
|
|
);
|
|
|
|
EFI_STATUS
|
|
SearchForExactMtrr (
|
|
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;
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED 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
|
|
}
|
|
};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED 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;
|
|
|
|
AsmDisableCache ();
|
|
|
|
///
|
|
/// Disable Cache MTRR
|
|
///
|
|
*OldMtrr = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
|
|
TempQword = (*OldMtrr) &~B_CACHE_MTRR_VALID &~B_CACHE_FIXED_MTRR_VALID;
|
|
AsmWriteMsr64 (MSR_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 (MSR_IA32_MTRR_DEF_TYPE);
|
|
TempQword |= (UINT64) (B_CACHE_MTRR_VALID | B_CACHE_FIXED_MTRR_VALID);
|
|
} else {
|
|
TempQword = OldMtrr;
|
|
}
|
|
|
|
AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, TempQword);
|
|
|
|
AsmEnableCache ();
|
|
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] 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 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;
|
|
UINT32 Eax;
|
|
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,
|
|
&Eax,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (Eax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
|
|
AsmCpuid (
|
|
CPUID_VIR_PHY_ADDRESS_SIZE,
|
|
&Eax,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ValidMtrrAddressMask = (LShiftU64 ((UINT64) 1, Eax & 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 (
|
|
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] This - Current instance of Pei Cache PPI.
|
|
|
|
@retval EFI_SUCCESS - Mtrr are set successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeiActivateCache (
|
|
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] This - Pointer to the instance of the PEI_CACHE_PPI.
|
|
|
|
@retval EFI_SUCCESS - All MTRRs have been reset successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeiResetCacheAttributes (
|
|
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] 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 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 (MSR_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;
|
|
}
|
|
|
|
/**
|
|
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) {
|
|
AsmInvd ();
|
|
|
|
///
|
|
/// Step 3: Disable No-Eviction Mode Run State by clearing
|
|
/// NO_EVICT_MODE MSR 2E0h bit [1] = 0
|
|
///
|
|
CacheAsRamMsr &= (UINT64) ~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 &= (UINT64) ~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 (MSR_IA32_MTRR_DEF_TYPE);
|
|
TempQword = OldMtrr &~B_CACHE_MTRR_VALID;
|
|
AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, TempQword);
|
|
}
|
|
|
|
///
|
|
/// After NEM is disabled, BIOS must clear any Machine Check Bank 6-9 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 = 6; McIndex < McCounter; McIndex++) {
|
|
if (McIndex <= 9) {
|
|
AsmWriteMsr64 (IA32_MC0_STATUS + McIndex * 4, McStatus);
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|