]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
index d4786979fa1b15a53affdebb516aa53971b9ecac..e7f1fe9f426c363f84ed69aa5bfbea7b6b357b55 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,14 @@ 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
+  EFI_STATUS    Status;\r
+} EXCEPTION_STACK_SWITCH_CONTEXT;\r
 \r
 /**\r
   Initializes CPU exceptions handlers for the sake of stack switch requirement.\r
@@ -444,27 +435,26 @@ 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
+  UINTN                           Index;\r
+\r
+  MpInitLibWhoAmI (&Index);\r
+  SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\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
+  // This function may be called twice for each Cpu. Only run InitializeSeparateExceptionStacks\r
+  // if this is the first call or the first call failed because of size too small.\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
+  if ((SwitchStackData[Index].Status == EFI_NOT_STARTED) || (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL)) {\r
+    SwitchStackData[Index].Status = InitializeSeparateExceptionStacks (SwitchStackData[Index].Buffer, &SwitchStackData[Index].BufferSize);\r
+  }\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,149 +462,77 @@ 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                           NumberOfProcessors;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  *SwitchStackData;\r
+  UINTN                           BufferSize;\r
+  EFI_STATUS                      Status;\r
+  UINT8                           *Buffer;\r
 \r
   if (!PcdGetBool (PcdCpuStackGuard)) {\r
     return;\r
   }\r
 \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
+  SwitchStackData = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT)));\r
+  ASSERT (SwitchStackData != NULL);\r
+  ZeroMem (SwitchStackData, NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT));\r
+  for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+    //\r
+    // Because the procedure may runs multiple times, use the status EFI_NOT_STARTED\r
+    // to indicate the procedure haven't been run yet.\r
+    //\r
+    SwitchStackData[Index].Status = EFI_NOT_STARTED;\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
+  Status = MpInitLibStartupAllCPUs (\r
+             InitializeExceptionStackSwitchHandlers,\r
+             0,\r
+             SwitchStackData\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  //\r
-  // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.\r
-  //\r
-  Gdtr.Base  = 0;\r
-  Gdtr.Limit = 0;\r
+  BufferSize = 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
-    if (Index == Bsp) {\r
-      GetGdtr (&Gdtr);\r
+    if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {\r
+      ASSERT (SwitchStackData[Index].BufferSize != 0);\r
+      BufferSize += SwitchStackData[Index].BufferSize;\r
     } else {\r
-      //\r
-      // AP might have different size of GDT from BSP.\r
-      //\r
-      MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);\r
+      ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
+      ASSERT (SwitchStackData[Index].BufferSize == 0);\r
     }\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
+    Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
+    ASSERT (Buffer != NULL);\r
+    BufferSize = 0;\r
+    for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+      if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {\r
+        SwitchStackData[Index].Buffer = (VOID *)(&Buffer[BufferSize]);\r
+        BufferSize                   += SwitchStackData[Index].BufferSize;\r
+        DEBUG ((\r
+          DEBUG_INFO,\r
+          "Buffer[cpu%lu] for InitializeExceptionStackSwitchHandlers: 0x%lX with size 0x%lX\n",\r
+          (UINT64)(UINTN)Index,\r
+          (UINT64)(UINTN)SwitchStackData[Index].Buffer,\r
+          (UINT64)(UINTN)SwitchStackData[Index].BufferSize\r
+          ));\r
+      }\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
-    DEBUG ((\r
-      DEBUG_INFO,\r
-      "Exception stack top[cpu%lu]: 0x%lX\n",\r
-      (UINT64)(UINTN)Index,\r
-      (UINT64)(UINTN)StackTop\r
-      ));\r
-\r
-    if (Index == Bsp) {\r
-      InitializeExceptionStackSwitchHandlers (&EssData);\r
-    } else {\r
-      MpInitLibStartupThisAP (\r
-        InitializeExceptionStackSwitchHandlers,\r
-        Index,\r
-        NULL,\r
-        0,\r
-        (VOID *)&EssData,\r
-        NULL\r
-        );\r
+    Status = MpInitLibStartupAllCPUs (\r
+               InitializeExceptionStackSwitchHandlers,\r
+               0,\r
+               SwitchStackData\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+    for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+      ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
     }\r
-\r
-    StackTop -= NewStackSize;\r
   }\r
+\r
+  FreePages (SwitchStackData, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT)));\r
 }\r
 \r
 /**\r