]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
UefiCpuPkg: Simplify the implementation when separate exception stacks
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ArchExceptionHandler.c
index 194d3a499b264818450970415fa18bb74c6acfc2..8c398ebc5b8ad917bd041bc0dc48966c0b466da1 100644 (file)
@@ -104,108 +104,97 @@ 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
 **/\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
   IA32_DESCRIPTOR                 Idtr;\r
   IA32_IDT_GATE_DESCRIPTOR        *IdtTable;\r
   IA32_TSS_DESCRIPTOR             *TssDesc;\r
+  IA32_TSS_DESCRIPTOR             *TssDescBase;\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
+  UINT8                           *StackSwitchExceptions;\r
+  UINTN                           NeedBufferSize;\r
   EXCEPTION_HANDLER_TEMPLATE_MAP  TemplateMap;\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
+  if (BufferSize == 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
+  // Total needed size includes stack size, new GDT table size, TSS size.\r
+  // Add another DESCRIPTOR size for alignment requiremet.\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
-\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
+  //    |    Current task descriptor   |\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    |  Exception task descriptors  |  X ExceptionNumber\r
+  //    |                              |\r
+  //    --------------------------------\r
+  //    |  Current task-state segment  |\r
+  //    --------------------------------\r
+  //    |                              |\r
+  //    | Exception task-state segment |  X ExceptionNumber\r
+  //    |                              |\r
+  //    --------------------------------\r
   //\r
-  // We need one descriptor and one TSS for current task and every exception\r
-  // specified.\r
-  //\r
-  if (StackSwitchData->ExceptionTssDescSize <\r
-      sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->StackSwitchExceptionNumber + 1))\r
-  {\r
-    return EFI_INVALID_PARAMETER;\r
+  AsmReadGdtr (&Gdtr);\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 (StackSwitchData->ExceptionTssSize <\r
-      sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->StackSwitchExceptionNumber + 1))\r
-  {\r
+  if (Buffer == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  TssDesc = StackSwitchData->ExceptionTssDesc;\r
-  Tss     = StackSwitchData->ExceptionTss;\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 +\r
-            sizeof (IA32_TSS_DESCRIPTOR) *\r
-            (StackSwitchData->StackSwitchExceptionNumber + 1) -\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
-  }\r
-\r
-  if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {\r
-    Idtr.Base = (UINTN)StackSwitchData->IdtTable;\r
-  }\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
+  TssDescBase           = TssDesc;\r
 \r
-  if (StackSwitchData->IdtTableSize > 0) {\r
-    Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);\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
@@ -226,10 +215,10 @@ ArchSetupExceptionStack (
   // Fixup exception task descriptor and task-state segment\r
   //\r
   AsmGetTssTemplateMap (&TemplateMap);\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
     TssDesc += 1;\r
     Tss     += 1;\r
 \r
@@ -250,7 +239,7 @@ ArchSetupExceptionStack (
     //\r
     // Fixup TSS\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
@@ -270,7 +259,7 @@ ArchSetupExceptionStack (
     Tss->FS     = AsmReadFs ();\r
     Tss->GS     = AsmReadGs ();\r
 \r
-    StackTop -= StackSwitchData->KnownGoodStackSize;\r
+    StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;\r
 \r
     //\r
     // Update IDT to use Task Gate for given exception\r
@@ -290,12 +279,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)TssDescBase - Gdtr.Base));\r
 \r
   return EFI_SUCCESS;\r
 }\r