From: jljusten Date: Wed, 27 May 2009 21:09:47 +0000 (+0000) Subject: Add CPU DXE driver for IA32 & X64 processor architectures. X-Git-Tag: edk2-stable201903~17878 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=a47463f28382bffcedacde0d96965977261d114a Add CPU DXE driver for IA32 & X64 processor architectures. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8395 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c new file mode 100644 index 0000000000..25131febf2 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/CpuDxe.c @@ -0,0 +1,1108 @@ +/** @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; +} + diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h new file mode 100644 index 0000000000..fbf3a9830f --- /dev/null +++ b/UefiCpuPkg/CpuDxe/CpuDxe.h @@ -0,0 +1,140 @@ +/** @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. + +**/ + +#ifndef _CPU_DXE_H +#define _CPU_DXE_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// +// +#define INTERRUPT_VECTOR_NUMBER 256 + +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \ + EFI_MEMORY_WC | \ + EFI_MEMORY_WT | \ + EFI_MEMORY_WB | \ + EFI_MEMORY_UCE \ + ) + + +// +// Function declarations +// +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ); + +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ); + +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +VOID +EFIAPI +AsmIdtVector00 ( + VOID + ); + +VOID +EFIAPI +InitializeExternalVectorTablePtr ( + EFI_CPU_INTERRUPT_HANDLER *VectorTable + ); + +VOID +InitGlobalDescriptorTable ( + VOID + ); + +VOID +EFIAPI +SetCodeSelector ( + UINT16 Selector + ); + +VOID +EFIAPI +SetDataSelectors ( + UINT16 Selector + ); + + +#endif + diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf new file mode 100644 index 0000000000..ff832450dd --- /dev/null +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf @@ -0,0 +1,67 @@ +#/** @file +# +# Component description file for simple CPU driver +# +# 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuDxe + FILE_GUID = 62D171CB-78CD-4480-8678-C6A2A797A8DE + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x0002000A + + ENTRY_POINT = InitializeCpu + +[Packages] + OvmfPkg/OvmfPkg.dec + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + CpuLib + DebugLib + DxeServicesTableLib + MemoryAllocationLib + MtrrLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Sources] + CpuDxe.c + CpuDxe.h + CpuGdt.c + + Ia32/IvtAsm.asm | MSFT + Ia32/IvtAsm.asm | INTEL + Ia32/IvtAsm.S | GCC + +[Sources.IA32] + Ia32/CpuAsm.asm | MSFT + Ia32/CpuAsm.asm | INTEL + Ia32/CpuAsm.S | GCC + +[Sources.X64] + X64/CpuAsm.asm | MSFT + X64/CpuAsm.asm | INTEL + X64/CpuAsm.S | GCC + +[Protocols] + gEfiCpuArchProtocolGuid + +[Depex] + TRUE + diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.c b/UefiCpuPkg/CpuDxe/CpuGdt.c new file mode 100755 index 0000000000..b6d8ffb75d --- /dev/null +++ b/UefiCpuPkg/CpuDxe/CpuGdt.c @@ -0,0 +1,200 @@ +/** @file + C based implemention of IA32 interrupt handling only + requiring a minimal assembly interrupt entry point. + + Copyright (c) 2006 - 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" + + +// +// Local structure definitions +// + +#pragma pack (1) + +// +// Global Descriptor Entry structures +// + +typedef +struct _GDT_ENTRY { + UINT16 limit15_0; + UINT16 base15_0; + UINT8 base23_16; + UINT8 type; + UINT8 limit19_16_and_flags; + UINT8 base31_24; +} GDT_ENTRY; + +typedef +struct _GDT_ENTRIES { + GDT_ENTRY Null; + GDT_ENTRY Linear; + GDT_ENTRY LinearCode; + GDT_ENTRY SysData; + GDT_ENTRY SysCode; + GDT_ENTRY LinearCode64; + GDT_ENTRY Spare4; + GDT_ENTRY Spare5; +} GDT_ENTRIES; + +#define NULL_SEL OFFSET_OF (GDT_ENTRIES, Null) +#define LINEAR_SEL OFFSET_OF (GDT_ENTRIES, Linear) +#define LINEAR_CODE_SEL OFFSET_OF (GDT_ENTRIES, LinearCode) +#define SYS_DATA_SEL OFFSET_OF (GDT_ENTRIES, SysData) +#define SYS_CODE_SEL OFFSET_OF (GDT_ENTRIES, SysCode) +#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64) +#define SPARE4_SEL OFFSET_OF (GDT_ENTRIES, Spare4) +#define SPARE5_SEL OFFSET_OF (GDT_ENTRIES, Spare5) + +#if defined (MDE_CPU_IA32) +#define CPU_CODE_SEL LINEAR_CODE_SEL +#define CPU_DATA_SEL LINEAR_SEL +#elif defined (MDE_CPU_X64) +#define CPU_CODE_SEL LINEAR_CODE64_SEL +#define CPU_DATA_SEL LINEAR_SEL +#else +#error CPU type not supported for CPU GDT initialization! +#endif + +// +// Global descriptor table (GDT) Template +// +STATIC GDT_ENTRIES GdtTemplate = { + // + // NULL_SEL + // + { + 0x0, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x0, // type + 0x0, // limit 19:16, flags + 0x0, // base 31:24 + }, + // + // LINEAR_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x092, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // LINEAR_CODE_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09A, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // SYS_DATA_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x092, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // SYS_CODE_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09A, // present, ring 0, data, expand-up, writable + 0x0CF, // page-granular, 32-bit + 0x0, + }, + // + // LINEAR_CODE64_SEL + // + { + 0x0FFFF, // limit 0xFFFFF + 0x0, // base 0 + 0x0, + 0x09B, // present, ring 0, code, expand-up, writable + 0x0AF, // LimitHigh (CS.L=1, CS.D=0) + 0x0, // base (high) + }, + // + // SPARE4_SEL + // + { + 0x0, // limit 0 + 0x0, // base 0 + 0x0, + 0x0, // present, ring 0, data, expand-up, writable + 0x0, // page-granular, 32-bit + 0x0, + }, + // + // SPARE5_SEL + // + { + 0x0, // limit 0 + 0x0, // base 0 + 0x0, + 0x0, // present, ring 0, data, expand-up, writable + 0x0, // page-granular, 32-bit + 0x0, + }, +}; + +/** + Initialize Global Descriptor Table + +**/ +VOID +InitGlobalDescriptorTable ( + ) +{ + GDT_ENTRIES *gdt; + IA32_DESCRIPTOR gdtPtr; + + // + // Allocate Runtime Data for the GDT + // + gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); + ASSERT (gdt != NULL); + gdt = ALIGN_POINTER (gdt, 8); + + // + // Initialize all GDT entries + // + CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate)); + + // + // Write GDT register + // + gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt; + gdtPtr.Limit = sizeof (GdtTemplate) - 1; + AsmWriteGdtr (&gdtPtr); + + // + // Update selector (segment) registers base on new GDT + // + SetCodeSelector ((UINT16)CPU_CODE_SEL); + SetDataSelectors ((UINT16)CPU_DATA_SEL); +} + diff --git a/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S b/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S new file mode 100755 index 0000000000..69fe215637 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.S @@ -0,0 +1,395 @@ +# +# ConvertAsm.py: Automatically generated from CpuAsm.asm +# +# TITLE CpuAsm.asm: + +#------------------------------------------------------------------------------ +#* +#* Copyright 2006 - 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. +#* +#* CpuAsm.S +#* +#* Abstract: +#* +#------------------------------------------------------------------------------ + + +#.MMX +#.XMM + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + + +# +# point to the external interrupt vector table +# +ExternalVectorTablePtr: + .byte 0, 0, 0, 0 + +.intel_syntax +ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr) +ASM_PFX(InitializeExternalVectorTablePtr): + mov eax, [esp+4] + mov ExternalVectorTablePtr, eax + ret + +#------------------------------------------------------------------------------ +# VOID +# SetCodeSelector ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +.intel_syntax +ASM_GLOBAL ASM_PFX(SetCodeSelector) +ASM_PFX(SetCodeSelector): + mov %ecx, [%esp+4] + sub %esp, 0x10 + lea %eax, setCodeSelectorLongJump + mov [%esp], %eax + mov [%esp+4], %cx + jmp fword ptr [%esp] +setCodeSelectorLongJump: + add %esp, 0x10 + ret + +#------------------------------------------------------------------------------ +# VOID +# SetDataSelectors ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +.intel_syntax +ASM_GLOBAL ASM_PFX(SetDataSelectors) +ASM_PFX(SetDataSelectors): + mov %ecx, [%esp+4] + mov %ss, %cx + mov %ds, %cx + mov %es, %cx + mov %fs, %cx + mov %gs, %cx + ret + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +.intel_syntax +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + + # + # Calculate vector number + # + # Get the return address of call, actually, it is the + # address of vector number. + # + xchg ecx, [esp] + mov cx, [ecx] + and ecx, 0x0FFFF + cmp ecx, 32 # Intel reserved vector for exceptions? + jae NoErrorCode + bt ASM_PFX(mErrorCodeFlag), ecx + jc HasErrorCode + +NoErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack + # + push ecx + + # + # Put 0 (dummy) error code on stack, and restore ECX + # + xor ecx, ecx # ECX = 0 + xchg ecx, [esp+4] + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack and restore ECX + # + xchg ecx, [esp] + + # + # Fall through to join main routine code + # at ErrorCodeAndVectorOnStack + # +CommonInterruptEntry_al_0000: + jmp CommonInterruptEntry_al_0000 + +ErrorCodeAndVectorOnStack: + push ebp + mov ebp, esp + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + Vector Number + + # +---------------------+ + # + EBP + + # +---------------------+ <-- EBP + # + + # + # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + # is 16-byte aligned + # + and esp, 0x0fffffff0 + sub esp, 12 + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx # ESP + push dword ptr [ebp] # EBP + push esi + push edi + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +#; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +#; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0x0FFFF + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0x0FFFF + mov [esp+4], eax + +#; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +#; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 0x208 + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax +#; clear Dr7 while executing debugger itself + xor eax, eax + mov dr7, eax + + mov eax, dr6 + push eax +#; insure all status bits in dr6 are clear... + xor eax, eax + mov dr6, eax + + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +#; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + .byte 0x0f, 0x0ae, 0x07 #fxsave [edi] + +#; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +#; call into exception handler + mov eax, ExternalVectorTablePtr # get the interrupt vectors base + or eax, eax # NULL? + jz nullExternalExceptionHandler + + mov ecx, [ebp + 4] + mov eax, [eax + ecx * 4] + or eax, eax # NULL? + jz nullExternalExceptionHandler + +#; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + # + # Call External Exception Handler + # + call eax + add esp, 8 + +nullExternalExceptionHandler: + + cli +#; UINT32 ExceptionData; + add esp, 4 + +#; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] + add esp, 512 + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop eax + mov dr0, eax + pop eax + mov dr1, eax + pop eax + mov dr2, eax + pop eax + mov dr3, eax +#; skip restore of dr6. We cleared dr6 during the context save. + add esp, 4 + pop eax + mov dr7, eax + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 # not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +#; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +#; UINT32 Ldtr, Tr; +#; UINT32 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + add esp, 24 + +#; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +#; NOTE - modified segment registers could hang the debugger... We +#; could attempt to insulate ourselves against this possibility, +#; but that poses risks as well. +#; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 # not for ebp + add esp, 4 # not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + add esp, 8 + iretd + + +#END + diff --git a/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm b/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm new file mode 100755 index 0000000000..dfcbc0deff --- /dev/null +++ b/UefiCpuPkg/CpuDxe/Ia32/CpuAsm.asm @@ -0,0 +1,384 @@ + TITLE CpuAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 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. +;* +;* CpuAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .686 + .model flat,C + .code + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +; +; point to the external interrupt vector table +; +ExternalVectorTablePtr DWORD 0 + +InitializeExternalVectorTablePtr PROC PUBLIC + mov eax, [esp+4] + mov ExternalVectorTablePtr, eax + ret +InitializeExternalVectorTablePtr ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetCodeSelector ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetCodeSelector PROC PUBLIC + mov ecx, [esp+4] + sub esp, 0x10 + lea eax, setCodeSelectorLongJump + mov [esp], eax + mov [esp+4], cx + jmp fword ptr [esp] +setCodeSelectorLongJump: + add esp, 0x10 + ret +SetCodeSelector ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetDataSelectors ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetDataSelectors PROC PUBLIC + mov ecx, [esp+4] + mov ss, cx + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + ret +SetDataSelectors ENDP + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. + +CommonInterruptEntry PROC PUBLIC + cli + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + + ; + ; Calculate vector number + ; + ; Get the return address of call, actually, it is the + ; address of vector number. + ; + xchg ecx, [esp] + mov cx, [ecx] + and ecx, 0FFFFh + cmp ecx, 32 ; Intel reserved vector for exceptions? + jae NoErrorCode + bt mErrorCodeFlag, ecx + jc HasErrorCode + +NoErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack + ; + push ecx + + ; + ; Put 0 (dummy) error code on stack, and restore ECX + ; + xor ecx, ecx ; ECX = 0 + xchg ecx, [esp+4] + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + ECX + + ; +---------------------+ <-- ESP + ; + ; Registers: + ; ECX - Vector Number + ; + + ; + ; Put Vector Number on stack and restore ECX + ; + xchg ecx, [esp] + + ; + ; Fall through to join main routine code + ; at ErrorCodeAndVectorOnStack + ; +@@: + jmp @B + +ErrorCodeAndVectorOnStack: + push ebp + mov ebp, esp + + ; + ; Stack: + ; +---------------------+ + ; + EFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + EIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + Vector Number + + ; +---------------------+ + ; + EBP + + ; +---------------------+ <-- EBP + ; + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword ptr [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax +;; clear Dr7 while executing debugger itself + xor eax, eax + mov dr7, eax + + mov eax, dr6 + push eax +;; insure all status bits in dr6 are clear... + xor eax, eax + mov dr6, eax + + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 07h ;fxsave [edi] + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; call into exception handler + mov eax, ExternalVectorTablePtr ; get the interrupt vectors base + or eax, eax ; NULL? + jz nullExternalExceptionHandler + + mov ecx, [ebp + 4] + mov eax, [eax + ecx * 4] + or eax, eax ; NULL? + jz nullExternalExceptionHandler + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + call eax + add esp, 8 + +nullExternalExceptionHandler: + + cli +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 0eh ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop eax + mov dr0, eax + pop eax + mov dr1, eax + pop eax + mov dr2, eax + pop eax + mov dr3, eax +;; skip restore of dr6. We cleared dr6 during the context save. + add esp, 4 + pop eax + mov dr7, eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + add esp, 8 + iretd + +CommonInterruptEntry ENDP + +END diff --git a/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S b/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S new file mode 100755 index 0000000000..2a6341a989 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.S @@ -0,0 +1,66 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2006 - 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. +# +# Module Name: +# +# IvtAsm.S +# +# Abstract: +# +# Interrupt Vector Table +# +#------------------------------------------------------------------------------ + +# +# Interrupt Vector Table +# + +.macro SingleIdtVectorMacro vectorNum + .intel_syntax + call ASM_PFX(CommonInterruptEntry) + .short \vectorNum + nop +.endm + +.macro EightIdtVectors firstVectorNum + SingleIdtVectorMacro \firstVectorNum + SingleIdtVectorMacro "(\firstVectorNum+1)" + SingleIdtVectorMacro "(\firstVectorNum+2)" + SingleIdtVectorMacro "(\firstVectorNum+3)" + SingleIdtVectorMacro "(\firstVectorNum+4)" + SingleIdtVectorMacro "(\firstVectorNum+5)" + SingleIdtVectorMacro "(\firstVectorNum+6)" + SingleIdtVectorMacro "(\firstVectorNum+7)" +.endm + +.macro SixtyFourIdtVectors firstVectorNum + EightIdtVectors \firstVectorNum + EightIdtVectors "(\firstVectorNum+0x08)" + EightIdtVectors "(\firstVectorNum+0x10)" + EightIdtVectors "(\firstVectorNum+0x18)" + EightIdtVectors "(\firstVectorNum+0x20)" + EightIdtVectors "(\firstVectorNum+0x28)" + EightIdtVectors "(\firstVectorNum+0x30)" + EightIdtVectors "(\firstVectorNum+0x38)" +.endm + +ASM_GLOBAL ASM_PFX(AsmIdtVector00) +.align 8 +ASM_PFX(AsmIdtVector00): + SixtyFourIdtVectors 0x00 + SixtyFourIdtVectors 0x40 + SixtyFourIdtVectors 0x80 + SixtyFourIdtVectors 0xC0 +ASM_GLOBAL ASM_PFX(AsmCommonIdtEnd) +ASM_PFX(AsmCommonIdtEnd): + .byte 0 + + diff --git a/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm b/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm new file mode 100755 index 0000000000..e5dfaace8c --- /dev/null +++ b/UefiCpuPkg/CpuDxe/Ia32/IvtAsm.asm @@ -0,0 +1,51 @@ + TITLE IvtAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright 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. +;* +;* IvtAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +#include + +#ifdef MDE_CPU_IA32 + .686 + .model flat,C +#endif + .code + +;------------------------------------------------------------------------------ +; Generic IDT Vector Handlers for the Host. They are all the same so they +; will compress really well. +; +; By knowing the return address for Vector 00 you can can calculate the +; vector number by looking at the call CommonInterruptEntry return address. +; (return address - (AsmIdtVector00 + 5))/8 == IDT index +; +;------------------------------------------------------------------------------ + +EXTRN CommonInterruptEntry:PROC + +ALIGN 8 + +PUBLIC AsmIdtVector00 + +AsmIdtVector00 LABEL BYTE +REPEAT 256 + call CommonInterruptEntry + dw ($ - AsmIdtVector00 - 5) / 8 ; vector number + nop +ENDM + +END + diff --git a/UefiCpuPkg/CpuDxe/X64/CpuAsm.S b/UefiCpuPkg/CpuDxe/X64/CpuAsm.S new file mode 100755 index 0000000000..9d4c26190e --- /dev/null +++ b/UefiCpuPkg/CpuDxe/X64/CpuAsm.S @@ -0,0 +1,363 @@ +# TITLE CpuAsm.asm: + +#------------------------------------------------------------------------------ +#* +#* Copyright 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. +#* +#* CpuAsm.S +#* +#* Abstract: +#* +#------------------------------------------------------------------------------ + + +#text SEGMENT + + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + + +# +# point to the external interrupt vector table +# +ExternalVectorTablePtr: + .byte 0, 0, 0, 0, 0, 0, 0, 0 + +.intel_syntax +ASM_GLOBAL ASM_PFX(InitializeExternalVectorTablePtr) +ASM_PFX(InitializeExternalVectorTablePtr): + lea %rax, [%rip+ExternalVectorTablePtr] # save vector number + mov [%rax], %rcx + ret + + +#------------------------------------------------------------------------------ +# VOID +# SetCodeSelector ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +.intel_syntax +ASM_GLOBAL ASM_PFX(SetCodeSelector) +ASM_PFX(SetCodeSelector): + sub %rsp, 0x10 + lea %rax, [%rip+setCodeSelectorLongJump] + mov [%rsp], %rax + mov [%rsp+4], %cx + jmp fword ptr [%rsp] +setCodeSelectorLongJump: + add %rsp, 0x10 + ret + +#------------------------------------------------------------------------------ +# VOID +# SetDataSelectors ( +# UINT16 Selector +# ); +#------------------------------------------------------------------------------ +.intel_syntax +ASM_GLOBAL ASM_PFX(SetDataSelectors) +ASM_PFX(SetDataSelectors): + mov %ss, %cx + mov %ds, %cx + mov %es, %cx + mov %fs, %cx + mov %gs, %cx + ret + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +.intel_syntax +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) +ASM_PFX(CommonInterruptEntry): + cli + # + # All interrupt handlers are invoked through interrupt gates, so + # IF flag automatically cleared at the entry point + # + # + # Calculate vector number + # + xchg %rcx, [%rsp] # get the return address of call, actually, it is the address of vector number. + movzx %ecx, word ptr [%rcx] + cmp %ecx, 32 # Intel reserved vector for exceptions? + jae NoErrorCode + push %rax + lea %rax, [%rip+ASM_PFX(mErrorCodeFlag)] + bt dword ptr [%rax], %ecx + pop %rax + jc CommonInterruptEntry_al_0000 + +NoErrorCode: + + # + # Push a dummy error code on the stack + # to maintain coherent stack map + # + push [%rsp] + mov qword ptr [%rsp + 8], 0 +CommonInterruptEntry_al_0000: + push %rbp + mov %rbp, %rsp + + # + # Stack: + # +---------------------+ <-- 16-byte aligned ensured by processor + # + Old SS + + # +---------------------+ + # + Old RSP + + # +---------------------+ + # + RFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + RIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + RCX / Vector Number + + # +---------------------+ + # + RBP + + # +---------------------+ <-- RBP, 16-byte aligned + # + + + # + # Since here the stack pointer is 16-byte aligned, so + # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + # is 16-byte aligned + # + +#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + push %r15 + push %r14 + push %r13 + push %r12 + push %r11 + push %r10 + push %r9 + push %r8 + push %rax + push qword ptr [%rbp + 8] # RCX + push %rdx + push %rbx + push qword ptr [%rbp + 48] # RSP + push qword ptr [%rbp] # RBP + push %rsi + push %rdi + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzx %rax, word ptr [%rbp + 56] + push %rax # for ss + movzx %rax, word ptr [%rbp + 32] + push %rax # for cs + mov %rax, %ds + push %rax + mov %rax, %es + push %rax + mov %rax, %fs + push %rax + mov %rax, %gs + push %rax + + mov [%rbp + 8], %rcx # save vector number + +#; UINT64 Rip; + push qword ptr [%rbp + 24] + +#; UINT64 Gdtr[2], Idtr[2]; + xor %rax, %rax + push %rax + push %rax + sidt [%rsp] + xchg %rax, [%rsp + 2] + xchg %rax, [%rsp] + xchg %rax, [%rsp + 8] + + xor %rax, %rax + push %rax + push %rax + sgdt [%rsp] + xchg %rax, [%rsp + 2] + xchg %rax, [%rsp] + xchg %rax, [%rsp + 8] + +#; UINT64 Ldtr, Tr; + xor %rax, %rax + str %ax + push %rax + sldt %ax + push %rax + +#; UINT64 RFlags; + push qword ptr [%rbp + 40] + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + mov %rax, %cr8 + push %rax + mov %rax, %cr4 + or %rax, 0x208 + mov %cr4, %rax + push %rax + mov %rax, %cr3 + push %rax + mov %rax, %cr2 + push %rax + xor %rax, %rax + push %rax + mov %rax, %cr0 + push %rax + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov %rax, %dr7 + push %rax +#; clear Dr7 while executing debugger itself + xor %rax, %rax + mov %dr7, %rax + + mov %rax, %dr6 + push %rax +#; insure all status bits in dr6 are clear... + xor %rax, %rax + mov %dr6, %rax + + mov %rax, %dr3 + push %rax + mov %rax, %dr2 + push %rax + mov %rax, %dr1 + push %rax + mov %rax, %dr0 + push %rax + +#; FX_SAVE_STATE_X64 FxSaveState; + sub %rsp, 512 + mov %rdi, %rsp + .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] + +#; UINT32 ExceptionData; + push qword ptr [%rbp + 16] + +#; call into exception handler + mov %rcx, [%rbp + 8] + lea %rax, [%rip+ExternalVectorTablePtr] + mov %eax, [%eax] + mov %rax, [%rax + %rcx * 8] + or %rax, %rax # NULL? + + je nonNullValue# + +#; Prepare parameter and call +# mov rcx, [rbp + 8] + mov %rdx, %rsp + # + # Per X64 calling convention, allocate maximum parameter stack space + # and make sure RSP is 16-byte aligned + # + sub %rsp, 4 * 8 + 8 + call %rax + add %rsp, 4 * 8 + 8 + +nonNullValue: + cli +#; UINT64 ExceptionData; + add %rsp, 8 + +#; FX_SAVE_STATE_X64 FxSaveState; + + mov %rsi, %rsp + .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] + add %rsp, 512 + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop %rax + mov %dr0, %rax + pop %rax + mov %dr1, %rax + pop %rax + mov %dr2, %rax + pop %rax + mov %dr3, %rax +#; skip restore of dr6. We cleared dr6 during the context save. + add %rsp, 8 + pop %rax + mov %dr7, %rax + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + pop %rax + mov %cr0, %rax + add %rsp, 8 # not for Cr1 + pop %rax + mov %cr2, %rax + pop %rax + mov %cr3, %rax + pop %rax + mov %cr4, %rax + pop %rax + mov %cr8, %rax + +#; UINT64 RFlags; + pop qword ptr [%rbp + 40] + +#; UINT64 Ldtr, Tr; +#; UINT64 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + add %rsp, 48 + +#; UINT64 Rip; + pop qword ptr [%rbp + 24] + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + pop %rax + # mov gs, rax ; not for gs + pop %rax + # mov fs, rax ; not for fs + # (X64 will not use fs and gs, so we do not restore it) + pop %rax + mov %es, %rax + pop %rax + mov %ds, %rax + pop qword ptr [%rbp + 32] # for cs + pop qword ptr [%rbp + 56] # for ss + +#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pop %rdi + pop %rsi + add %rsp, 8 # not for rbp + pop qword ptr [%rbp + 48] # for rsp + pop %rbx + pop %rdx + pop %rcx + pop %rax + pop %r8 + pop %r9 + pop %r10 + pop %r11 + pop %r12 + pop %r13 + pop %r14 + pop %r15 + + mov %rsp, %rbp + pop %rbp + add %rsp, 16 + iretq + + +#text ENDS + +#END + + diff --git a/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm b/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm new file mode 100755 index 0000000000..05d9bca119 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/X64/CpuAsm.asm @@ -0,0 +1,345 @@ + TITLE CpuAsm.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright 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. +;* +;* CpuAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .code + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +; +; point to the external interrupt vector table +; +ExternalVectorTablePtr QWORD 0 + +InitializeExternalVectorTablePtr PROC PUBLIC + mov ExternalVectorTablePtr, rcx + ret +InitializeExternalVectorTablePtr ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetCodeSelector ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetCodeSelector PROC PUBLIC + sub rsp, 0x10 + lea rax, setCodeSelectorLongJump + mov [rsp], rax + mov [rsp+4], cx + jmp fword ptr [rsp] +setCodeSelectorLongJump: + add rsp, 0x10 + ret +SetCodeSelector ENDP + +;------------------------------------------------------------------------------ +; VOID +; SetDataSelectors ( +; UINT16 Selector +; ); +;------------------------------------------------------------------------------ +SetDataSelectors PROC PUBLIC + mov ss, cx + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + ret +SetDataSelectors ENDP + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. + +CommonInterruptEntry PROC PUBLIC + cli + ; + ; All interrupt handlers are invoked through interrupt gates, so + ; IF flag automatically cleared at the entry point + ; + ; + ; Calculate vector number + ; + xchg rcx, [rsp] ; get the return address of call, actually, it is the address of vector number. + movzx ecx, word ptr [rcx] + cmp ecx, 32 ; Intel reserved vector for exceptions? + jae NoErrorCode + bt mErrorCodeFlag, ecx + jc @F + +NoErrorCode: + + ; + ; Push a dummy error code on the stack + ; to maintain coherent stack map + ; + push [rsp] + mov qword ptr [rsp + 8], 0 +@@: + push rbp + mov rbp, rsp + + ; + ; Stack: + ; +---------------------+ <-- 16-byte aligned ensured by processor + ; + Old SS + + ; +---------------------+ + ; + Old RSP + + ; +---------------------+ + ; + RFlags + + ; +---------------------+ + ; + CS + + ; +---------------------+ + ; + RIP + + ; +---------------------+ + ; + Error Code + + ; +---------------------+ + ; + RCX / Vector Number + + ; +---------------------+ + ; + RBP + + ; +---------------------+ <-- RBP, 16-byte aligned + ; + + + ; + ; Since here the stack pointer is 16-byte aligned, so + ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + ; is 16-byte aligned + ; + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rax + push qword ptr [rbp + 8] ; RCX + push rdx + push rbx + push qword ptr [rbp + 48] ; RSP + push qword ptr [rbp] ; RBP + push rsi + push rdi + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzx rax, word ptr [rbp + 56] + push rax ; for ss + movzx rax, word ptr [rbp + 32] + push rax ; for cs + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + + mov [rbp + 8], rcx ; save vector number + +;; UINT64 Rip; + push qword ptr [rbp + 24] + +;; UINT64 Gdtr[2], Idtr[2]; + xor rax, rax + push rax + push rax + sidt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + + xor rax, rax + push rax + push rax + sgdt [rsp] + xchg rax, [rsp + 2] + xchg rax, [rsp] + xchg rax, [rsp + 8] + +;; UINT64 Ldtr, Tr; + xor rax, rax + str ax + push rax + sldt ax + push rax + +;; UINT64 RFlags; + push qword ptr [rbp + 40] + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + mov rax, cr8 + push rax + mov rax, cr4 + or rax, 208h + mov cr4, rax + push rax + mov rax, cr3 + push rax + mov rax, cr2 + push rax + xor rax, rax + push rax + mov rax, cr0 + push rax + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov rax, dr7 + push rax +;; clear Dr7 while executing debugger itself + xor rax, rax + mov dr7, rax + + mov rax, dr6 + push rax +;; insure all status bits in dr6 are clear... + xor rax, rax + mov dr6, rax + + mov rax, dr3 + push rax + mov rax, dr2 + push rax + mov rax, dr1 + push rax + mov rax, dr0 + push rax + +;; FX_SAVE_STATE_X64 FxSaveState; + sub rsp, 512 + mov rdi, rsp + db 0fh, 0aeh, 07h ;fxsave [rdi] + +;; UINT32 ExceptionData; + push qword ptr [rbp + 16] + +;; call into exception handler + mov rcx, [rbp + 8] + mov rax, ExternalVectorTablePtr ; get the interrupt vectors base + mov rax, [rax + rcx * 8] + or rax, rax ; NULL? + + je nonNullValue; + +;; Prepare parameter and call +; mov rcx, [rbp + 8] + mov rdx, rsp + ; + ; Per X64 calling convention, allocate maximum parameter stack space + ; and make sure RSP is 16-byte aligned + ; + sub rsp, 4 * 8 + 8 + call rax + add rsp, 4 * 8 + 8 + +nonNullValue: + cli +;; UINT64 ExceptionData; + add rsp, 8 + +;; FX_SAVE_STATE_X64 FxSaveState; + + mov rsi, rsp + db 0fh, 0aeh, 0Eh ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop rax + mov dr0, rax + pop rax + mov dr1, rax + pop rax + mov dr2, rax + pop rax + mov dr3, rax +;; skip restore of dr6. We cleared dr6 during the context save. + add rsp, 8 + pop rax + mov dr7, rax + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + pop rax + mov cr0, rax + add rsp, 8 ; not for Cr1 + pop rax + mov cr2, rax + pop rax + mov cr3, rax + pop rax + mov cr4, rax + pop rax + mov cr8, rax + +;; UINT64 RFlags; + pop qword ptr [rbp + 40] + +;; UINT64 Ldtr, Tr; +;; UINT64 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add rsp, 48 + +;; UINT64 Rip; + pop qword ptr [rbp + 24] + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + pop rax + ; mov gs, rax ; not for gs + pop rax + ; mov fs, rax ; not for fs + ; (X64 will not use fs and gs, so we do not restore it) + pop rax + mov es, rax + pop rax + mov ds, rax + pop qword ptr [rbp + 32] ; for cs + pop qword ptr [rbp + 56] ; for ss + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pop rdi + pop rsi + add rsp, 8 ; not for rbp + pop qword ptr [rbp + 48] ; for rsp + pop rbx + pop rdx + pop rcx + pop rax + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + mov rsp, rbp + pop rbp + add rsp, 16 + iretq + +CommonInterruptEntry ENDP + +END +