]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ArchExceptionHandler.c
index ee16ea856ad8a04b53f5ac7dfedbdf57aa53ab99..894c1cfb7533f4b0d44a06a11a72a2a8a6abe8fc 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   x64 CPU Exception Handler.\r
 \r
-  Copyright (c) 2012 - 2013, 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
@@ -29,7 +23,7 @@ ArchUpdateIdtEntry (
 {\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.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);\r
   IdtEntry->Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
 }\r
 \r
@@ -51,55 +45,226 @@ ArchGetIdtHandler (
 /**\r
   Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
 \r
-  @param ExceptionType  Exception type.\r
-  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.\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
 ArchSaveExceptionContext (\r
-  IN UINTN                ExceptionType,\r
-  IN EFI_SYSTEM_CONTEXT   SystemContext \r
+  IN UINTN                        ExceptionType,\r
+  IN EFI_SYSTEM_CONTEXT           SystemContext,\r
+  IN EXCEPTION_HANDLER_DATA       *ExceptionHandlerData\r
   )\r
 {\r
   IA32_EFLAGS32           Eflags;\r
+  RESERVED_VECTORS_DATA   *ReservedVectors;\r
+\r
+  ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
   //\r
-  // Save Exception context in global variable\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
-  mReservedVectors[ExceptionType].OldSs         = SystemContext.SystemContextX64->Ss;\r
-  mReservedVectors[ExceptionType].OldSp         = SystemContext.SystemContextX64->Rsp;\r
-  mReservedVectors[ExceptionType].OldFlags      = SystemContext.SystemContextX64->Rflags;\r
-  mReservedVectors[ExceptionType].OldCs         = SystemContext.SystemContextX64->Cs;\r
-  mReservedVectors[ExceptionType].OldIp         = SystemContext.SystemContextX64->Rip;\r
-  mReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;\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
+  Eflags.Bits.IF = 0;\r
   SystemContext.SystemContextX64->Rflags = Eflags.UintN;\r
   //\r
-  // Modify the EIP in stack, then old IDT handler will return to the stub code\r
+  // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.\r
   //\r
-  SystemContext.SystemContextX64->Rip = (UINTN) mReservedVectors[ExceptionType].HookAfterStubHeaderCode;\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 ExceptionType  Exception type.\r
-  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.\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 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
-  SystemContext.SystemContextX64->Ss            = mReservedVectors[ExceptionType].OldSs;\r
-  SystemContext.SystemContextX64->Rsp           = mReservedVectors[ExceptionType].OldSp;\r
-  SystemContext.SystemContextX64->Rflags        = mReservedVectors[ExceptionType].OldFlags;\r
-  SystemContext.SystemContextX64->Cs            = mReservedVectors[ExceptionType].OldCs;\r
-  SystemContext.SystemContextX64->Rip           = mReservedVectors[ExceptionType].OldIp;\r
-  SystemContext.SystemContextX64->ExceptionData = mReservedVectors[ExceptionType].ExceptionData;\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
+    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
+    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
+  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
+  if (StackSwitchData->X64.IdtTableSize > 0) {\r
+    Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);\r
+  }\r
+\r
+  //\r
+  // Fixup current task descriptor. Task-state segment for current task will\r
+  // be filled by processor during task switching.\r
+  //\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
+    Tss->IST[Index] = StackTop;\r
+    StackTop -= StackSwitchData->X64.KnownGoodStackSize;\r
+\r
+    //\r
+    // Set the IST field to enable corresponding IST\r
+    //\r
+    Vector = StackSwitchData->X64.StackSwitchExceptions[Index];\r
+    if (Vector >= CPU_EXCEPTION_NUM ||\r
+        Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {\r
+      continue;\r
+    }\r
+    IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);\r
+  }\r
+\r
+  //\r
+  // Publish GDT\r
+  //\r
+  AsmWriteGdtr (&Gdtr);\r
+\r
+  //\r
+  // Load current task\r
+  //\r
+  AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));\r
+\r
+  //\r
+  // Publish IDT\r
+  //\r
+  AsmWriteIdtr (&Idtr);\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -109,31 +274,44 @@ ArchRestoreExceptionContext (
   @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.\r
 **/\r
 VOID\r
-DumpCpuContent (\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
+    InternalPrintMessage ("\n");\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
@@ -214,20 +392,36 @@ DumpCpuContent (
     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
+    // 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