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