]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
UefiCpuPkg: Simplify the implementation when separate exception stacks
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ArchExceptionHandler.c
index c14ac66c43c03f38d795715f1a4fb7518de19c91..80e9f08e5ba0ba436f5ffac9e4eed60cb958734b 100644 (file)
@@ -109,19 +109,22 @@ ArchRestoreExceptionContext (
 }\r
 \r
 /**\r
-  Setup separate stack for given exceptions.\r
+  Setup separate stacks for certain exception handlers.\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
+  @param[in]       Buffer        Point to buffer used to separate exception stack.\r
+  @param[in, out]  BufferSize    On input, it indicates the byte size of Buffer.\r
+                                 If the size is not enough, the return status will\r
+                                 be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+                                 will be the size it needs.\r
 \r
+  @retval EFI_SUCCESS             The stacks are assigned successfully.\r
+  @retval EFI_BUFFER_TOO_SMALL    This BufferSize is too small.\r
+  @retval EFI_UNSUPPORTED         This function is not supported.\r
 **/\r
 EFI_STATUS\r
 ArchSetupExceptionStack (\r
-  IN CPU_EXCEPTION_INIT_DATA  *StackSwitchData\r
+  IN     VOID   *Buffer,\r
+  IN OUT UINTN  *BufferSize\r
   )\r
 {\r
   IA32_DESCRIPTOR           Gdtr;\r
@@ -129,86 +132,75 @@ ArchSetupExceptionStack (
   IA32_IDT_GATE_DESCRIPTOR  *IdtTable;\r
   IA32_TSS_DESCRIPTOR       *TssDesc;\r
   IA32_TASK_STATE_SEGMENT   *Tss;\r
+  VOID                      *NewGdtTable;\r
   UINTN                     StackTop;\r
   UINTN                     Index;\r
   UINTN                     Vector;\r
   UINTN                     TssBase;\r
-  UINTN                     GdtSize;\r
-\r
-  if ((StackSwitchData == NULL) ||\r
-      (StackSwitchData->KnownGoodStackTop == 0) ||\r
-      (StackSwitchData->KnownGoodStackSize == 0) ||\r
-      (StackSwitchData->StackSwitchExceptions == NULL) ||\r
-      (StackSwitchData->StackSwitchExceptionNumber == 0) ||\r
-      (StackSwitchData->StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||\r
-      (StackSwitchData->GdtTable == NULL) ||\r
-      (StackSwitchData->IdtTable == NULL) ||\r
-      (StackSwitchData->ExceptionTssDesc == NULL) ||\r
-      (StackSwitchData->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->GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if ((UINTN)StackSwitchData->ExceptionTssDesc < (UINTN)(StackSwitchData->GdtTable)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (((UINTN)StackSwitchData->ExceptionTssDesc + StackSwitchData->ExceptionTssDescSize) >\r
-      ((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtTableSize))\r
-  {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  UINT8                     *StackSwitchExceptions;\r
+  UINTN                     NeedBufferSize;\r
 \r
-  //\r
-  // One task gate descriptor and one task-state segment are needed.\r
-  //\r
-  if (StackSwitchData->ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (StackSwitchData->ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {\r
+  if (BufferSize == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
   // Interrupt stack table supports only 7 vectors.\r
   //\r
-  TssDesc = StackSwitchData->ExceptionTssDesc;\r
-  Tss     = StackSwitchData->ExceptionTss;\r
-  if (StackSwitchData->StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {\r
-    return EFI_INVALID_PARAMETER;\r
+  if (CPU_STACK_SWITCH_EXCEPTION_NUMBER > ARRAY_SIZE (Tss->IST)) {\r
+    return EFI_UNSUPPORTED;\r
   }\r
 \r
   //\r
-  // Initialize new GDT table and/or IDT table, if any\r
+  // Total needed size includes stack size, new GDT table size, TSS size.\r
+  // Add another DESCRIPTOR size for alignment requiremet.\r
+  //\r
+  // Layout of memory needed for each processor:\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    |          Stack Size          |  X ExceptionNumber\r
+  //    |                              |\r
+  //    --------------------------------\r
+  //    |          Alignment           |  (just in case)\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    |         Original GDT         |\r
+  //    |                              |\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    |  Exception task descriptors  |  X 1\r
+  //    |                              |\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    | Exception task-state segment |  X 1\r
+  //    |                              |\r
+  //    --------------------------------\r
   //\r
-  AsmReadIdtr (&Idtr);\r
   AsmReadGdtr (&Gdtr);\r
-\r
-  GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -\r
-            (UINTN)(StackSwitchData->GdtTable);\r
-  if ((UINTN)StackSwitchData->GdtTable != Gdtr.Base) {\r
-    CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
-    Gdtr.Base  = (UINTN)StackSwitchData->GdtTable;\r
-    Gdtr.Limit = (UINT16)GdtSize - 1;\r
+  NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+                   sizeof (IA32_TSS_DESCRIPTOR) +\r
+                   Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +\r
+                   CPU_TSS_SIZE;\r
+\r
+  if (*BufferSize < NeedBufferSize) {\r
+    *BufferSize = NeedBufferSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
   }\r
 \r
-  if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {\r
-    Idtr.Base = (UINTN)StackSwitchData->IdtTable;\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (StackSwitchData->IdtTableSize > 0) {\r
-    Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);\r
-  }\r
+  AsmReadIdtr (&Idtr);\r
+  StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+  StackTop              = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+  NewGdtTable           = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
+  TssDesc               = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);\r
+  Tss                   = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);\r
+\r
+  CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
+  Gdtr.Base  = (UINTN)NewGdtTable;\r
+  Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);\r
 \r
   //\r
   // Fixup current task descriptor. Task-state segment for current task will\r
@@ -231,20 +223,20 @@ ArchSetupExceptionStack (
   // Fixup exception task descriptor and task-state segment\r
   //\r
   ZeroMem (Tss, sizeof (*Tss));\r
-  StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;\r
+  StackTop = StackTop - CPU_STACK_ALIGNMENT;\r
   StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
-  IdtTable = StackSwitchData->IdtTable;\r
-  for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {\r
+  IdtTable = (IA32_IDT_GATE_DESCRIPTOR  *)Idtr.Base;\r
+  for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {\r
     //\r
     // Fixup IST\r
     //\r
     Tss->IST[Index] = StackTop;\r
-    StackTop       -= StackSwitchData->KnownGoodStackSize;\r
+    StackTop       -= CPU_KNOWN_GOOD_STACK_SIZE;\r
 \r
     //\r
     // Set the IST field to enable corresponding IST\r
     //\r
-    Vector = StackSwitchData->StackSwitchExceptions[Index];\r
+    Vector = StackSwitchExceptions[Index];\r
     if ((Vector >= CPU_EXCEPTION_NUM) ||\r
         (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))\r
     {\r
@@ -262,12 +254,7 @@ ArchSetupExceptionStack (
   //\r
   // Load current task\r
   //\r
-  AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));\r
-\r
-  //\r
-  // Publish IDT\r
-  //\r
-  AsmWriteIdtr (&Idtr);\r
+  AsmWriteTr ((UINT16)((UINTN)TssDesc - Gdtr.Base));\r
 \r
   return EFI_SUCCESS;\r
 }\r