]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg: Simplify InitializeSeparateExceptionStacks
authorLiu, Zhiguang <Zhiguang.Liu@intel.com>
Tue, 9 Aug 2022 01:25:35 +0000 (09:25 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 9 Aug 2022 04:12:28 +0000 (04:12 +0000)
Hide the Exception implementation details in CpuExcetionHandlerLib and
caller only need to provide buffer

Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.c
MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
MdeModulePkg/Include/Library/CpuExceptionHandlerLib.h
MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c
UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c

index 2c7bc66aa72946290439bf1bcaa585a1b3988afc..a521c33f3281814c78220bf0a08e3a4c442966f8 100644 (file)
@@ -288,20 +288,23 @@ CommonCExceptionHandler (
 \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
   return EFI_SUCCESS;\r
index 0a1f3d79e2420eb1e7a224efdbceaddf5224e740..5733f0c8ec84b4fad5442b3e90648c67a91e4386 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   DXE Core Main Entry Point\r
 \r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>\r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -260,7 +260,7 @@ DxeMain (
   // Setup Stack Guard\r
   //\r
   if (PcdGetBool (PcdCpuStackGuard)) {\r
-    Status = InitializeSeparateExceptionStacks (NULL);\r
+    Status = InitializeSeparateExceptionStacks (NULL, NULL);\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 \r
index 9a495081f7ed9221f09ac7caf5d482cc31cf794b..8d44ed916ac29a208868c863a43ca38b63e51ee1 100644 (file)
@@ -104,20 +104,23 @@ 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
 /**\r
index 8aeedcb4d1378b88c4589c6f5e68624717814834..74908a379beb64476120fe864fd0ae2492578e5b 100644 (file)
@@ -83,20 +83,23 @@ DumpCpuContext (
 \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
   return EFI_UNSUPPORTED;\r
index e385f585c7f15f455086a19aa0f29a2f82f72e5e..f3ca813d2a1ce19c875dffcc8aa82c75b33df6d2 100644 (file)
@@ -596,23 +596,13 @@ CollectBistDataFromHob (
   }\r
 }\r
 \r
-/**\r
-  Get GDT register value.\r
-\r
-  This function is mainly for AP purpose because AP may have different GDT\r
-  table than BSP.\r
-\r
-  @param[in,out] Buffer  The pointer to private data buffer.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-GetGdtr (\r
-  IN OUT VOID  *Buffer\r
-  )\r
-{\r
-  AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);\r
-}\r
+//\r
+// Structure for InitializeSeparateExceptionStacks\r
+//\r
+typedef struct {\r
+  VOID     *Buffer;\r
+  UINTN    *BufferSize;\r
+} EXCEPTION_STACK_SWITCH_CONTEXT;\r
 \r
 /**\r
   Initializes CPU exceptions handlers for the sake of stack switch requirement.\r
@@ -629,27 +619,17 @@ InitializeExceptionStackSwitchHandlers (
   IN OUT VOID  *Buffer\r
   )\r
 {\r
-  CPU_EXCEPTION_INIT_DATA  *EssData;\r
-  IA32_DESCRIPTOR          Idtr;\r
-  EFI_STATUS               Status;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  *SwitchStackData;\r
 \r
-  EssData = Buffer;\r
-  //\r
-  // We don't plan to replace IDT table with a new one, but we should not assume\r
-  // the AP's IDT is the same as BSP's IDT either.\r
-  //\r
-  AsmReadIdtr (&Idtr);\r
-  EssData->Ia32.IdtTable     = (VOID *)Idtr.Base;\r
-  EssData->Ia32.IdtTableSize = Idtr.Limit + 1;\r
-  Status                     = InitializeSeparateExceptionStacks (EssData);\r
-  ASSERT_EFI_ERROR (Status);\r
+  SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\r
+  InitializeSeparateExceptionStacks (SwitchStackData->Buffer, SwitchStackData->BufferSize);\r
 }\r
 \r
 /**\r
   Initializes MP exceptions handlers for the sake of stack switch requirement.\r
 \r
   This function will allocate required resources required to setup stack switch\r
-  and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.\r
+  and pass them through SwitchStackData to each logic processor.\r
 \r
 **/\r
 VOID\r
@@ -657,129 +637,53 @@ InitializeMpExceptionStackSwitchHandlers (
   VOID\r
   )\r
 {\r
-  UINTN                    Index;\r
-  UINTN                    Bsp;\r
-  UINTN                    ExceptionNumber;\r
-  UINTN                    OldGdtSize;\r
-  UINTN                    NewGdtSize;\r
-  UINTN                    NewStackSize;\r
-  IA32_DESCRIPTOR          Gdtr;\r
-  CPU_EXCEPTION_INIT_DATA  EssData;\r
-  UINT8                    *GdtBuffer;\r
-  UINT8                    *StackTop;\r
-\r
-  ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);\r
-  NewStackSize    = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;\r
-\r
-  StackTop = AllocateRuntimeZeroPool (NewStackSize * mNumberOfProcessors);\r
-  ASSERT (StackTop != NULL);\r
-  StackTop += NewStackSize  * mNumberOfProcessors;\r
-\r
-  //\r
-  // The default exception handlers must have been initialized. Let's just skip\r
-  // it in this method.\r
-  //\r
-  EssData.Ia32.Revision            = CPU_EXCEPTION_INIT_DATA_REV;\r
-  EssData.Ia32.InitDefaultHandlers = FALSE;\r
-\r
-  EssData.Ia32.StackSwitchExceptions      = FixedPcdGetPtr (PcdCpuStackSwitchExceptionList);\r
-  EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;\r
-  EssData.Ia32.KnownGoodStackSize         = FixedPcdGet32 (PcdCpuKnownGoodStackSize);\r
+  UINTN                           Index;\r
+  UINTN                           Bsp;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  SwitchStackData;\r
+  UINTN                           BufferSize;\r
 \r
-  //\r
-  // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.\r
-  //\r
-  Gdtr.Base  = 0;\r
-  Gdtr.Limit = 0;\r
+  SwitchStackData.BufferSize = &BufferSize;\r
   MpInitLibWhoAmI (&Bsp);\r
+\r
   for (Index = 0; Index < mNumberOfProcessors; ++Index) {\r
-    //\r
-    // To support stack switch, we need to re-construct GDT but not IDT.\r
-    //\r
+    SwitchStackData.Buffer = NULL;\r
+    BufferSize             = 0;\r
+\r
     if (Index == Bsp) {\r
-      GetGdtr (&Gdtr);\r
+      InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
     } else {\r
       //\r
-      // AP might have different size of GDT from BSP.\r
+      // AP might need different buffer size from BSP.\r
       //\r
-      MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);\r
+      MpInitLibStartupThisAP (InitializeExceptionStackSwitchHandlers, Index, NULL, 0, (VOID *)&SwitchStackData, NULL);\r
     }\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. Since AP is not supposed to allocate\r
-    // memory, we have to do it in BSP. To simplify the code, we allocate\r
-    // memory for IA32 case to cover both IA32 and X64 exception stack\r
-    // switch.\r
-    //\r
-    // Layout of memory to allocate 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
-    OldGdtSize                        = Gdtr.Limit + 1;\r
-    EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *\r
-                                        (ExceptionNumber + 1);\r
-    EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *\r
-                                    (ExceptionNumber + 1);\r
-    NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +\r
-                 OldGdtSize +\r
-                 EssData.Ia32.ExceptionTssDescSize +\r
-                 EssData.Ia32.ExceptionTssSize;\r
-\r
-    GdtBuffer = AllocateRuntimeZeroPool (NewGdtSize);\r
-    ASSERT (GdtBuffer != NULL);\r
-\r
-    //\r
-    // Make sure GDT table alignment\r
-    //\r
-    EssData.Ia32.GdtTable     = ALIGN_POINTER (GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));\r
-    NewGdtSize               -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);\r
-    EssData.Ia32.GdtTableSize = NewGdtSize;\r
-\r
-    EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);\r
-    EssData.Ia32.ExceptionTss     = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +\r
-                                     EssData.Ia32.ExceptionTssDescSize);\r
+    if (BufferSize == 0) {\r
+      continue;\r
+    }\r
 \r
-    EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;\r
+    SwitchStackData.Buffer = AllocateRuntimeZeroPool (BufferSize);\r
+    ASSERT (SwitchStackData.Buffer != NULL);\r
     DEBUG ((\r
       DEBUG_INFO,\r
-      "Exception stack top[cpu%lu]: 0x%lX\n",\r
+      "Buffer[cpu%lu] for InitializeExceptionStackSwitchHandlers: 0x%lX with size 0x%x\n",\r
       (UINT64)(UINTN)Index,\r
-      (UINT64)(UINTN)StackTop\r
+      (UINT64)(UINTN)SwitchStackData.Buffer,\r
+      (UINT32)BufferSize\r
       ));\r
 \r
     if (Index == Bsp) {\r
-      InitializeExceptionStackSwitchHandlers (&EssData);\r
+      InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
     } else {\r
       MpInitLibStartupThisAP (\r
         InitializeExceptionStackSwitchHandlers,\r
         Index,\r
         NULL,\r
         0,\r
-        (VOID *)&EssData,\r
+        (VOID *)&SwitchStackData,\r
         NULL\r
         );\r
     }\r
-\r
-    StackTop -= NewStackSize;\r
   }\r
 }\r
 \r
index d4786979fa1b15a53affdebb516aa53971b9ecac..c0be11d3add472388da2f19fddc2a6ff7d3e6b3d 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   CPU PEI Module installs CPU Multiple Processor PPI.\r
 \r
-  Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -411,23 +411,13 @@ PeiWhoAmI (
   return MpInitLibWhoAmI (ProcessorNumber);\r
 }\r
 \r
-/**\r
-  Get GDT register value.\r
-\r
-  This function is mainly for AP purpose because AP may have different GDT\r
-  table than BSP.\r
-\r
-  @param[in,out] Buffer  The pointer to private data buffer.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-GetGdtr (\r
-  IN OUT VOID  *Buffer\r
-  )\r
-{\r
-  AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);\r
-}\r
+//\r
+// Structure for InitializeSeparateExceptionStacks\r
+//\r
+typedef struct {\r
+  VOID     *Buffer;\r
+  UINTN    *BufferSize;\r
+} EXCEPTION_STACK_SWITCH_CONTEXT;\r
 \r
 /**\r
   Initializes CPU exceptions handlers for the sake of stack switch requirement.\r
@@ -444,27 +434,17 @@ InitializeExceptionStackSwitchHandlers (
   IN OUT VOID  *Buffer\r
   )\r
 {\r
-  CPU_EXCEPTION_INIT_DATA  *EssData;\r
-  IA32_DESCRIPTOR          Idtr;\r
-  EFI_STATUS               Status;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  *SwitchStackData;\r
 \r
-  EssData = Buffer;\r
-  //\r
-  // We don't plan to replace IDT table with a new one, but we should not assume\r
-  // the AP's IDT is the same as BSP's IDT either.\r
-  //\r
-  AsmReadIdtr (&Idtr);\r
-  EssData->Ia32.IdtTable     = (VOID *)Idtr.Base;\r
-  EssData->Ia32.IdtTableSize = Idtr.Limit + 1;\r
-  Status                     = InitializeSeparateExceptionStacks (EssData);\r
-  ASSERT_EFI_ERROR (Status);\r
+  SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\r
+  InitializeSeparateExceptionStacks (SwitchStackData->Buffer, SwitchStackData->BufferSize);\r
 }\r
 \r
 /**\r
   Initializes MP exceptions handlers for the sake of stack switch requirement.\r
 \r
   This function will allocate required resources required to setup stack switch\r
-  and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.\r
+  and pass them through SwitchStackData to each logic processor.\r
 \r
 **/\r
 VOID\r
@@ -472,148 +452,60 @@ InitializeMpExceptionStackSwitchHandlers (
   VOID\r
   )\r
 {\r
-  EFI_STATUS               Status;\r
-  UINTN                    Index;\r
-  UINTN                    Bsp;\r
-  UINTN                    ExceptionNumber;\r
-  UINTN                    OldGdtSize;\r
-  UINTN                    NewGdtSize;\r
-  UINTN                    NewStackSize;\r
-  IA32_DESCRIPTOR          Gdtr;\r
-  CPU_EXCEPTION_INIT_DATA  EssData;\r
-  UINT8                    *GdtBuffer;\r
-  UINT8                    *StackTop;\r
-  UINTN                    NumberOfProcessors;\r
+  UINTN                           Index;\r
+  UINTN                           Bsp;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  SwitchStackData;\r
+  UINTN                           BufferSize;\r
+  UINTN                           NumberOfProcessors;\r
 \r
   if (!PcdGetBool (PcdCpuStackGuard)) {\r
     return;\r
   }\r
 \r
+  SwitchStackData.BufferSize = &BufferSize;\r
   MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);\r
   MpInitLibWhoAmI (&Bsp);\r
 \r
-  ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);\r
-  NewStackSize    = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;\r
-\r
-  StackTop = AllocatePages (EFI_SIZE_TO_PAGES (NewStackSize * NumberOfProcessors));\r
-  ASSERT (StackTop != NULL);\r
-  if (StackTop == NULL) {\r
-    return;\r
-  }\r
-\r
-  StackTop += NewStackSize  * NumberOfProcessors;\r
-\r
-  //\r
-  // The default exception handlers must have been initialized. Let's just skip\r
-  // it in this method.\r
-  //\r
-  EssData.Ia32.Revision            = CPU_EXCEPTION_INIT_DATA_REV;\r
-  EssData.Ia32.InitDefaultHandlers = FALSE;\r
-\r
-  EssData.Ia32.StackSwitchExceptions      = FixedPcdGetPtr (PcdCpuStackSwitchExceptionList);\r
-  EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;\r
-  EssData.Ia32.KnownGoodStackSize         = FixedPcdGet32 (PcdCpuKnownGoodStackSize);\r
-\r
-  //\r
-  // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.\r
-  //\r
-  Gdtr.Base  = 0;\r
-  Gdtr.Limit = 0;\r
   for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
-    //\r
-    // To support stack switch, we need to re-construct GDT but not IDT.\r
-    //\r
+    SwitchStackData.Buffer = NULL;\r
+    BufferSize             = 0;\r
+\r
     if (Index == Bsp) {\r
-      GetGdtr (&Gdtr);\r
+      InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
     } else {\r
       //\r
-      // AP might have different size of GDT from BSP.\r
+      // AP might need different buffer size from BSP.\r
       //\r
-      MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);\r
+      MpInitLibStartupThisAP (InitializeExceptionStackSwitchHandlers, Index, NULL, 0, (VOID *)&SwitchStackData, NULL);\r
     }\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. Since AP is not supposed to allocate\r
-    // memory, we have to do it in BSP. To simplify the code, we allocate\r
-    // memory for IA32 case to cover both IA32 and X64 exception stack\r
-    // switch.\r
-    //\r
-    // Layout of memory to allocate 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
-    OldGdtSize                        = Gdtr.Limit + 1;\r
-    EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *\r
-                                        (ExceptionNumber + 1);\r
-    EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *\r
-                                    (ExceptionNumber + 1);\r
-    NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +\r
-                 OldGdtSize +\r
-                 EssData.Ia32.ExceptionTssDescSize +\r
-                 EssData.Ia32.ExceptionTssSize;\r
-\r
-    Status = PeiServicesAllocatePool (\r
-               NewGdtSize,\r
-               (VOID **)&GdtBuffer\r
-               );\r
-    ASSERT (GdtBuffer != NULL);\r
-    if (EFI_ERROR (Status)) {\r
-      ASSERT_EFI_ERROR (Status);\r
-      return;\r
+    if (BufferSize == 0) {\r
+      continue;\r
     }\r
 \r
-    //\r
-    // Make sure GDT table alignment\r
-    //\r
-    EssData.Ia32.GdtTable     = ALIGN_POINTER (GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));\r
-    NewGdtSize               -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);\r
-    EssData.Ia32.GdtTableSize = NewGdtSize;\r
-\r
-    EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);\r
-    EssData.Ia32.ExceptionTss     = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +\r
-                                     EssData.Ia32.ExceptionTssDescSize);\r
-\r
-    EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;\r
+    SwitchStackData.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
+    ASSERT (SwitchStackData.Buffer != NULL);\r
+    ZeroMem (SwitchStackData.Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (BufferSize)));\r
     DEBUG ((\r
       DEBUG_INFO,\r
-      "Exception stack top[cpu%lu]: 0x%lX\n",\r
+      "Buffer[cpu%lu] for InitializeExceptionStackSwitchHandlers: 0x%lX with size 0x%x\n",\r
       (UINT64)(UINTN)Index,\r
-      (UINT64)(UINTN)StackTop\r
+      (UINT64)(UINTN)SwitchStackData.Buffer,\r
+      (UINT32)BufferSize\r
       ));\r
 \r
     if (Index == Bsp) {\r
-      InitializeExceptionStackSwitchHandlers (&EssData);\r
+      InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
     } else {\r
       MpInitLibStartupThisAP (\r
         InitializeExceptionStackSwitchHandlers,\r
         Index,\r
         NULL,\r
         0,\r
-        (VOID *)&EssData,\r
+        (VOID *)&SwitchStackData,\r
         NULL\r
         );\r
     }\r
-\r
-    StackTop -= NewStackSize;\r
   }\r
 }\r
 \r
index e62bb5e6c07c1b2767277918cabc0e6751d5d1e3..04e84099226c982db221dfc8b604ab124d94636d 100644 (file)
@@ -104,48 +104,105 @@ RegisterCpuInterruptHandler (
 \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
   CPU_EXCEPTION_INIT_DATA  EssData;\r
   IA32_DESCRIPTOR          Idtr;\r
   IA32_DESCRIPTOR          Gdtr;\r
-\r
-  if (InitData == NULL) {\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
+  AsmReadGdtr (&Gdtr);\r
+  if ((Buffer == NULL) && (BufferSize == NULL)) {\r
     SetMem (mNewGdt, sizeof (mNewGdt), 0);\r
-\r
-    AsmReadIdtr (&Idtr);\r
-    AsmReadGdtr (&Gdtr);\r
-\r
-    EssData.X64.Revision                   = CPU_EXCEPTION_INIT_DATA_REV;\r
-    EssData.X64.KnownGoodStackTop          = (UINTN)mNewStack + sizeof (mNewStack);\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                   = mNewGdt;\r
-    EssData.X64.GdtTableSize               = sizeof (mNewGdt);\r
-    EssData.X64.ExceptionTssDesc           = mNewGdt + Gdtr.Limit + 1;\r
-    EssData.X64.ExceptionTssDescSize       = CPU_TSS_DESC_SIZE;\r
-    EssData.X64.ExceptionTss               = mNewGdt + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
-    EssData.X64.ExceptionTssSize           = CPU_TSS_SIZE;\r
-\r
-    InitData = &EssData;\r
+    StackTop    = (UINTN)mNewStack + sizeof (mNewStack);\r
+    NewGdtTable = mNewGdt;\r
+  } else {\r
+    if (BufferSize == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\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
 \r
-  return ArchSetupExceptionStack (InitData);\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
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
index cf5bfe40832b05aa35802e5c1e231bbf7f9b94db..7c2ec3b2db4caf74ec709034564ee4de894eeddd 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 #  CPU Exception Handler library instance for PEI module.\r
 #\r
-#  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>\r
 #  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
 ##\r
@@ -56,6 +56,8 @@
 \r
 [Pcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard    # CONSUMES\r
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize\r
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList\r
 \r
 [FeaturePcd]\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard                    ## CONSUMES\r
index 4313cc5582e3cd7d066478ea43c7bdc5b16035fb..ad5e0e9ed4f1f71b62e33733a5b40a853b4e7bc6 100644 (file)
@@ -201,20 +201,23 @@ RegisterCpuInterruptHandler (
 \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
   return EFI_UNSUPPORTED;\r
index 1c97dab926971a3fa1b089eb139b27205e5184bc..46a86ad2c6f9daf3ae1efd87a45045b4617be89a 100644 (file)
@@ -97,20 +97,23 @@ RegisterCpuInterruptHandler (
 \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
   return EFI_UNSUPPORTED;\r