]> 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 926541c93712ade823158540b99f3035b6a369b5..e7f1fe9f426c363f84ed69aa5bfbea7b6b357b55 100644 (file)
@@ -1,17 +1,19 @@
 /** @file\r
   CPU PEI Module installs CPU Multiple Processor PPI.\r
 \r
-  Copyright (c) 2015 - 2018, 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
 \r
 #include "CpuMpPei.h"\r
 \r
+extern EDKII_PEI_MP_SERVICES2_PPI  mMpServices2Ppi;\r
+\r
 //\r
 // CPU MP PPI to be installed\r
 //\r
-EFI_PEI_MP_SERVICES_PPI                mMpServicesPpi = {\r
+EFI_PEI_MP_SERVICES_PPI  mMpServicesPpi = {\r
   PeiGetNumberOfProcessors,\r
   PeiGetProcessorInfo,\r
   PeiStartupAllAPs,\r
@@ -21,10 +23,17 @@ EFI_PEI_MP_SERVICES_PPI                mMpServicesPpi = {
   PeiWhoAmI,\r
 };\r
 \r
-EFI_PEI_PPI_DESCRIPTOR           mPeiCpuMpPpiDesc = {\r
-  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
-  &gEfiPeiMpServicesPpiGuid,\r
-  &mMpServicesPpi\r
+EFI_PEI_PPI_DESCRIPTOR  mPeiCpuMpPpiList[] = {\r
+  {\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+    &gEdkiiPeiMpServices2PpiGuid,\r
+    &mMpServices2Ppi\r
+  },\r
+  {\r
+    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+    &gEfiPeiMpServicesPpiGuid,\r
+    &mMpServicesPpi\r
+  }\r
 };\r
 \r
 /**\r
@@ -64,10 +73,10 @@ EFI_PEI_PPI_DESCRIPTOR           mPeiCpuMpPpiDesc = {
 EFI_STATUS\r
 EFIAPI\r
 PeiGetNumberOfProcessors (\r
-  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
-  IN  EFI_PEI_MP_SERVICES_PPI   *This,\r
-  OUT UINTN                     *NumberOfProcessors,\r
-  OUT UINTN                     *NumberOfEnabledProcessors\r
+  IN  CONST EFI_PEI_SERVICES   **PeiServices,\r
+  IN  EFI_PEI_MP_SERVICES_PPI  *This,\r
+  OUT UINTN                    *NumberOfProcessors,\r
+  OUT UINTN                    *NumberOfEnabledProcessors\r
   )\r
 {\r
   if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {\r
@@ -184,12 +193,12 @@ PeiGetProcessorInfo (
 EFI_STATUS\r
 EFIAPI\r
 PeiStartupAllAPs (\r
-  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
-  IN  EFI_PEI_MP_SERVICES_PPI   *This,\r
-  IN  EFI_AP_PROCEDURE          Procedure,\r
-  IN  BOOLEAN                   SingleThread,\r
-  IN  UINTN                     TimeoutInMicroSeconds,\r
-  IN  VOID                      *ProcedureArgument      OPTIONAL\r
+  IN  CONST EFI_PEI_SERVICES   **PeiServices,\r
+  IN  EFI_PEI_MP_SERVICES_PPI  *This,\r
+  IN  EFI_AP_PROCEDURE         Procedure,\r
+  IN  BOOLEAN                  SingleThread,\r
+  IN  UINTN                    TimeoutInMicroSeconds,\r
+  IN  VOID                     *ProcedureArgument      OPTIONAL\r
   )\r
 {\r
   return MpInitLibStartupAllAPs (\r
@@ -251,12 +260,12 @@ PeiStartupAllAPs (
 EFI_STATUS\r
 EFIAPI\r
 PeiStartupThisAP (\r
-  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
-  IN  EFI_PEI_MP_SERVICES_PPI   *This,\r
-  IN  EFI_AP_PROCEDURE          Procedure,\r
-  IN  UINTN                     ProcessorNumber,\r
-  IN  UINTN                     TimeoutInMicroseconds,\r
-  IN  VOID                      *ProcedureArgument      OPTIONAL\r
+  IN  CONST EFI_PEI_SERVICES   **PeiServices,\r
+  IN  EFI_PEI_MP_SERVICES_PPI  *This,\r
+  IN  EFI_AP_PROCEDURE         Procedure,\r
+  IN  UINTN                    ProcessorNumber,\r
+  IN  UINTN                    TimeoutInMicroseconds,\r
+  IN  VOID                     *ProcedureArgument      OPTIONAL\r
   )\r
 {\r
   return MpInitLibStartupThisAP (\r
@@ -357,11 +366,11 @@ PeiSwitchBSP (
 EFI_STATUS\r
 EFIAPI\r
 PeiEnableDisableAP (\r
-  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
-  IN  EFI_PEI_MP_SERVICES_PPI   *This,\r
-  IN  UINTN                     ProcessorNumber,\r
-  IN  BOOLEAN                   EnableAP,\r
-  IN  UINT32                    *HealthFlag OPTIONAL\r
+  IN  CONST EFI_PEI_SERVICES   **PeiServices,\r
+  IN  EFI_PEI_MP_SERVICES_PPI  *This,\r
+  IN  UINTN                    ProcessorNumber,\r
+  IN  BOOLEAN                  EnableAP,\r
+  IN  UINT32                   *HealthFlag OPTIONAL\r
   )\r
 {\r
   return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);\r
@@ -402,28 +411,19 @@ 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
 \r
-  This function is a wrapper of InitializeCpuExceptionHandlersEx. It's mainly\r
+  This function is a wrapper of InitializeSeparateExceptionStacks. It's mainly\r
   for the sake of AP's init because of EFI_AP_PROCEDURE API requirement.\r
 \r
   @param[in,out] Buffer  The pointer to private data buffer.\r
@@ -432,30 +432,29 @@ GetGdtr (
 VOID\r
 EFIAPI\r
 InitializeExceptionStackSwitchHandlers (\r
-  IN OUT VOID *Buffer\r
+  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 = InitializeCpuExceptionHandlersEx (NULL, 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
@@ -463,150 +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
+  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
-  Status = PeiServicesAllocatePool (\r
-             NewStackSize * NumberOfProcessors,\r
-             (VOID **)&StackTop\r
-             );\r
-  ASSERT(StackTop != NULL);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT_EFI_ERROR (Status);\r
-    return;\r
+  MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);\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
-  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 ((DEBUG_INFO,\r
-            "Exception stack top[cpu%lu]: 0x%lX\n",\r
-            (UINT64)(UINTN)Index,\r
-            (UINT64)(UINTN)StackTop));\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
@@ -620,23 +546,23 @@ InitializeMpExceptionStackSwitchHandlers (
 **/\r
 EFI_STATUS\r
 InitializeCpuMpWorker (\r
-  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices\r
   )\r
 {\r
-  EFI_STATUS                      Status;\r
-  EFI_VECTOR_HANDOFF_INFO         *VectorInfo;\r
-  EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
+  EFI_STATUS                       Status;\r
+  EFI_VECTOR_HANDOFF_INFO          *VectorInfo;\r
+  EFI_PEI_VECTOR_HANDOFF_INFO_PPI  *VectorHandoffInfoPpi;\r
 \r
   //\r
   // Get Vector Hand-off Info PPI\r
   //\r
   VectorInfo = NULL;\r
-  Status = PeiServicesLocatePpi (\r
-             &gEfiVectorHandoffInfoPpiGuid,\r
-             0,\r
-             NULL,\r
-             (VOID **)&VectorHandoffInfoPpi\r
-             );\r
+  Status     = PeiServicesLocatePpi (\r
+                 &gEfiVectorHandoffInfoPpiGuid,\r
+                 0,\r
+                 NULL,\r
+                 (VOID **)&VectorHandoffInfoPpi\r
+                 );\r
   if (Status == EFI_SUCCESS) {\r
     VectorInfo = VectorHandoffInfoPpi->Info;\r
   }\r
@@ -667,7 +593,7 @@ InitializeCpuMpWorker (
   //\r
   // Install CPU MP PPI\r
   //\r
-  Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
+  Status = PeiServicesInstallPpi (mPeiCpuMpPpiList);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   return Status;\r
@@ -692,7 +618,7 @@ CpuMpPeimInit (
   IN CONST EFI_PEI_SERVICES     **PeiServices\r
   )\r
 {\r
-  EFI_STATUS           Status;\r
+  EFI_STATUS  Status;\r
 \r
   //\r
   // For the sake of special initialization needing to be done right after\r