From 8f07f895fb03800e54c23225639116f34d2ce7b1 Mon Sep 17 00:00:00 2001 From: vanjeff Date: Thu, 15 Mar 2012 05:24:07 +0000 Subject: [PATCH] Import two CPU Exception Handler Library instances: SecPeiCpuExceptionHandler.inf and DxeSmmCpuExceptionHandler.inf. Signed-off-by: vanjeff Reviewed-by: jyao1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13098 6f19259b-4bc3-4df7-8a09-765794883524 --- .../CpuExceptionCommon.c | 132 +++++ .../CpuExceptionCommon.h | 96 ++++ .../DxeSmmCpuException.c | 84 ++++ .../DxeSmmCpuExceptionHandlerLib.inf | 57 +++ .../Ia32/ArchExceptionHandler.c | 164 ++++++ .../Ia32/ExceptionHandlerAsm.S | 467 +++++++++++++++++ .../Ia32/ExceptionHandlerAsm.asm | 471 ++++++++++++++++++ .../SecPeiCpuException.c | 63 +++ .../SecPeiCpuExceptionHandlerLib.inf | 56 +++ .../X64/ArchExceptionHandler.c | 192 +++++++ .../X64/ExceptionHandlerAsm.S | 406 +++++++++++++++ .../X64/ExceptionHandlerAsm.asm | 407 +++++++++++++++ UefiCpuPkg/UefiCpuPkg.dsc | 4 +- 13 files changed, 2598 insertions(+), 1 deletion(-) create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c new file mode 100644 index 0000000000..4a4925afe5 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c @@ -0,0 +1,132 @@ +/** @file + CPU Exception Hanlder Library common functions. + + Copyright (c) 2012, 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 "CpuExceptionCommon.h" + +// +// 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 +// +UINT32 mErrorCodeFlag = 0x00027d00; + +// +// Define the maximum message length +// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +/** + Prints a message to the serial port. + + @param Format Format string for the message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + // + // Send the print string to a Serial Port + // + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); +} + +/** + Find and display image base address and return image base and its entry point. + + @return EFI_SUCCESS Image base address. + @return 0 Image header cannot be found. +**/ +UINTN +FindModuleImageBase ( + IN UINTN CurrentEip, + OUT UINTN *EntryPoint + ) +{ + UINTN Pe32Data; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + VOID *PdbPointer; + + // + // Find Image Base + // + Pe32Data = CurrentEip & ~(mImageAlignSize - 1); + while (Pe32Data != 0) { + DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + // + // It's PE image. + // + InternalPrintMessage ("!!!! Find PE image "); + *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff); + break; + } + } else { + // + // DOS image header is not present, TE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) && + ((Hdr.Te->Machine == IMAGE_FILE_MACHINE_I386) || Hdr.Te->Machine == IMAGE_FILE_MACHINE_X64)) { + // + // It's TE image, it TE header and Machine type match + // + InternalPrintMessage ("!!!! Find TE image "); + *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; + break; + } + } + + // + // Not found the image base, check the previous aligned address + // + Pe32Data -= mImageAlignSize; + } + + if (Pe32Data != 0) { + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data); + if (PdbPointer != NULL) { + InternalPrintMessage ("%a", PdbPointer); + } else { + InternalPrintMessage ("(No PDB) " ); + } + } else { + InternalPrintMessage ("!!!! Can't find image information. !!!!\n"); + } + + return Pe32Data; +} + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h new file mode 100644 index 0000000000..fa245e2ac8 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h @@ -0,0 +1,96 @@ +/** @file + Common header file for CPU Exception Handler Library. + + Copyright (c) 2012, 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_EXCEPTION_COMMON_H_ +#define _CPU_EXCEPTION_COMMON_H_ + +#include +#include +#include +#include +#include + +#define CPU_EXCEPTION_NUM 32 +// +// Record exception handler information +// +typedef struct { + UINTN ExceptionStart; + UINTN ExceptionStubHeaderSize; +} EXCEPTION_HANDLER_TEMPLATE_MAP; + +extern UINT32 mErrorCodeFlag; +extern CONST UINTN mImageAlignSize; + +/** + Return address map of exception handler template so that C code can generate + exception tables. + + @param AddressMap Pointer to a buffer where the address map is returned. +**/ +VOID +EFIAPI +GetTemplateAddressMap ( + OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap + ); + +/** + Internal function to setup CPU exception handlers. + +**/ +VOID +InternalSetupCpuExceptionHandlers ( + VOID + ); + +/** + Prints a message to the serial port. + + @param Format Format string for the message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ); + +/** + Find and display image base address and return image base and its entry point. + + @return EFI_SUCCESS Image base address. + @return 0 Image header cannot be found. +**/ +UINTN +FindModuleImageBase ( + IN UINTN CurrentEip, + OUT UINTN *EntryPoint + ); + +/** + Display CPU information. + + @param InterruptType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN UINTN InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +#endif diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c new file mode 100644 index 0000000000..3110687284 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c @@ -0,0 +1,84 @@ +/** @file + CPU Exception Library provides DXE/SMM CPU exception handler. + +Copyright (c) 2012, 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 that 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 + +#include "CpuExceptionCommon.h" +#include + +// +// Spinlock for CPU information display +// +SPIN_LOCK mDisplayMessageSpinLock; + +// +// Image align size for DXE/SMM +// +CONST UINTN mImageAlignSize = SIZE_4KB; + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // Get Spinlock to display CPU information + // + while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock)) { + CpuPause (); + } + + // + // Display ExceptionType, CPU information and Image information + // + DumpCpuContent (ExceptionType, SystemContext); + + // + // Release Spinlock + // + ReleaseSpinLock (&mDisplayMessageSpinLock); + + // + // Enter a dead loop. + // + CpuDeadLoop (); +} + +/** + Setup CPU exception handlers. + + This API will setups the CPU exception handler to display CPU contents and run into + CpuDeadLoop(). + @Note: Before invoking this API, caller must allocate memory for IDT table and load + IDTR by AsmWriteIdtr(). + +**/ +VOID +EFIAPI +SetupCpuExceptionHandlers ( + IN VOID + ) +{ + InitializeSpinLock (&mDisplayMessageSpinLock); + InternalSetupCpuExceptionHandlers (); +} + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf new file mode 100644 index 0000000000..9f0f2d9beb --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf @@ -0,0 +1,57 @@ +## @file +# Component description file for DXE/SMM CPU Exception Handler Library instance. +# +# This library instance supports DXE SMM module only. +# +# Copyright (c) 2012, 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 = DxeSmmCpuExceptionHandlerLib + FILE_GUID = EC629480-BD36-4e8e-8AB2-D28BF0D45864 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.asm |MSFT + Ia32/ExceptionHandlerAsm.S |GCC + Ia32/ArchExceptionHandler.c + +[Sources.X64] + X64/ExceptionHandlerAsm.asm |MSFT + X64/ExceptionHandlerAsm.S |GCC + X64/ArchExceptionHandler.c + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + DxeSmmCpuException.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + SynchronizationLib + LocalApicLib + PeCoffGetEntryPointLib diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c new file mode 100644 index 0000000000..a69f0d3d2b --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c @@ -0,0 +1,164 @@ +/** @file + IA32 CPU Exception Hanlder functons. + + Copyright (c) 2012, 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 "CpuExceptionCommon.h" + +/** + Internal function to setup CPU exception handlers. + +**/ +VOID +InternalSetupCpuExceptionHandlers ( + VOID + ) +{ + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtSize; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + UINT16 CodeSegment; + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN Index; + UINTN InterruptHandler;; + + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtSize = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtSize > CPU_EXCEPTION_NUM) { + // + // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most + // + IdtSize = CPU_EXCEPTION_NUM; + } + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; + + GetTemplateAddressMap (&TemplateMap); + + for (Index = 0; Index < IdtSize; Index ++) { + InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize; + IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[Index].Bits.Selector = CodeSegment; + IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + } +} + +/** + Dump CPU content information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN ImageBase; + UINTN EntryPoint; + + InternalPrintMessage ( + "!!!! IA32 Exception Type - %08x CPU Apic ID - %08x !!!!\n", + ExceptionType, + GetApicId () + ); + InternalPrintMessage ( + "EIP - %08x, CS - %08x, EFLAGS - %08x\n", + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->Cs, + SystemContext.SystemContextIa32->Eflags + ); + if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) { + InternalPrintMessage ( + "ExceptionData - %08x\n", + SystemContext.SystemContextIa32->ExceptionData + ); + } + InternalPrintMessage ( + "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n", + SystemContext.SystemContextIa32->Eax, + SystemContext.SystemContextIa32->Ecx, + SystemContext.SystemContextIa32->Edx, + SystemContext.SystemContextIa32->Ebx + ); + InternalPrintMessage ( + "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n", + SystemContext.SystemContextIa32->Esp, + SystemContext.SystemContextIa32->Ebp, + SystemContext.SystemContextIa32->Esi, + SystemContext.SystemContextIa32->Edi + ); + InternalPrintMessage ( + "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n", + SystemContext.SystemContextIa32->Ds, + SystemContext.SystemContextIa32->Es, + SystemContext.SystemContextIa32->Fs, + SystemContext.SystemContextIa32->Gs, + SystemContext.SystemContextIa32->Ss + ); + InternalPrintMessage ( + "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n", + SystemContext.SystemContextIa32->Cr0, + SystemContext.SystemContextIa32->Cr2, + SystemContext.SystemContextIa32->Cr3, + SystemContext.SystemContextIa32->Cr4 + ); + InternalPrintMessage ( + "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n", + SystemContext.SystemContextIa32->Dr0, + SystemContext.SystemContextIa32->Dr1, + SystemContext.SystemContextIa32->Dr2, + SystemContext.SystemContextIa32->Dr3 + ); + InternalPrintMessage ( + "DR6 - %08x, DR7 - %08x\n", + SystemContext.SystemContextIa32->Dr6, + SystemContext.SystemContextIa32->Dr7 + ); + InternalPrintMessage ( + "GDTR - %08x %08x, IDTR - %08x %08x\n", + SystemContext.SystemContextIa32->Gdtr[0], + SystemContext.SystemContextIa32->Gdtr[1], + SystemContext.SystemContextIa32->Idtr[0], + SystemContext.SystemContextIa32->Idtr[1] + ); + InternalPrintMessage ( + "LDTR - %08x, TR - %08x\n", + SystemContext.SystemContextIa32->Ldtr, + SystemContext.SystemContextIa32->Tr + ); + InternalPrintMessage ( + "FXSAVE_STATE - %08x\n", + &SystemContext.SystemContextIa32->FxSaveState + ); + + // + // Find module image base and module entry point by RIP + // + ImageBase = FindModuleImageBase (SystemContext.SystemContextIa32->Eip, &EntryPoint); + if (ImageBase != 0) { + InternalPrintMessage ( + " (ImageBase=%08x, EntryPoint=%08x) !!!!\n", + ImageBase, + EntryPoint + ); + } +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S new file mode 100644 index 0000000000..8b3f6319b6 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S @@ -0,0 +1,467 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2012, 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. +#* +#* ExceptionHandlerAsm.S +#* +#* Abstract: +#* +#* IA32 CPU Exception Handler +# +#------------------------------------------------------------------------------ + + + + + +#.MMX +#.XMM + +ASM_GLOBAL ASM_PFX(CommonExceptionHandler) +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + +.text + +# +# exception handler stub table +# +Exception0Handle: + pushl $0 + jmp ASM_PFX(CommonInterruptEntry) +Exception1Handle: + pushl $1 + jmp ASM_PFX(CommonInterruptEntry) +Exception2Handle: + pushl $2 + jmp ASM_PFX(CommonInterruptEntry) +Exception3Handle: + pushl $3 + jmp ASM_PFX(CommonInterruptEntry) +Exception4Handle: + pushl $4 + jmp ASM_PFX(CommonInterruptEntry) +Exception5Handle: + pushl $5 + jmp ASM_PFX(CommonInterruptEntry) +Exception6Handle: + pushl $6 + jmp ASM_PFX(CommonInterruptEntry) +Exception7Handle: + pushl $7 + jmp ASM_PFX(CommonInterruptEntry) +Exception8Handle: + pushl $8 + jmp ASM_PFX(CommonInterruptEntry) +Exception9Handle: + pushl $9 + jmp ASM_PFX(CommonInterruptEntry) +Exception10Handle: + pushl $10 + jmp ASM_PFX(CommonInterruptEntry) +Exception11Handle: + pushl $11 + jmp ASM_PFX(CommonInterruptEntry) +Exception12Handle: + pushl $12 + jmp ASM_PFX(CommonInterruptEntry) +Exception13Handle: + pushl $13 + jmp ASM_PFX(CommonInterruptEntry) +Exception14Handle: + pushl $14 + jmp ASM_PFX(CommonInterruptEntry) +Exception15Handle: + pushl $15 + jmp ASM_PFX(CommonInterruptEntry) +Exception16Handle: + pushl $16 + jmp ASM_PFX(CommonInterruptEntry) +Exception17Handle: + pushl $17 + jmp ASM_PFX(CommonInterruptEntry) +Exception18Handle: + pushl $18 + jmp ASM_PFX(CommonInterruptEntry) +Exception19Handle: + pushl $19 + jmp ASM_PFX(CommonInterruptEntry) +Exception20Handle: + pushl $20 + jmp ASM_PFX(CommonInterruptEntry) +Exception21Handle: + pushl $21 + jmp ASM_PFX(CommonInterruptEntry) +Exception22Handle: + pushl $22 + jmp ASM_PFX(CommonInterruptEntry) +Exception23Handle: + pushl $23 + jmp ASM_PFX(CommonInterruptEntry) +Exception24Handle: + pushl $24 + jmp ASM_PFX(CommonInterruptEntry) +Exception25Handle: + pushl $25 + jmp ASM_PFX(CommonInterruptEntry) +Exception26Handle: + pushl $26 + jmp ASM_PFX(CommonInterruptEntry) +Exception27Handle: + pushl $27 + jmp ASM_PFX(CommonInterruptEntry) +Exception28Handle: + pushl $28 + jmp ASM_PFX(CommonInterruptEntry) +Exception29Handle: + pushl $29 + jmp ASM_PFX(CommonInterruptEntry) +Exception30Handle: + pushl $30 + jmp ASM_PFX(CommonInterruptEntry) +Exception31Handle: + pushl $31 + jmp ASM_PFX(CommonInterruptEntry) + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +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. + # + xchgl (%esp), %ecx + andl $0x0FFFF, %ecx + cmpl $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + bt %ecx, ASM_PFX(mErrorCodeFlag) + jc HasErrorCode + +NoErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack + # + pushl %ecx + + # + # Put 0 (dummy) error code on stack, and restore ECX + # + xorl %ecx, %ecx # ECX = 0 + xchgl 4(%esp), %ecx + + jmp ErrorCodeAndVectorOnStack + +HasErrorCode: + + # + # Stack: + # +---------------------+ + # + EFlags + + # +---------------------+ + # + CS + + # +---------------------+ + # + EIP + + # +---------------------+ + # + Error Code + + # +---------------------+ + # + ECX + + # +---------------------+ <-- ESP + # + # Registers: + # ECX - Vector Number + # + + # + # Put Vector Number on stack and restore ECX + # + xchgl (%esp), %ecx + + # + # Fall through to join main routine code + # at ErrorCodeAndVectorOnStack + # +CommonInterruptEntry_al_0000: + jmp CommonInterruptEntry_al_0000 + +ErrorCodeAndVectorOnStack: + pushl %ebp + movl %esp, %ebp + + # + # 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 + # + andl $0x0fffffff0, %esp + subl $12, %esp + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + leal 24(%ebp), %ecx + pushl %ecx # ESP + pushl (%ebp) # EBP + pushl %esi + pushl %edi + +#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movl %ss, %eax + pushl %eax + movzwl 16(%ebp), %eax + pushl %eax + movl %ds, %eax + pushl %eax + movl %es, %eax + pushl %eax + movl %fs, %eax + pushl %eax + movl %gs, %eax + pushl %eax + +#; UINT32 Eip; + movl 12(%ebp), %eax + pushl %eax + +#; UINT32 Gdtr[2], Idtr[2]; + subl $8, %esp + sidt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + + subl $8, %esp + sgdt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0x0FFFF, %eax + movl %eax, 4(%esp) + +#; UINT32 Ldtr, Tr; + xorl %eax, %eax + str %ax + pushl %eax + sldt %ax + pushl %eax + +#; UINT32 EFlags; + movl 20(%ebp), %eax + pushl %eax + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + movl %cr4, %eax + orl $0x208, %eax + movl %eax, %cr4 + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + xorl %eax, %eax + pushl %eax + movl %cr0, %eax + pushl %eax + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movl %dr7, %eax + pushl %eax + movl %dr6, %eax + pushl %eax + movl %dr3, %eax + pushl %eax + movl %dr2, %eax + pushl %eax + movl %dr1, %eax + pushl %eax + movl %dr0, %eax + pushl %eax + +#; FX_SAVE_STATE_IA32 FxSaveState; + subl $512, %esp + movl %esp, %edi + .byte 0x0f, 0x0ae, 0x07 #fxsave [edi] + +#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushl 8(%ebp) + +#; Prepare parameter and call + movl %esp, %edx + pushl %edx + movl 4(%ebp), %edx + pushl %edx + + # + # Call External Exception Handler + # + call ASM_PFX(CommonExceptionHandler) + addl $8, %esp + + cli +#; UINT32 ExceptionData; + addl $4, %esp + +#; FX_SAVE_STATE_IA32 FxSaveState; + movl %esp, %esi + .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] + addl $512, %esp + +#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addl $24, %esp + +#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + popl %eax + movl %eax, %cr0 + addl $4, %esp # not for Cr1 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, %cr3 + popl %eax + movl %eax, %cr4 + +#; UINT32 EFlags; + popl 20(%ebp) + +#; UINT32 Ldtr, Tr; +#; UINT32 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addl $24, %esp + +#; UINT32 Eip; + popl 12(%ebp) + +#; 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. +#; + popl %gs + popl %fs + popl %es + popl %ds + popl 16(%ebp) + popl %ss + +#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + popl %edi + popl %esi + addl $4, %esp # not for ebp + addl $4, %esp # not for esp + popl %ebx + popl %edx + popl %ecx + popl %eax + + movl %ebp, %esp + popl %ebp + addl $8, %esp + iretl + + +#---------------------------------------; +# _GetTemplateAddressMap ; +#----------------------------------------------------------------------------; +# +# Protocol prototype +# GetTemplateAddressMap ( +# EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap +# ); +# +# Routine Description: +# +# Return address map of interrupt handler template so that C code can generate +# interrupt table. +# +# Arguments: +# +# +# Returns: +# +# Nothing +# +# +# Input: [ebp][0] = Original ebp +# [ebp][4] = Return address +# +# Output: Nothing +# +# Destroys: Nothing +#-----------------------------------------------------------------------------; +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(GetTemplateAddressMap) +ASM_PFX(GetTemplateAddressMap): + + pushl %ebp + movl %esp,%ebp + pushal + + movl 0x8(%ebp), %ebx + movl $Exception0Handle, (%ebx) + movl $(Exception1Handle - Exception0Handle), 0x4(%ebx) + + popal + popl %ebp + ret + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm new file mode 100644 index 0000000000..dc71959bd1 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm @@ -0,0 +1,471 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012, 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: +; +; ExceptionHandlerAsm.Asm +; +; Abstract: +; +; IA32 CPU Exception Handler +; +; Notes: +; +;------------------------------------------------------------------------------ + + .686 + .model flat,C + +; +; CommonExceptionHandler() +; +CommonExceptionHandler PROTO C + +.data + +CommonEntryAddr DD CommonInterruptEntry + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +.code + +; +; exception handler stub table +; +Exception0Handle: + push 0 + jmp dword ptr [CommonEntryAddr] +Exception1Handle: + push 1 + jmp dword ptr [CommonEntryAddr] +Exception2Handle: + push 2 + jmp dword ptr [CommonEntryAddr] +Exception3Handle: + push 3 + jmp dword ptr [CommonEntryAddr] +Exception4Handle: + push 4 + jmp dword ptr [CommonEntryAddr] +Exception5Handle: + push 5 + jmp dword ptr [CommonEntryAddr] +Exception6Handle: + push 6 + jmp dword ptr [CommonEntryAddr] +Exception7Handle: + push 7 + jmp dword ptr [CommonEntryAddr] +Exception8Handle: + push 8 + jmp dword ptr [CommonEntryAddr] +Exception9Handle: + push 9 + jmp dword ptr [CommonEntryAddr] +Exception10Handle: + push 10 + jmp dword ptr [CommonEntryAddr] +Exception11Handle: + push 11 + jmp dword ptr [CommonEntryAddr] +Exception12Handle: + push 12 + jmp dword ptr [CommonEntryAddr] +Exception13Handle: + push 13 + jmp dword ptr [CommonEntryAddr] +Exception14Handle: + push 14 + jmp dword ptr [CommonEntryAddr] +Exception15Handle: + push 15 + jmp dword ptr [CommonEntryAddr] +Exception16Handle: + push 16 + jmp dword ptr [CommonEntryAddr] +Exception17Handle: + push 17 + jmp dword ptr [CommonEntryAddr] +Exception18Handle: + push 18 + jmp dword ptr [CommonEntryAddr] +Exception19Handle: + push 19 + jmp dword ptr [CommonEntryAddr] +Exception20Handle: + push 20 + jmp dword ptr [CommonEntryAddr] +Exception21Handle: + push 21 + jmp dword ptr [CommonEntryAddr] +Exception22Handle: + push 22 + jmp dword ptr [CommonEntryAddr] +Exception23Handle: + push 23 + jmp dword ptr [CommonEntryAddr] +Exception24Handle: + push 24 + jmp dword ptr [CommonEntryAddr] +Exception25Handle: + push 25 + jmp dword ptr [CommonEntryAddr] +Exception26Handle: + push 26 + jmp dword ptr [CommonEntryAddr] +Exception27Handle: + push 27 + jmp dword ptr [CommonEntryAddr] +Exception28Handle: + push 28 + jmp dword ptr [CommonEntryAddr] +Exception29Handle: + push 29 + jmp dword ptr [CommonEntryAddr] +Exception30Handle: + push 30 + jmp dword ptr [CommonEntryAddr] +Exception31Handle: + push 31 + jmp dword ptr [CommonEntryAddr] + +;----------------------------------------------------------------------------; +; CommonInterruptEntry ; +;----------------------------------------------------------------------------; +; The follow algorithm is used for the common interrupt routine. +; Entry from each interrupt with a push eax and eax=interrupt number + +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] + 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 + mov eax, dr6 + push 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] + +;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + mov eax, CommonExceptionHandler + call eax + add esp, 8 + + 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; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add esp, 4 * 6 + +;; 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 + +;---------------------------------------; +; _GetTemplateAddressMap ; +;----------------------------------------------------------------------------; +; +; Protocol prototype +; GetTemplateAddressMap ( +; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap +; ); +; +; Routine Description: +; +; Return address map of interrupt handler template so that C code can generate +; interrupt table. +; +; Arguments: +; +; +; Returns: +; +; Nothing +; +; +; Input: [ebp][0] = Original ebp +; [ebp][4] = Return address +; +; Output: Nothing +; +; Destroys: Nothing +;-----------------------------------------------------------------------------; +GetTemplateAddressMap proc near public + push ebp ; C prolog + mov ebp, esp + pushad + + mov ebx, dword ptr [ebp+08h] + mov dword ptr [ebx], Exception0Handle + mov dword ptr [ebx+4h], Exception1Handle - Exception0Handle + + popad + pop ebp + ret +GetTemplateAddressMap ENDP + +END diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c new file mode 100644 index 0000000000..de76e478ba --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c @@ -0,0 +1,63 @@ +/** @file + CPU Exception Library provides SEC/PEIM CPU exception handler. + +Copyright (c) 2012, 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 that 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 +#include "CpuExceptionCommon.h" + +// +// Image Aglinment size for SEC/PEI phase +// +CONST UINTN mImageAlignSize = 4; + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // Display ExceptionType, CPU information and Image information + // + DumpCpuContent (ExceptionType, SystemContext); + + // + // Enter a dead loop. + // + CpuDeadLoop (); +} + +/** + Setup CPU exception handlers. + + This API will setups the CPU exception handler to display CPU contents and run into + CpuDeadLoop(). + @Note: Before invoking this API, caller must allocate memory for IDT table and load + IDTR by AsmWriteIdtr(). + +**/ +VOID +EFIAPI +SetupCpuExceptionHandlers ( + IN VOID + ) +{ + InternalSetupCpuExceptionHandlers (); +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf new file mode 100644 index 0000000000..96ddaafd43 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -0,0 +1,56 @@ +## @file +# Component description file for SEC/PEI CPU Exception Handler Library instance +# +# This library instance supports SEC/PEI module only. +# +# Copyright (c) 2012, 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 = SecPeiCpuExceptionHandlerLib + FILE_GUID = CA4BBC99-DFC6-4234-B553-8B6586B7B113 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEIM_CORE PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.asm |MSFT + Ia32/ExceptionHandlerAsm.S |GCC + Ia32/ArchExceptionHandler.c + +[Sources.X64] + X64/ExceptionHandlerAsm.asm |MSFT + X64/ExceptionHandlerAsm.S |GCC + X64/ArchExceptionHandler.c + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + SecPeiCpuException.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + LocalApicLib + PeCoffGetEntryPointLib diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c new file mode 100644 index 0000000000..664472a667 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c @@ -0,0 +1,192 @@ +/** @file + x64 CPU Exception Hanlder. + + Copyright (c) 2012, 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 "CpuExceptionCommon.h" + +/** + Internal function to setup CPU exception handlers. + +**/ +VOID +InternalSetupCpuExceptionHandlers ( + VOID + ) +{ + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtSize; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + UINT16 CodeSegment; + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN Index; + UINTN InterruptHandler; + + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtSize = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtSize > CPU_EXCEPTION_NUM) { + // + // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most + // + IdtSize = CPU_EXCEPTION_NUM; + } + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; + + GetTemplateAddressMap (&TemplateMap); + + for (Index = 0; Index < IdtSize; Index ++) { + InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize; + IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry[Index].Bits.Selector = CodeSegment; + IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + } +} + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +DumpCpuContent ( + IN UINTN ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN ImageBase; + UINTN EntryPoint; + + InternalPrintMessage ( + "!!!! X64 Exception Type - %016lx CPU Apic ID - %08x !!!!\n", + ExceptionType, + GetApicId () + ); + InternalPrintMessage ( + "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Rflags + ); + if (mErrorCodeFlag & (1 << ExceptionType)) { + InternalPrintMessage ( + "ExceptionData - %016lx\n", + SystemContext.SystemContextX64->ExceptionData + ); + } + InternalPrintMessage ( + "RAX - %016lx, RCX - %016lx, RDX - %016lx\n", + SystemContext.SystemContextX64->Rax, + SystemContext.SystemContextX64->Rcx, + SystemContext.SystemContextX64->Rdx + ); + InternalPrintMessage ( + "RBX - %016lx, RSP - %016lx, RBP - %016lx\n", + SystemContext.SystemContextX64->Rbx, + SystemContext.SystemContextX64->Rsp, + SystemContext.SystemContextX64->Rbp + ); + InternalPrintMessage ( + "RSI - %016lx, RDI - %016lx\n", + SystemContext.SystemContextX64->Rsi, + SystemContext.SystemContextX64->Rdi + ); + InternalPrintMessage ( + "R8 - %016lx, R9 - %016lx, R10 - %016lx\n", + SystemContext.SystemContextX64->R8, + SystemContext.SystemContextX64->R9, + SystemContext.SystemContextX64->R10 + ); + InternalPrintMessage ( + "R11 - %016lx, R12 - %016lx, R13 - %016lx\n", + SystemContext.SystemContextX64->R11, + SystemContext.SystemContextX64->R12, + SystemContext.SystemContextX64->R13 + ); + InternalPrintMessage ( + "R14 - %016lx, R15 - %016lx\n", + SystemContext.SystemContextX64->R14, + SystemContext.SystemContextX64->R15 + ); + InternalPrintMessage ( + "DS - %016lx, ES - %016lx, FS - %016lx\n", + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs + ); + InternalPrintMessage ( + "GS - %016lx, SS - %016lx\n", + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss + ); + InternalPrintMessage ( + "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n", + SystemContext.SystemContextX64->Cr0, + SystemContext.SystemContextX64->Cr2, + SystemContext.SystemContextX64->Cr3 + ); + InternalPrintMessage ( + "CR4 - %016lx, CR8 - %016lx\n", + SystemContext.SystemContextX64->Cr4, + SystemContext.SystemContextX64->Cr8 + ); + InternalPrintMessage ( + "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n", + SystemContext.SystemContextX64->Dr0, + SystemContext.SystemContextX64->Dr1, + SystemContext.SystemContextX64->Dr2 + ); + InternalPrintMessage ( + "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n", + SystemContext.SystemContextX64->Dr3, + SystemContext.SystemContextX64->Dr6, + SystemContext.SystemContextX64->Dr7 + ); + InternalPrintMessage ( + "GDTR - %016lx %016lx, LDTR - %016lx\n", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Ldtr + ); + InternalPrintMessage ( + "IDTR - %016lx %016lx, TR - %016lx\n", + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1], + SystemContext.SystemContextX64->Tr + ); + InternalPrintMessage ( + "FXSAVE_STATE - %016lx\n", + &SystemContext.SystemContextX64->FxSaveState + ); + + // + // Find module image base and module entry point by RIP + // + ImageBase = FindModuleImageBase (SystemContext.SystemContextX64->Rip, &EntryPoint); + if (ImageBase != 0) { + InternalPrintMessage ( + " (ImageBase=%016lx, EntryPoint=%016lx) !!!!\n", + ImageBase, + EntryPoint + ); + } +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S new file mode 100644 index 0000000000..cd101475a7 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S @@ -0,0 +1,406 @@ +#------------------------------------------------------------------------------ ; +# Copyright (c) 2012, 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: +# +# ExceptionHandlerAsm.S +# +# Abstract: +# +# x64 CPU Exception Handler +# +# Notes: +# +#------------------------------------------------------------------------------ + + +#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions + +ASM_GLOBAL ASM_PFX(CommonExceptionHandler) +ASM_GLOBAL ASM_PFX(CommonInterruptEntry) + + +.text + +# +# point to the external interrupt vector table +# +Exception0Handle: + pushq $0 + jmp ASM_PFX(CommonInterruptEntry) +Exception1Handle: + pushq $1 + jmp ASM_PFX(CommonInterruptEntry) +Exception2Handle: + pushq $2 + jmp ASM_PFX(CommonInterruptEntry) +Exception3Handle: + pushq $3 + jmp ASM_PFX(CommonInterruptEntry) +Exception4Handle: + pushq $4 + jmp ASM_PFX(CommonInterruptEntry) +Exception5Handle: + pushq $5 + jmp ASM_PFX(CommonInterruptEntry) +Exception6Handle: + pushq $6 + jmp ASM_PFX(CommonInterruptEntry) +Exception7Handle: + pushq $7 + jmp ASM_PFX(CommonInterruptEntry) +Exception8Handle: + pushq $8 + jmp ASM_PFX(CommonInterruptEntry) +Exception9Handle: + pushq $9 + jmp ASM_PFX(CommonInterruptEntry) +Exception10Handle: + pushq $10 + jmp ASM_PFX(CommonInterruptEntry) +Exception11Handle: + pushq $11 + jmp ASM_PFX(CommonInterruptEntry) +Exception12Handle: + pushq $12 + jmp ASM_PFX(CommonInterruptEntry) +Exception13Handle: + pushq $13 + jmp ASM_PFX(CommonInterruptEntry) +Exception14Handle: + pushq $14 + jmp ASM_PFX(CommonInterruptEntry) +Exception15Handle: + pushq $15 + jmp ASM_PFX(CommonInterruptEntry) +Exception16Handle: + pushq $16 + jmp ASM_PFX(CommonInterruptEntry) +Exception17Handle: + pushq $17 + jmp ASM_PFX(CommonInterruptEntry) +Exception18Handle: + pushq $18 + jmp ASM_PFX(CommonInterruptEntry) +Exception19Handle: + pushq $19 + jmp ASM_PFX(CommonInterruptEntry) +Exception20Handle: + pushq $20 + jmp ASM_PFX(CommonInterruptEntry) +Exception21Handle: + pushq $21 + jmp ASM_PFX(CommonInterruptEntry) +Exception22Handle: + pushq $22 + jmp ASM_PFX(CommonInterruptEntry) +Exception23Handle: + pushq $23 + jmp ASM_PFX(CommonInterruptEntry) +Exception24Handle: + pushq $24 + jmp ASM_PFX(CommonInterruptEntry) +Exception25Handle: + pushq $25 + jmp ASM_PFX(CommonInterruptEntry) +Exception26Handle: + pushq $26 + jmp ASM_PFX(CommonInterruptEntry) +Exception27Handle: + pushq $27 + jmp ASM_PFX(CommonInterruptEntry) +Exception28Handle: + pushq $28 + jmp ASM_PFX(CommonInterruptEntry) +Exception29Handle: + pushq $29 + jmp ASM_PFX(CommonInterruptEntry) +Exception30Handle: + pushq $30 + jmp ASM_PFX(CommonInterruptEntry) +Exception31Handle: + pushq $31 + jmp ASM_PFX(CommonInterruptEntry) + + +#---------------------------------------; +# CommonInterruptEntry ; +#---------------------------------------; +# The follow algorithm is used for the common interrupt routine. + +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 + # + xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number. + cmp $32, %ecx # Intel reserved vector for exceptions? + jae NoErrorCode + pushq %rax + leaq ASM_PFX(mErrorCodeFlag)(%rip), %rax + bt %ecx, (%rax) + popq %rax + jc CommonInterruptEntry_al_0000 + +NoErrorCode: + + # + # Push a dummy error code on the stack + # to maintain coherent stack map + # + pushq (%rsp) + movq $0, 8(%rsp) +CommonInterruptEntry_al_0000: + pushq %rbp + movq %rsp, %rbp + + # + # 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; + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq 8(%rbp) # RCX + pushq %rdx + pushq %rbx + pushq 48(%rbp) # RSP + pushq (%rbp) # RBP + pushq %rsi + pushq %rdi + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzwq 56(%rbp), %rax + pushq %rax # for ss + movzwq 32(%rbp), %rax + pushq %rax # for cs + movl %ds, %eax + pushq %rax + movl %es, %eax + pushq %rax + movl %fs, %eax + pushq %rax + movl %gs, %eax + pushq %rax + + movq %rcx, 8(%rbp) # save vector number + +#; UINT64 Rip; + pushq 24(%rbp) + +#; UINT64 Gdtr[2], Idtr[2]; + xorq %rax, %rax + pushq %rax + pushq %rax + sidt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + + xorq %rax, %rax + pushq %rax + pushq %rax + sgdt (%rsp) + xchgq 2(%rsp), %rax + xchgq (%rsp), %rax + xchgq 8(%rsp), %rax + +#; UINT64 Ldtr, Tr; + xorq %rax, %rax + str %ax + pushq %rax + sldt %ax + pushq %rax + +#; UINT64 RFlags; + pushq 40(%rbp) + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + movq %cr8, %rax + pushq %rax + movq %cr4, %rax + orq $0x208, %rax + movq %rax, %cr4 + pushq %rax + mov %cr3, %rax + pushq %rax + mov %cr2, %rax + pushq %rax + xorq %rax, %rax + pushq %rax + mov %cr0, %rax + pushq %rax + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movq %dr7, %rax + pushq %rax + movq %dr6, %rax + pushq %rax + movq %dr3, %rax + pushq %rax + movq %dr2, %rax + pushq %rax + movq %dr1, %rax + pushq %rax + movq %dr0, %rax + pushq %rax + +#; FX_SAVE_STATE_X64 FxSaveState; + subq $512, %rsp + movq %rsp, %rdi + .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] + +#; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +#; UINT32 ExceptionData; + pushq 16(%rbp) + +#; Prepare parameter and call + mov 8(%rbp), %rcx + mov %rsp, %rdx + # + # Per X64 calling convention, allocate maximum parameter stack space + # and make sure RSP is 16-byte aligned + # + subq $40, %rsp + call ASM_PFX(CommonExceptionHandler) + addq $40, %rsp + + cli +#; UINT64 ExceptionData; + addq $8, %rsp + +#; FX_SAVE_STATE_X64 FxSaveState; + + movq %rsp, %rsi + .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] + addq $512, %rsp + +#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +#; Skip restoration of DRx registers to support in-circuit emualators +#; or debuggers set breakpoint in interrupt/exception context + addq $48, %rsp + +#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + popq %rax + movq %rax, %cr0 + addq $8, %rsp # not for Cr1 + popq %rax + movq %rax, %cr2 + popq %rax + movq %rax, %cr3 + popq %rax + movq %rax, %cr4 + popq %rax + movq %rax, %cr8 + +#; UINT64 RFlags; + popq 40(%rbp) + +#; UINT64 Ldtr, Tr; +#; UINT64 Gdtr[2], Idtr[2]; +#; Best not let anyone mess with these particular registers... + addq $48, %rsp + +#; UINT64 Rip; + popq 24(%rbp) + +#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + popq %rax + # mov %rax, %gs ; not for gs + popq %rax + # mov %rax, %fs ; not for fs + # (X64 will not use fs and gs, so we do not restore it) + popq %rax + movl %eax, %es + popq %rax + movl %eax, %ds + popq 32(%rbp) # for cs + popq 56(%rbp) # for ss + +#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + popq %rdi + popq %rsi + addq $8, %rsp # not for rbp + popq 48(%rbp) # for rsp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + movq %rbp, %rsp + popq %rbp + addq $16, %rsp + iretq + + +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +# comments here for definition of address map +ASM_GLOBAL ASM_PFX(GetTemplateAddressMap) +ASM_PFX(GetTemplateAddressMap): + + movabsq $Exception0Handle, %rax + movq %rax, (%rcx) + movq $(Exception1Handle - Exception0Handle), 0x08(%rcx) + + ret + +#END + + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm new file mode 100644 index 0000000000..1fa7cb8702 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm @@ -0,0 +1,407 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012, 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: +; +; ExceptionHandlerAsm.Asm +; +; Abstract: +; +; x64 CPU Exception Handler +; +; Notes: +; +;------------------------------------------------------------------------------ + +; +; CommonExceptionHandler() +; +CommonExceptionHandler PROTO C + +EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions + +data SEGMENT + +CommonEntryAddr dq CommonInterruptEntry; + +.code + +Exception0Handle: + push 0 + jmp qword ptr [CommonEntryAddr] +Exception1Handle: + push 1 + jmp qword ptr [CommonEntryAddr] +Exception2Handle: + push 2 + jmp qword ptr [CommonEntryAddr] +Exception3Handle: + push 3 + jmp qword ptr [CommonEntryAddr] +Exception4Handle: + push 4 + jmp qword ptr [CommonEntryAddr] +Exception5Handle: + push 5 + jmp qword ptr [CommonEntryAddr] +Exception6Handle: + push 6 + jmp qword ptr [CommonEntryAddr] +Exception7Handle: + push 7 + jmp qword ptr [CommonEntryAddr] +Exception8Handle: + push 8 + jmp qword ptr [CommonEntryAddr] +Exception9Handle: + push 9 + jmp qword ptr [CommonEntryAddr] +Exception10Handle: + push 10 + jmp qword ptr [CommonEntryAddr] +Exception11Handle: + push 11 + jmp qword ptr [CommonEntryAddr] +Exception12Handle: + push 12 + jmp qword ptr [CommonEntryAddr] +Exception13Handle: + push 13 + jmp qword ptr [CommonEntryAddr] +Exception14Handle: + push 14 + jmp qword ptr [CommonEntryAddr] +Exception15Handle: + push 15 + jmp qword ptr [CommonEntryAddr] +Exception16Handle: + push 16 + jmp qword ptr [CommonEntryAddr] +Exception17Handle: + push 17 + jmp qword ptr [CommonEntryAddr] +Exception18Handle: + push 18 + jmp qword ptr [CommonEntryAddr] +Exception19Handle: + push 19 + jmp qword ptr [CommonEntryAddr] +Exception20Handle: + push 20 + jmp qword ptr [CommonEntryAddr] +Exception21Handle: + push 21 + jmp qword ptr [CommonEntryAddr] +Exception22Handle: + push 22 + jmp qword ptr [CommonEntryAddr] +Exception23Handle: + push 23 + jmp qword ptr [CommonEntryAddr] +Exception24Handle: + push 24 + jmp qword ptr [CommonEntryAddr] +Exception25Handle: + push 25 + jmp qword ptr [CommonEntryAddr] +Exception26Handle: + push 26 + jmp qword ptr [CommonEntryAddr] +Exception27Handle: + push 27 + jmp qword ptr [CommonEntryAddr] +Exception28Handle: + push 28 + jmp qword ptr [CommonEntryAddr] +Exception29Handle: + push 29 + jmp qword ptr [CommonEntryAddr] +Exception30Handle: + push 30 + jmp qword ptr [CommonEntryAddr] +Exception31Handle: + push 31 + jmp qword ptr [CommonEntryAddr] + +;CommonInterruptEntrypoint: +;---------------------------------------; +; _CommonEntry ; +;----------------------------------------------------------------------------; +; The follow algorithm is used for the common interrupt routine. +; Entry from each interrupt with a push eax and eax=interrupt number + +;---------------------------------------; +; 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. + 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 + mov rax, dr6 + push 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] + +;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push qword ptr [rbp + 16] + +;; 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 + mov rax, CommonExceptionHandler + call rax + add rsp, 4 * 8 + 8 + + 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; +;; Skip restoration of DRx registers to support in-circuit emualators +;; or debuggers set breakpoint in interrupt/exception context + add rsp, 8 * 6 + +;; 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 + +;------------------------------------------------------------------------------------- +; GetTemplateAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +; comments here for definition of address map +GetTemplateAddressMap PROC + mov rax, offset Exception0Handle + mov qword ptr [rcx], rax + mov qword ptr [rcx+8h], Exception1Handle - Exception0Handle + ret +GetTemplateAddressMap ENDP + +END diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 8d049bbc82..73dbbaf3a2 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -1,7 +1,7 @@ ## @file # UefiCpuPkg Package # -# Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2012, 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 @@ -85,5 +85,7 @@ UefiCpuPkg/Library/MtrrLib/MtrrLib.inf UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf + UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf -- 2.39.2