/** @file | |
CPU DXE Module. | |
Copyright (c) 2008 - 2009, Intel Corporation | |
All rights reserved. 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 "CpuDxe.h" | |
// | |
// Global Variables | |
// | |
IA32_IDT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 }; | |
EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100]; | |
BOOLEAN InterruptState = FALSE; | |
EFI_HANDLE mCpuHandle = NULL; | |
BOOLEAN mIsFlushingGCD; | |
UINT8 mDefaultMemoryType = MTRR_CACHE_WRITE_BACK; | |
UINT64 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; | |
UINT64 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK; | |
FIXED_MTRR mFixedMtrrTable[] = { | |
{ | |
MTRR_LIB_IA32_MTRR_FIX64K_00000, | |
0, | |
0x10000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX16K_80000, | |
0x80000, | |
0x4000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX16K_A0000, | |
0xA0000, | |
0x4000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_C0000, | |
0xC0000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_C8000, | |
0xC8000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_D0000, | |
0xD0000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_D8000, | |
0xD8000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_E0000, | |
0xE0000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_E8000, | |
0xE8000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_F0000, | |
0xF0000, | |
0x1000 | |
}, | |
{ | |
MTRR_LIB_IA32_MTRR_FIX4K_F8000, | |
0xF8000, | |
0x1000 | |
}, | |
}; | |
EFI_CPU_ARCH_PROTOCOL gCpu = { | |
CpuFlushCpuDataCache, | |
CpuEnableInterrupt, | |
CpuDisableInterrupt, | |
CpuGetInterruptState, | |
CpuInit, | |
CpuRegisterInterruptHandler, | |
CpuGetTimerValue, | |
CpuSetMemoryAttributes, | |
1, // NumberOfTimers | |
4 // DmaBufferAlignment | |
}; | |
// | |
// Error code flag indicating whether or not an error code will be | |
// pushed on the stack if an exception occurs. | |
// | |
// 1 means an error code will be pushed, otherwise 0 | |
// | |
// bit 0 - exception 0 | |
// bit 1 - exception 1 | |
// etc. | |
// | |
UINT32 mErrorCodeFlag = 0x00027d00; | |
// | |
// CPU Arch Protocol Functions | |
// | |
/** | |
Common exception handler. | |
@param InterruptType Exception type | |
@param SystemContext EFI_SYSTEM_CONTEXT | |
**/ | |
VOID | |
EFIAPI | |
CommonExceptionHandler ( | |
IN EFI_EXCEPTION_TYPE InterruptType, | |
IN EFI_SYSTEM_CONTEXT SystemContext | |
) | |
{ | |
#if defined (MDE_CPU_IA32) | |
DEBUG (( | |
EFI_D_ERROR, | |
"!!!! IA32 Exception Type - %08x !!!!\n", | |
InterruptType | |
)); | |
if (mErrorCodeFlag & (1 << InterruptType)) { | |
DEBUG (( | |
EFI_D_ERROR, | |
"ExceptionData - %08x\n", | |
SystemContext.SystemContextIa32->ExceptionData | |
)); | |
} | |
DEBUG (( | |
EFI_D_ERROR, | |
"CS - %04x, EIP - %08x, EFL - %08x, SS - %04x\n", | |
SystemContext.SystemContextIa32->Cs, | |
SystemContext.SystemContextIa32->Eip, | |
SystemContext.SystemContextIa32->Eflags, | |
SystemContext.SystemContextIa32->Ss | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"DS - %04x, ES - %04x, FS - %04x, GS - %04x\n", | |
SystemContext.SystemContextIa32->Ds, | |
SystemContext.SystemContextIa32->Es, | |
SystemContext.SystemContextIa32->Fs, | |
SystemContext.SystemContextIa32->Gs | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"EAX - %08x, EBX - %08x, ECX - %08x, EDX - %08x\n", | |
SystemContext.SystemContextIa32->Eax, | |
SystemContext.SystemContextIa32->Ebx, | |
SystemContext.SystemContextIa32->Ecx, | |
SystemContext.SystemContextIa32->Edx | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n", | |
SystemContext.SystemContextIa32->Esp, | |
SystemContext.SystemContextIa32->Ebp, | |
SystemContext.SystemContextIa32->Esi, | |
SystemContext.SystemContextIa32->Edi | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"GDT - %08x LIM - %04x, IDT - %08x LIM - %04x\n", | |
SystemContext.SystemContextIa32->Gdtr[0], | |
SystemContext.SystemContextIa32->Gdtr[1], | |
SystemContext.SystemContextIa32->Idtr[0], | |
SystemContext.SystemContextIa32->Idtr[1] | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"LDT - %08x, TR - %08x\n", | |
SystemContext.SystemContextIa32->Ldtr, | |
SystemContext.SystemContextIa32->Tr | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n", | |
SystemContext.SystemContextIa32->Cr0, | |
SystemContext.SystemContextIa32->Cr2, | |
SystemContext.SystemContextIa32->Cr3, | |
SystemContext.SystemContextIa32->Cr4 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n", | |
SystemContext.SystemContextIa32->Dr0, | |
SystemContext.SystemContextIa32->Dr1, | |
SystemContext.SystemContextIa32->Dr2, | |
SystemContext.SystemContextIa32->Dr3 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"DR6 - %08x, DR7 - %08x\n", | |
SystemContext.SystemContextIa32->Dr6, | |
SystemContext.SystemContextIa32->Dr7 | |
)); | |
#elif defined (MDE_CPU_X64) | |
DEBUG (( | |
EFI_D_ERROR, | |
"!!!! X64 Exception Type - %016lx !!!!\n", | |
(UINT64)InterruptType | |
)); | |
if (mErrorCodeFlag & (1 << InterruptType)) { | |
DEBUG (( | |
EFI_D_ERROR, | |
"ExceptionData - %016lx\n", | |
SystemContext.SystemContextX64->ExceptionData | |
)); | |
} | |
DEBUG (( | |
EFI_D_ERROR, | |
"RIP - %016lx, RFL - %016lx\n", | |
SystemContext.SystemContextX64->Rip, | |
SystemContext.SystemContextX64->Rflags | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"RAX - %016lx, RCX - %016lx, RDX - %016lx\n", | |
SystemContext.SystemContextX64->Rax, | |
SystemContext.SystemContextX64->Rcx, | |
SystemContext.SystemContextX64->Rdx | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"RBX - %016lx, RSP - %016lx, RBP - %016lx\n", | |
SystemContext.SystemContextX64->Rbx, | |
SystemContext.SystemContextX64->Rsp, | |
SystemContext.SystemContextX64->Rbp | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"RSI - %016lx, RDI - %016lx\n", | |
SystemContext.SystemContextX64->Rsi, | |
SystemContext.SystemContextX64->Rdi | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"R8 - %016lx, R9 - %016lx, R10 - %016lx\n", | |
SystemContext.SystemContextX64->R8, | |
SystemContext.SystemContextX64->R9, | |
SystemContext.SystemContextX64->R10 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"R11 - %016lx, R12 - %016lx, R13 - %016lx\n", | |
SystemContext.SystemContextX64->R11, | |
SystemContext.SystemContextX64->R12, | |
SystemContext.SystemContextX64->R13 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"R14 - %016lx, R15 - %016lx\n", | |
SystemContext.SystemContextX64->R14, | |
SystemContext.SystemContextX64->R15 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"CS - %04lx, DS - %04lx, ES - %04lx, FS - %04lx, GS - %04lx, SS - %04lx\n", | |
SystemContext.SystemContextX64->Cs, | |
SystemContext.SystemContextX64->Ds, | |
SystemContext.SystemContextX64->Es, | |
SystemContext.SystemContextX64->Fs, | |
SystemContext.SystemContextX64->Gs, | |
SystemContext.SystemContextX64->Ss | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"GDT - %016lx; %04lx, IDT - %016lx; %04lx\n", | |
SystemContext.SystemContextX64->Gdtr[0], | |
SystemContext.SystemContextX64->Gdtr[1], | |
SystemContext.SystemContextX64->Idtr[0], | |
SystemContext.SystemContextX64->Idtr[1] | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"LDT - %016lx, TR - %016lx\n", | |
SystemContext.SystemContextX64->Ldtr, | |
SystemContext.SystemContextX64->Tr | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n", | |
SystemContext.SystemContextX64->Cr0, | |
SystemContext.SystemContextX64->Cr2, | |
SystemContext.SystemContextX64->Cr3 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"CR4 - %016lx, CR8 - %016lx\n", | |
SystemContext.SystemContextX64->Cr4, | |
SystemContext.SystemContextX64->Cr8 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n", | |
SystemContext.SystemContextX64->Dr0, | |
SystemContext.SystemContextX64->Dr1, | |
SystemContext.SystemContextX64->Dr2 | |
)); | |
DEBUG (( | |
EFI_D_ERROR, | |
"DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n", | |
SystemContext.SystemContextX64->Dr3, | |
SystemContext.SystemContextX64->Dr6, | |
SystemContext.SystemContextX64->Dr7 | |
)); | |
#else | |
#error CPU type not supported for exception information dump! | |
#endif | |
// | |
// Hang the system with CpuSleep so the processor will enter a lower power | |
// state. | |
// | |
while (TRUE) { | |
CpuSleep (); | |
}; | |
} | |
/** | |
Flush CPU data cache. If the instruction cache is fully coherent | |
with all DMA operations then function can just return EFI_SUCCESS. | |
@param This Protocol instance structure | |
@param Start Physical address to start flushing from. | |
@param Length Number of bytes to flush. Round up to chipset | |
granularity. | |
@param FlushType Specifies the type of flush operation to perform. | |
@retval EFI_SUCCESS If cache was flushed | |
@retval EFI_UNSUPPORTED If flush type is not supported. | |
@retval EFI_DEVICE_ERROR If requested range could not be flushed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuFlushCpuDataCache ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
IN EFI_PHYSICAL_ADDRESS Start, | |
IN UINT64 Length, | |
IN EFI_CPU_FLUSH_TYPE FlushType | |
) | |
{ | |
if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { | |
AsmWbinvd (); | |
return EFI_SUCCESS; | |
} else if (FlushType == EfiCpuFlushTypeInvalidate) { | |
AsmInvd (); | |
return EFI_SUCCESS; | |
} else { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
/** | |
Enables CPU interrupts. | |
@param This Protocol instance structure | |
@retval EFI_SUCCESS If interrupts were enabled in the CPU | |
@retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuEnableInterrupt ( | |
IN EFI_CPU_ARCH_PROTOCOL *This | |
) | |
{ | |
EnableInterrupts (); | |
InterruptState = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
Disables CPU interrupts. | |
@param This Protocol instance structure | |
@retval EFI_SUCCESS If interrupts were disabled in the CPU. | |
@retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuDisableInterrupt ( | |
IN EFI_CPU_ARCH_PROTOCOL *This | |
) | |
{ | |
DisableInterrupts (); | |
InterruptState = FALSE; | |
return EFI_SUCCESS; | |
} | |
/** | |
Return the state of interrupts. | |
@param This Protocol instance structure | |
@param State Pointer to the CPU's current interrupt state | |
@retval EFI_SUCCESS If interrupts were disabled in the CPU. | |
@retval EFI_INVALID_PARAMETER State is NULL. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuGetInterruptState ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
OUT BOOLEAN *State | |
) | |
{ | |
if (State == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*State = InterruptState; | |
return EFI_SUCCESS; | |
} | |
/** | |
Generates an INIT to the CPU. | |
@param This Protocol instance structure | |
@param InitType Type of CPU INIT to perform | |
@retval EFI_SUCCESS If CPU INIT occurred. This value should never be | |
seen. | |
@retval EFI_DEVICE_ERROR If CPU INIT failed. | |
@retval EFI_UNSUPPORTED Requested type of CPU INIT not supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuInit ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
IN EFI_CPU_INIT_TYPE InitType | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Registers a function to be called from the CPU interrupt handler. | |
@param This Protocol instance structure | |
@param InterruptType Defines which interrupt to hook. IA-32 | |
valid range is 0x00 through 0xFF | |
@param InterruptHandler A pointer to a function of type | |
EFI_CPU_INTERRUPT_HANDLER that is called | |
when a processor interrupt occurs. A null | |
pointer is an error condition. | |
@retval EFI_SUCCESS If handler installed or uninstalled. | |
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler | |
for InterruptType was previously installed. | |
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for | |
InterruptType was not previously installed. | |
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType | |
is not supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuRegisterInterruptHandler ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
IN EFI_EXCEPTION_TYPE InterruptType, | |
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler | |
) | |
{ | |
if (InterruptType < 0 || InterruptType > 0xff) { | |
return EFI_UNSUPPORTED; | |
} | |
if (InterruptHandler == NULL && ExternalVectorTable[InterruptType] == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (InterruptHandler != NULL && ExternalVectorTable[InterruptType] != NULL) { | |
return EFI_ALREADY_STARTED; | |
} | |
ExternalVectorTable[InterruptType] = InterruptHandler; | |
return EFI_SUCCESS; | |
} | |
/** | |
Returns a timer value from one of the CPU's internal timers. There is no | |
inherent time interval between ticks but is a function of the CPU frequency. | |
@param This - Protocol instance structure. | |
@param TimerIndex - Specifies which CPU timer is requested. | |
@param TimerValue - Pointer to the returned timer value. | |
@param TimerPeriod - A pointer to the amount of time that passes | |
in femtoseconds (10-15) for each increment | |
of TimerValue. If TimerValue does not | |
increment at a predictable rate, then 0 is | |
returned. The amount of time that has | |
passed between two calls to GetTimerValue() | |
can be calculated with the formula | |
(TimerValue2 - TimerValue1) * TimerPeriod. | |
This parameter is optional and may be NULL. | |
@retval EFI_SUCCESS - If the CPU timer count was returned. | |
@retval EFI_UNSUPPORTED - If the CPU does not have any readable timers. | |
@retval EFI_DEVICE_ERROR - If an error occurred while reading the timer. | |
@retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuGetTimerValue ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
IN UINT32 TimerIndex, | |
OUT UINT64 *TimerValue, | |
OUT UINT64 *TimerPeriod OPTIONAL | |
) | |
{ | |
if (TimerValue == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (TimerIndex != 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*TimerValue = AsmReadTsc (); | |
if (TimerPeriod != NULL) { | |
// | |
// BugBug: Hard coded. Don't know how to do this generically | |
// | |
*TimerPeriod = 1000000000; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Set memory cacheability attributes for given range of memeory. | |
@param This Protocol instance structure | |
@param BaseAddress Specifies the start address of the | |
memory range | |
@param Length Specifies the length of the memory range | |
@param Attributes The memory cacheability for the memory range | |
@retval EFI_SUCCESS If the cacheability of that memory range is | |
set successfully | |
@retval EFI_UNSUPPORTED If the desired operation cannot be done | |
@retval EFI_INVALID_PARAMETER The input parameter is not correct, | |
such as Length = 0 | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CpuSetMemoryAttributes ( | |
IN EFI_CPU_ARCH_PROTOCOL *This, | |
IN EFI_PHYSICAL_ADDRESS BaseAddress, | |
IN UINT64 Length, | |
IN UINT64 Attributes | |
) | |
{ | |
RETURN_STATUS Status; | |
MTRR_MEMORY_CACHE_TYPE CacheType; | |
DEBUG((EFI_D_ERROR, "CpuAp: SetMemorySpaceAttributes(BA=%08x, Len=%08x, Attr=%08x)\n", BaseAddress, Length, Attributes)); | |
// | |
// If this function is called because GCD SetMemorySpaceAttributes () is called | |
// by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory | |
// map with MTRR values. So there is no need to modify MTRRs, just return immediately | |
// to avoid unnecessary computing. | |
// | |
if (mIsFlushingGCD) { | |
DEBUG((EFI_D_ERROR, " Flushing GCD\n")); | |
return EFI_SUCCESS; | |
} | |
switch (Attributes) { | |
case EFI_MEMORY_UC: | |
CacheType = CacheUncacheable; | |
break; | |
case EFI_MEMORY_WC: | |
CacheType = CacheWriteCombining; | |
break; | |
case EFI_MEMORY_WT: | |
CacheType = CacheWriteThrough; | |
break; | |
case EFI_MEMORY_WP: | |
CacheType = CacheWriteProtected; | |
break; | |
case EFI_MEMORY_WB: | |
CacheType = CacheWriteBack; | |
break; | |
default: | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// call MTRR libary function | |
// | |
DEBUG((EFI_D_ERROR, " MtrrSetMemoryAttribute()\n")); | |
Status = MtrrSetMemoryAttribute( | |
BaseAddress, | |
Length, | |
CacheType | |
); | |
MtrrDebugPrintAllMtrrs (); | |
return (EFI_STATUS) Status; | |
} | |
/** | |
Initializes the valid bits mask and valid address mask for MTRRs. | |
This function initializes the valid bits mask and valid address mask for MTRRs. | |
**/ | |
VOID | |
InitializeMtrrMask ( | |
VOID | |
) | |
{ | |
UINT32 RegEax; | |
UINT8 PhysicalAddressBits; | |
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); | |
if (RegEax >= 0x80000008) { | |
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); | |
PhysicalAddressBits = (UINT8) RegEax; | |
mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; | |
mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL; | |
} else { | |
mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK; | |
mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; | |
} | |
} | |
/** | |
Gets GCD Mem Space type from MTRR Type | |
This function gets GCD Mem Space type from MTRR Type | |
@param MtrrAttribute MTRR memory type | |
@return GCD Mem Space type | |
**/ | |
UINT64 | |
GetMemorySpaceAttributeFromMtrrType ( | |
IN UINT8 MtrrAttributes | |
) | |
{ | |
switch (MtrrAttributes) { | |
case MTRR_CACHE_UNCACHEABLE: | |
return EFI_MEMORY_UC; | |
case MTRR_CACHE_WRITE_COMBINING: | |
return EFI_MEMORY_WC; | |
case MTRR_CACHE_WRITE_THROUGH: | |
return EFI_MEMORY_WT; | |
case MTRR_CACHE_WRITE_PROTECTED: | |
return EFI_MEMORY_WP; | |
case MTRR_CACHE_WRITE_BACK: | |
return EFI_MEMORY_WB; | |
default: | |
return 0; | |
} | |
} | |
/** | |
Searches memory descriptors covered by given memory range. | |
This function searches into the Gcd Memory Space for descriptors | |
(from StartIndex to EndIndex) that contains the memory range | |
specified by BaseAddress and Length. | |
@param MemorySpaceMap Gcd Memory Space Map as array. | |
@param NumberOfDescriptors Number of descriptors in map. | |
@param BaseAddress BaseAddress for the requested range. | |
@param Length Length for the requested range. | |
@param StartIndex Start index into the Gcd Memory Space Map. | |
@param EndIndex End index into the Gcd Memory Space Map. | |
@retval EFI_SUCCESS Search successfully. | |
@retval EFI_NOT_FOUND The requested descriptors does not exist. | |
**/ | |
EFI_STATUS | |
SearchGcdMemorySpaces ( | |
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, | |
IN UINTN NumberOfDescriptors, | |
IN EFI_PHYSICAL_ADDRESS BaseAddress, | |
IN UINT64 Length, | |
OUT UINTN *StartIndex, | |
OUT UINTN *EndIndex | |
) | |
{ | |
UINTN Index; | |
*StartIndex = 0; | |
*EndIndex = 0; | |
for (Index = 0; Index < NumberOfDescriptors; Index++) { | |
if (BaseAddress >= MemorySpaceMap[Index].BaseAddress && | |
BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { | |
*StartIndex = Index; | |
} | |
if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress && | |
BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { | |
*EndIndex = Index; | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Sets the attributes for a specified range in Gcd Memory Space Map. | |
This function sets the attributes for a specified range in | |
Gcd Memory Space Map. | |
@param MemorySpaceMap Gcd Memory Space Map as array | |
@param NumberOfDescriptors Number of descriptors in map | |
@param BaseAddress BaseAddress for the range | |
@param Length Length for the range | |
@param Attributes Attributes to set | |
@retval EFI_SUCCESS Memory attributes set successfully | |
@retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space | |
**/ | |
EFI_STATUS | |
SetGcdMemorySpaceAttributes ( | |
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, | |
IN UINTN NumberOfDescriptors, | |
IN EFI_PHYSICAL_ADDRESS BaseAddress, | |
IN UINT64 Length, | |
IN UINT64 Attributes | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
UINTN StartIndex; | |
UINTN EndIndex; | |
EFI_PHYSICAL_ADDRESS RegionStart; | |
UINT64 RegionLength; | |
// | |
// Get all memory descriptors covered by the memory range | |
// | |
Status = SearchGcdMemorySpaces ( | |
MemorySpaceMap, | |
NumberOfDescriptors, | |
BaseAddress, | |
Length, | |
&StartIndex, | |
&EndIndex | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Go through all related descriptors and set attributes accordingly | |
// | |
for (Index = StartIndex; Index <= EndIndex; Index++) { | |
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) { | |
continue; | |
} | |
// | |
// Calculate the start and end address of the overlapping range | |
// | |
if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) { | |
RegionStart = BaseAddress; | |
} else { | |
RegionStart = MemorySpaceMap[Index].BaseAddress; | |
} | |
if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) { | |
RegionLength = BaseAddress + Length - RegionStart; | |
} else { | |
RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart; | |
} | |
// | |
// Set memory attributes according to MTRR attribute and the original attribute of descriptor | |
// | |
gDS->SetMemorySpaceAttributes ( | |
RegionStart, | |
RegionLength, | |
(MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes) | |
); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Refreshes the GCD Memory Space attributes according to MTRRs. | |
This function refreshes the GCD Memory Space attributes according to MTRRs. | |
**/ | |
VOID | |
RefreshGcdMemoryAttributes ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
UINTN SubIndex; | |
UINT64 RegValue; | |
EFI_PHYSICAL_ADDRESS BaseAddress; | |
UINT64 Length; | |
UINT64 Attributes; | |
UINT64 CurrentAttributes; | |
UINT8 MtrrType; | |
UINTN NumberOfDescriptors; | |
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; | |
UINT64 DefaultAttributes; | |
VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; | |
MTRR_FIXED_SETTINGS MtrrFixedSettings; | |
// mIsFlushingGCD = TRUE; | |
mIsFlushingGCD = FALSE; | |
MemorySpaceMap = NULL; | |
// | |
// Initialize the valid bits mask and valid address mask for MTRRs | |
// | |
InitializeMtrrMask (); | |
// | |
// Get the memory attribute of variable MTRRs | |
// | |
MtrrGetMemoryAttributeInVariableMtrr ( | |
mValidMtrrBitsMask, | |
mValidMtrrAddressMask, | |
VariableMtrr | |
); | |
// | |
// Get the memory space map from GCD | |
// | |
Status = gDS->GetMemorySpaceMap ( | |
&NumberOfDescriptors, | |
&MemorySpaceMap | |
); | |
ASSERT_EFI_ERROR (Status); | |
DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (mDefaultMemoryType); | |
// | |
// Set default attributes to all spaces. | |
// | |
for (Index = 0; Index < NumberOfDescriptors; Index++) { | |
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) { | |
continue; | |
} | |
gDS->SetMemorySpaceAttributes ( | |
MemorySpaceMap[Index].BaseAddress, | |
MemorySpaceMap[Index].Length, | |
(MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | | |
(MemorySpaceMap[Index].Capabilities & DefaultAttributes) | |
); | |
} | |
// | |
// Go for variable MTRRs with WB attribute | |
// | |
for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) { | |
if (VariableMtrr[Index].Valid && | |
VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) { | |
SetGcdMemorySpaceAttributes ( | |
MemorySpaceMap, | |
NumberOfDescriptors, | |
VariableMtrr[Index].BaseAddress, | |
VariableMtrr[Index].Length, | |
EFI_MEMORY_WB | |
); | |
} | |
} | |
// | |
// Go for variable MTRRs with Non-WB attribute | |
// | |
for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; Index++) { | |
if (VariableMtrr[Index].Valid && | |
VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) { | |
Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type); | |
SetGcdMemorySpaceAttributes ( | |
MemorySpaceMap, | |
NumberOfDescriptors, | |
VariableMtrr[Index].BaseAddress, | |
VariableMtrr[Index].Length, | |
Attributes | |
); | |
} | |
} | |
// | |
// Go for fixed MTRRs | |
// | |
Attributes = 0; | |
BaseAddress = 0; | |
Length = 0; | |
MtrrGetFixedMtrr (&MtrrFixedSettings); | |
for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { | |
RegValue = MtrrFixedSettings.Mtrr[Index]; | |
// | |
// Check for continuous fixed MTRR sections | |
// | |
for (SubIndex = 0; SubIndex < 8; SubIndex++) { | |
MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8); | |
CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType); | |
if (Length == 0) { | |
// | |
// A new MTRR attribute begins | |
// | |
Attributes = CurrentAttributes; | |
} else { | |
// | |
// If fixed MTRR attribute changed, then set memory attribute for previous atrribute | |
// | |
if (CurrentAttributes != Attributes) { | |
SetGcdMemorySpaceAttributes ( | |
MemorySpaceMap, | |
NumberOfDescriptors, | |
BaseAddress, | |
Length, | |
Attributes | |
); | |
BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex; | |
Length = 0; | |
Attributes = CurrentAttributes; | |
} | |
} | |
Length += mFixedMtrrTable[Index].Length; | |
} | |
} | |
// | |
// Handle the last fixed MTRR region | |
// | |
SetGcdMemorySpaceAttributes ( | |
MemorySpaceMap, | |
NumberOfDescriptors, | |
BaseAddress, | |
Length, | |
Attributes | |
); | |
// | |
// Free memory space map allocated by GCD service GetMemorySpaceMap () | |
// | |
if (MemorySpaceMap != NULL) { | |
FreePool (MemorySpaceMap); | |
} | |
mIsFlushingGCD = FALSE; | |
} | |
/** | |
Initialize Interrupt Descriptor Table for interrupt handling. | |
**/ | |
STATIC | |
VOID | |
InitInterruptDescriptorTable ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *IdtPtrAlignmentBuffer; | |
IA32_DESCRIPTOR *IdtPtr; | |
UINTN Index; | |
UINTN CurrentHandler; | |
SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0); | |
// | |
// Intialize IDT | |
// | |
CurrentHandler = (UINTN)AsmIdtVector00; | |
for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) { | |
gIdtTable[Index].Bits.OffsetLow = (UINT16)CurrentHandler; | |
gIdtTable[Index].Bits.Selector = AsmReadCs(); | |
gIdtTable[Index].Bits.Reserved_0 = 0; | |
gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; | |
gIdtTable[Index].Bits.OffsetHigh = (UINT16)(CurrentHandler >> 16); | |
#if defined (MDE_CPU_X64) | |
gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32); | |
gIdtTable[Index].Bits.Reserved_1 = 0; | |
#endif | |
} | |
// | |
// Load IDT Pointer | |
// | |
IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16); | |
IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16); | |
IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1)); | |
IdtPtr->Limit = sizeof (gIdtTable) - 1; | |
AsmWriteIdtr (IdtPtr); | |
FreePool (IdtPtrAlignmentBuffer); | |
// | |
// Initialize Exception Handlers | |
// | |
for (Index = 0; Index < 32; Index++) { | |
Status = CpuRegisterInterruptHandler (&gCpu, Index, CommonExceptionHandler); | |
ASSERT_EFI_ERROR (Status); | |
} | |
// | |
// Set the pointer to the array of C based exception handling routines. | |
// | |
InitializeExternalVectorTablePtr (ExternalVectorTable); | |
} | |
/** | |
Initialize the state information for the CPU Architectural Protocol. | |
@param ImageHandle Image handle this driver. | |
@param SystemTable Pointer to the System Table. | |
@retval EFI_SUCCESS Thread can be successfully created | |
@retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure | |
@retval EFI_DEVICE_ERROR Cannot create the thread | |
**/ | |
EFI_STATUS | |
EFIAPI | |
InitializeCpu ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Make sure interrupts are disabled | |
// | |
DisableInterrupts (); | |
// | |
// Init GDT for DXE | |
// | |
InitGlobalDescriptorTable (); | |
// | |
// Setup IDT pointer, IDT and interrupt entry points | |
// | |
InitInterruptDescriptorTable (); | |
// | |
// Install CPU Architectural Protocol | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&mCpuHandle, | |
&gEfiCpuArchProtocolGuid, &gCpu, | |
NULL | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Refresh GCD memory space map according to MTRR value. | |
// | |
RefreshGcdMemoryAttributes (); | |
return Status; | |
} | |