/** @file\r
- x64 CPU Exception Hanlder.\r
+ x64 CPU Exception Handler.\r
\r
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "CpuExceptionCommon.h"\r
\r
/**\r
- Internal function to setup CPU exception handlers.\r
+ Return address map of exception handler template so that C code can generate\r
+ exception tables.\r
+\r
+ @param IdtEntry Pointer to IDT entry to be updated.\r
+ @param InterruptHandler IDT handler value.\r
+**/\r
+VOID\r
+ArchUpdateIdtEntry (\r
+ OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,\r
+ IN UINTN InterruptHandler\r
+ )\r
+{\r
+ IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;\r
+ IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);\r
+ IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);\r
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
+}\r
+\r
+/**\r
+ Read IDT handler value from IDT entry.\r
+\r
+ @param IdtEntry Pointer to IDT entry to be read.\r
+\r
+**/\r
+UINTN\r
+ArchGetIdtHandler (\r
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry\r
+ )\r
+{\r
+ return IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16) +\r
+ (((UINTN)IdtEntry->Bits.OffsetUpper) << 32);\r
+}\r
+\r
+/**\r
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
\r
+ @param[in] ExceptionType Exception type.\r
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+ @param[in] ExceptionHandlerData Pointer to exception handler data.\r
**/\r
VOID\r
-InternalSetupCpuExceptionHandlers (\r
- VOID\r
+ArchSaveExceptionContext (\r
+ IN UINTN ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext,\r
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
)\r
{\r
- IA32_DESCRIPTOR IdtDescriptor;\r
- UINTN IdtSize;\r
- EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
- UINT16 CodeSegment;\r
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
- UINTN Index;\r
- UINTN InterruptHandler;\r
+ IA32_EFLAGS32 Eflags;\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
+\r
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
+ //\r
+ // Save Exception context in global variable in first entry of the exception handler.\r
+ // So when original exception handler returns to the new exception handler (second entry),\r
+ // the Eflags/Cs/Eip/ExceptionData can be used.\r
+ //\r
+ ReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss;\r
+ ReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp;\r
+ ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags;\r
+ ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs;\r
+ ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip;\r
+ ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;\r
+ //\r
+ // Clear IF flag to avoid old IDT handler enable interrupt by IRET\r
+ //\r
+ Eflags.UintN = SystemContext.SystemContextX64->Rflags;\r
+ Eflags.Bits.IF = 0;\r
+ SystemContext.SystemContextX64->Rflags = Eflags.UintN;\r
+ //\r
+ // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.\r
+ //\r
+ SystemContext.SystemContextX64->Rip = (UINTN)ReservedVectors[ExceptionType].HookAfterStubHeaderCode;\r
+}\r
+\r
+/**\r
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
+\r
+ @param[in] ExceptionType Exception type.\r
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+ @param[in] ExceptionHandlerData Pointer to exception handler data.\r
+**/\r
+VOID\r
+ArchRestoreExceptionContext (\r
+ IN UINTN ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext,\r
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
+ )\r
+{\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
+\r
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
+ SystemContext.SystemContextX64->Ss = ReservedVectors[ExceptionType].OldSs;\r
+ SystemContext.SystemContextX64->Rsp = ReservedVectors[ExceptionType].OldSp;\r
+ SystemContext.SystemContextX64->Rflags = ReservedVectors[ExceptionType].OldFlags;\r
+ SystemContext.SystemContextX64->Cs = ReservedVectors[ExceptionType].OldCs;\r
+ SystemContext.SystemContextX64->Rip = ReservedVectors[ExceptionType].OldIp;\r
+ SystemContext.SystemContextX64->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;\r
+}\r
+\r
+/**\r
+ Setup separate stack for given exceptions.\r
+\r
+ @param[in] StackSwitchData Pointer to data required for setuping up\r
+ stack switch.\r
+\r
+ @retval EFI_SUCCESS The exceptions have been successfully\r
+ initialized with new stack.\r
+ @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.\r
+\r
+**/\r
+EFI_STATUS\r
+ArchSetupExceptionStack (\r
+ IN CPU_EXCEPTION_INIT_DATA *StackSwitchData\r
+ )\r
+{\r
+ IA32_DESCRIPTOR Gdtr;\r
+ IA32_DESCRIPTOR Idtr;\r
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
+ IA32_TSS_DESCRIPTOR *TssDesc;\r
+ IA32_TASK_STATE_SEGMENT *Tss;\r
+ UINTN StackTop;\r
+ UINTN Index;\r
+ UINTN Vector;\r
+ UINTN TssBase;\r
+ UINTN GdtSize;\r
+\r
+ if ((StackSwitchData == NULL) ||\r
+ (StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV) ||\r
+ (StackSwitchData->X64.KnownGoodStackTop == 0) ||\r
+ (StackSwitchData->X64.KnownGoodStackSize == 0) ||\r
+ (StackSwitchData->X64.StackSwitchExceptions == NULL) ||\r
+ (StackSwitchData->X64.StackSwitchExceptionNumber == 0) ||\r
+ (StackSwitchData->X64.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||\r
+ (StackSwitchData->X64.GdtTable == NULL) ||\r
+ (StackSwitchData->X64.IdtTable == NULL) ||\r
+ (StackSwitchData->X64.ExceptionTssDesc == NULL) ||\r
+ (StackSwitchData->X64.ExceptionTss == NULL))\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The caller is responsible for that the GDT table, no matter the existing\r
+ // one or newly allocated, has enough space to hold descriptors for exception\r
+ // task-state segments.\r
+ //\r
+ if (((UINTN)StackSwitchData->X64.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((UINTN)StackSwitchData->X64.ExceptionTssDesc < (UINTN)(StackSwitchData->X64.GdtTable)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (((UINTN)StackSwitchData->X64.ExceptionTssDesc + StackSwitchData->X64.ExceptionTssDescSize) >\r
+ ((UINTN)(StackSwitchData->X64.GdtTable) + StackSwitchData->X64.GdtTableSize))\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // One task gate descriptor and one task-state segment are needed.\r
+ //\r
+ if (StackSwitchData->X64.ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (StackSwitchData->X64.ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Interrupt stack table supports only 7 vectors.\r
+ //\r
+ TssDesc = StackSwitchData->X64.ExceptionTssDesc;\r
+ Tss = StackSwitchData->X64.ExceptionTss;\r
+ if (StackSwitchData->X64.StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Initialize new GDT table and/or IDT table, if any\r
+ //\r
+ AsmReadIdtr (&Idtr);\r
+ AsmReadGdtr (&Gdtr);\r
+\r
+ GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -\r
+ (UINTN)(StackSwitchData->X64.GdtTable);\r
+ if ((UINTN)StackSwitchData->X64.GdtTable != Gdtr.Base) {\r
+ CopyMem (StackSwitchData->X64.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
+ Gdtr.Base = (UINTN)StackSwitchData->X64.GdtTable;\r
+ Gdtr.Limit = (UINT16)GdtSize - 1;\r
+ }\r
+\r
+ if ((UINTN)StackSwitchData->X64.IdtTable != Idtr.Base) {\r
+ Idtr.Base = (UINTN)StackSwitchData->X64.IdtTable;\r
+ }\r
+\r
+ if (StackSwitchData->X64.IdtTableSize > 0) {\r
+ Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);\r
+ }\r
\r
//\r
- // Read IDT descriptor and calculate IDT size\r
+ // Fixup current task descriptor. Task-state segment for current task will\r
+ // be filled by processor during task switching.\r
//\r
- AsmReadIdtr (&IdtDescriptor);\r
- IdtSize = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
- if (IdtSize > CPU_EXCEPTION_NUM) {\r
+ TssBase = (UINTN)Tss;\r
+\r
+ TssDesc->Uint128.Uint64 = 0;\r
+ TssDesc->Uint128.Uint64_1 = 0;\r
+ TssDesc->Bits.LimitLow = sizeof (IA32_TASK_STATE_SEGMENT) - 1;\r
+ TssDesc->Bits.BaseLow = (UINT16)TssBase;\r
+ TssDesc->Bits.BaseMidl = (UINT8)(TssBase >> 16);\r
+ TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;\r
+ TssDesc->Bits.P = 1;\r
+ TssDesc->Bits.LimitHigh = 0;\r
+ TssDesc->Bits.BaseMidh = (UINT8)(TssBase >> 24);\r
+ TssDesc->Bits.BaseHigh = (UINT32)(TssBase >> 32);\r
+\r
+ //\r
+ // Fixup exception task descriptor and task-state segment\r
+ //\r
+ ZeroMem (Tss, sizeof (*Tss));\r
+ StackTop = StackSwitchData->X64.KnownGoodStackTop - CPU_STACK_ALIGNMENT;\r
+ StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
+ IdtTable = StackSwitchData->X64.IdtTable;\r
+ for (Index = 0; Index < StackSwitchData->X64.StackSwitchExceptionNumber; ++Index) {\r
+ //\r
+ // Fixup IST\r
//\r
- // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
+ Tss->IST[Index] = StackTop;\r
+ StackTop -= StackSwitchData->X64.KnownGoodStackSize;\r
+\r
+ //\r
+ // Set the IST field to enable corresponding IST\r
//\r
- IdtSize = CPU_EXCEPTION_NUM;\r
+ Vector = StackSwitchData->X64.StackSwitchExceptions[Index];\r
+ if ((Vector >= CPU_EXCEPTION_NUM) ||\r
+ (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);\r
}\r
\r
//\r
- // Use current CS as the segment selector of interrupt gate in IDT\r
+ // Publish GDT\r
//\r
- CodeSegment = AsmReadCs ();\r
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
+ AsmWriteGdtr (&Gdtr);\r
\r
- GetTemplateAddressMap (&TemplateMap);\r
+ //\r
+ // Load current task\r
+ //\r
+ AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));\r
\r
- for (Index = 0; Index < IdtSize; Index ++) {\r
- InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize;\r
- IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;\r
- IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);\r
- IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);\r
- IdtEntry[Index].Bits.Selector = CodeSegment;\r
- IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
- }\r
+ //\r
+ // Publish IDT\r
+ //\r
+ AsmWriteIdtr (&Idtr);\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
- Common exception handler.\r
+ Display CPU information.\r
\r
@param ExceptionType Exception type.\r
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
**/\r
VOID\r
-DumpCpuContent (\r
- IN UINTN ExceptionType,\r
- IN EFI_SYSTEM_CONTEXT SystemContext\r
+EFIAPI\r
+DumpCpuContext (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
)\r
{\r
- UINTN ImageBase;\r
- UINTN EntryPoint;\r
-\r
InternalPrintMessage (\r
- "!!!! X64 Exception Type - %016lx CPU Apic ID - %08x !!!!\n",\r
+ "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",\r
ExceptionType,\r
+ GetExceptionNameStr (ExceptionType),\r
GetApicId ()\r
);\r
+ if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {\r
+ InternalPrintMessage (\r
+ "ExceptionData - %016lx",\r
+ SystemContext.SystemContextX64->ExceptionData\r
+ );\r
+ if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {\r
+ InternalPrintMessage (\r
+ " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_RSVD) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_US) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_WR) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_P) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_PK) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SS) != 0,\r
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SGX) != 0\r
+ );\r
+ }\r
+\r
+ InternalPrintMessage ("\n");\r
+ }\r
+\r
InternalPrintMessage (\r
"RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",\r
SystemContext.SystemContextX64->Rip,\r
SystemContext.SystemContextX64->Cs,\r
SystemContext.SystemContextX64->Rflags\r
);\r
- if (mErrorCodeFlag & (1 << ExceptionType)) {\r
- InternalPrintMessage (\r
- "ExceptionData - %016lx\n",\r
- SystemContext.SystemContextX64->ExceptionData\r
- );\r
- }\r
InternalPrintMessage (\r
"RAX - %016lx, RCX - %016lx, RDX - %016lx\n",\r
SystemContext.SystemContextX64->Rax,\r
SystemContext.SystemContextX64->Idtr[1],\r
SystemContext.SystemContextX64->Tr\r
);\r
- InternalPrintMessage (\r
+ InternalPrintMessage (\r
"FXSAVE_STATE - %016lx\n",\r
&SystemContext.SystemContextX64->FxSaveState\r
);\r
+}\r
+\r
+/**\r
+ Display CPU information.\r
\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+**/\r
+VOID\r
+DumpImageAndCpuContent (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ DumpCpuContext (ExceptionType, SystemContext);\r
//\r
- // Find module image base and module entry point by RIP\r
+ // Dump module image base and module entry point by RIP\r
//\r
- ImageBase = FindModuleImageBase (SystemContext.SystemContextX64->Rip, &EntryPoint);\r
- if (ImageBase != 0) {\r
- InternalPrintMessage (\r
- " (ImageBase=%016lx, EntryPoint=%016lx) !!!!\n",\r
- ImageBase,\r
- EntryPoint\r
- );\r
+ if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&\r
+ ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0))\r
+ {\r
+ //\r
+ // The RIP in SystemContext could not be used\r
+ // if it is page fault with I/D set.\r
+ //\r
+ DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));\r
+ } else {\r
+ DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);\r
}\r
}\r