]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
UefiCpuPkg: Simplify InitializeSeparateExceptionStacks
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / PeiCpuException.c
index 494c2ab4332a85e796d6a7d773cd797415c7f0e6..52ec0fb8033b89b590c258feda4e36b0a733eff6 100644 (file)
@@ -151,25 +151,104 @@ InitializeCpuExceptionHandlers (
 \r
 /**\r
   Setup separate stacks for certain exception handlers.\r
+  If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
 \r
-  InitData is optional and processor arch dependent.\r
-\r
-  @param[in]  InitData      Pointer to data optional for information about how\r
-                            to assign stacks for certain exception handlers.\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_UNSUPPORTED         This function is not supported.\r
-\r
+  @retval EFI_BUFFER_TOO_SMALL    This BufferSize is too small.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 InitializeSeparateExceptionStacks (\r
-  IN CPU_EXCEPTION_INIT_DATA  *InitData OPTIONAL\r
+  IN     VOID   *Buffer,\r
+  IN OUT UINTN  *BufferSize\r
   )\r
 {\r
-  if (InitData == NULL) {\r
+  CPU_EXCEPTION_INIT_DATA  EssData;\r
+  IA32_DESCRIPTOR          Idtr;\r
+  IA32_DESCRIPTOR          Gdtr;\r
+  UINTN                    NeedBufferSize;\r
+  UINTN                    StackTop;\r
+  UINT8                    *NewGdtTable;\r
+\r
+  //\r
+  // X64 needs only one TSS of current task working for all exceptions\r
+  // because of its IST feature. IA32 needs one TSS for each exception\r
+  // in addition to current task. To simplify the code, we report the\r
+  // needed memory for IA32 case to cover both IA32 and X64 exception\r
+  // stack switch.\r
+  //\r
+  // Layout of memory needed for each processor:\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
+\r
+  if ((Buffer == NULL) && (BufferSize == NULL)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  return ArchSetupExceptionStack (InitData);\r
+  if (BufferSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AsmReadGdtr (&Gdtr);\r
+  //\r
+  // Total needed size includes stack size, new GDT table size, TSS size.\r
+  // Add another DESCRIPTOR size for alignment requiremet.\r
+  //\r
+  NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+                   CPU_TSS_DESC_SIZE + Gdtr.Limit + 1 +\r
+                   CPU_TSS_SIZE +\r
+                   sizeof (IA32_TSS_DESCRIPTOR);\r
+  if (*BufferSize < NeedBufferSize) {\r
+    *BufferSize = NeedBufferSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  StackTop    = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+  NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
+\r
+  AsmReadIdtr (&Idtr);\r
+  EssData.X64.Revision                   = CPU_EXCEPTION_INIT_DATA_REV;\r
+  EssData.X64.KnownGoodStackTop          = StackTop;\r
+  EssData.X64.KnownGoodStackSize         = CPU_KNOWN_GOOD_STACK_SIZE;\r
+  EssData.X64.StackSwitchExceptions      = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+  EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
+  EssData.X64.IdtTable                   = (VOID *)Idtr.Base;\r
+  EssData.X64.IdtTableSize               = Idtr.Limit + 1;\r
+  EssData.X64.GdtTable                   = NewGdtTable;\r
+  EssData.X64.GdtTableSize               = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;\r
+  EssData.X64.ExceptionTssDesc           = NewGdtTable + Gdtr.Limit + 1;\r
+  EssData.X64.ExceptionTssDescSize       = CPU_TSS_DESC_SIZE;\r
+  EssData.X64.ExceptionTss               = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
+  EssData.X64.ExceptionTssSize           = CPU_TSS_SIZE;\r
+\r
+  return ArchSetupExceptionStack (&EssData);\r
 }\r