]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuMp.c
index 9659bd280725c56a5a6ed325a191a4ff3f7bd83a..e7575d9b8062e77b4a1957338d32d9679d258cca 100644 (file)
@@ -1,22 +1,16 @@
 /** @file\r
   CPU DXE Module to produce CPU MP Protocol.\r
 \r
-  Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "CpuDxe.h"\r
 #include "CpuMp.h"\r
 \r
-EFI_HANDLE     mMpServiceHandle       = NULL;\r
-UINTN          mNumberOfProcessors    = 1;\r
+EFI_HANDLE  mMpServiceHandle    = NULL;\r
+UINTN       mNumberOfProcessors = 1;\r
 \r
 EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {\r
   GetNumberOfProcessors,\r
@@ -170,7 +164,7 @@ GetProcessorInfo (
        and releases the BSP to continue with other tasks.\r
     -# The caller can use the CheckEvent() and WaitForEvent() services to check\r
        the state of the WaitEvent created in step 1.\r
-    -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP\r
+    -# When the APs complete their task or TimeoutInMicroSeconds expires, the MP\r
        Service signals WaitEvent by calling the EFI SignalEvent() function. If\r
        FailedCpuList is not NULL, its content is available when WaitEvent is\r
        signaled. If all APs returned from Procedure prior to the timeout, then\r
@@ -287,7 +281,7 @@ StartupAllAPs (
   This function is used to dispatch one enabled AP to the function specified by\r
   Procedure passing in the argument specified by ProcedureArgument.  If WaitEvent\r
   is NULL, execution is in blocking mode. The BSP waits until the AP finishes or\r
-  TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.\r
+  TimeoutInMicroSeconds expires. Otherwise, execution is in non-blocking mode.\r
   BSP proceeds to the next task without waiting for the AP. If a non-blocking mode\r
   is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,\r
   then EFI_UNSUPPORTED must be returned.\r
@@ -412,7 +406,7 @@ StartupThisAP (
   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to\r
                                   this service returning.\r
   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.\r
-  @retval EFI_SUCCESS             The calling processor is an AP.\r
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.\r
   @retval EFI_NOT_FOUND           The processor with the handle specified by\r
                                   ProcessorNumber does not exist.\r
   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or\r
@@ -515,7 +509,7 @@ WhoAmI (
   OUT UINTN                    *ProcessorNumber\r
   )\r
 {\r
-  return MpInitLibWhoAmI (ProcessorNumber);;\r
+  return MpInitLibWhoAmI (ProcessorNumber);\r
 }\r
 \r
 /**\r
@@ -553,8 +547,8 @@ CollectBistDataFromHob (
     // Sec Platform Information2 PPI includes BSP/APs' BIST information\r
     //\r
     SecPlatformInformation2 = GET_GUID_HOB_DATA (GuidHob);\r
-    NumberOfData = SecPlatformInformation2->NumberOfCpus;\r
-    CpuInstance  = SecPlatformInformation2->CpuInstance;\r
+    NumberOfData            = SecPlatformInformation2->NumberOfCpus;\r
+    CpuInstance             = SecPlatformInformation2->CpuInstance;\r
   } else {\r
     //\r
     // Otherwise, get gEfiSecPlatformInformationPpiGuid Guided HOB\r
@@ -562,16 +556,16 @@ CollectBistDataFromHob (
     GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);\r
     if (GuidHob != NULL) {\r
       SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);\r
-      NumberOfData = 1;\r
+      NumberOfData           = 1;\r
       //\r
       // SEC Platform Information only includes BSP's BIST information\r
       // does not have BSP's APIC ID\r
       //\r
-      BspCpuInstance.CpuLocation = GetApicId ();\r
-      BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32  = SecPlatformInformation->IA32HealthFlags.Uint32;\r
-      CpuInstance = &BspCpuInstance;\r
+      BspCpuInstance.CpuLocation                       = GetApicId ();\r
+      BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;\r
+      CpuInstance                                      = &BspCpuInstance;\r
     } else {\r
-      DEBUG ((EFI_D_INFO, "Does not find any HOB stored CPU BIST information!\n"));\r
+      DEBUG ((DEBUG_INFO, "Does not find any HOB stored CPU BIST information!\n"));\r
       //\r
       // Does not find any HOB stored BIST information\r
       //\r
@@ -589,6 +583,7 @@ CollectBistDataFromHob (
         BistData = CpuInstance[CpuInstanceNumber].InfoRecord.IA32HealthFlags;\r
       }\r
     }\r
+\r
     if (BistData.Uint32 != 0) {\r
       //\r
       // Report Status Code that self test is failed\r
@@ -601,6 +596,149 @@ CollectBistDataFromHob (
   }\r
 }\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 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
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeExceptionStackSwitchHandlers (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  *SwitchStackData;\r
+  UINTN                           Index;\r
+\r
+  MpInitLibWhoAmI (&Index);\r
+  SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\r
+\r
+  //\r
+  // This 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
+  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 SwitchStackData to each logic processor.\r
+\r
+**/\r
+VOID\r
+InitializeMpExceptionStackSwitchHandlers (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                           Index;\r
+  EXCEPTION_STACK_SWITCH_CONTEXT  *SwitchStackData;\r
+  UINTN                           BufferSize;\r
+  EFI_STATUS                      Status;\r
+  UINT8                           *Buffer;\r
+\r
+  SwitchStackData = AllocateZeroPool (mNumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT));\r
+  ASSERT (SwitchStackData != NULL);\r
+  for (Index = 0; Index < mNumberOfProcessors; ++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
+  Status = MpInitLibStartupAllCPUs (\r
+             InitializeExceptionStackSwitchHandlers,\r
+             0,\r
+             SwitchStackData\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  BufferSize = 0;\r
+  for (Index = 0; Index < mNumberOfProcessors; ++Index) {\r
+    if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {\r
+      ASSERT (SwitchStackData[Index].BufferSize != 0);\r
+      BufferSize += SwitchStackData[Index].BufferSize;\r
+    } else {\r
+      ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
+      ASSERT (SwitchStackData[Index].BufferSize == 0);\r
+    }\r
+  }\r
+\r
+  if (BufferSize != 0) {\r
+    Buffer = AllocateRuntimeZeroPool (BufferSize);\r
+    ASSERT (Buffer != NULL);\r
+    BufferSize = 0;\r
+    for (Index = 0; Index < mNumberOfProcessors; ++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
+    Status = MpInitLibStartupAllCPUs (\r
+               InitializeExceptionStackSwitchHandlers,\r
+               0,\r
+               SwitchStackData\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+    for (Index = 0; Index < mNumberOfProcessors; ++Index) {\r
+      ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
+    }\r
+  }\r
+\r
+  FreePool (SwitchStackData);\r
+}\r
+\r
+/**\r
+  Initializes MP exceptions handlers for special features, such as Heap Guard\r
+  and Stack Guard.\r
+**/\r
+VOID\r
+InitializeMpExceptionHandlers (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Enable non-stop mode for #PF triggered by Heap Guard or NULL Pointer\r
+  // Detection.\r
+  //\r
+  if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {\r
+    RegisterCpuInterruptHandler (EXCEPT_IA32_DEBUG, DebugExceptionHandler);\r
+    RegisterCpuInterruptHandler (EXCEPT_IA32_PAGE_FAULT, PageFaultExceptionHandler);\r
+  }\r
+\r
+  //\r
+  // Setup stack switch for Stack Guard feature.\r
+  //\r
+  if (PcdGetBool (PcdCpuStackGuard)) {\r
+    InitializeMpExceptionStackSwitchHandlers ();\r
+  }\r
+}\r
+\r
 /**\r
   Initialize Multi-processor support.\r
 \r
@@ -610,9 +748,9 @@ InitializeMpSupport (
   VOID\r
   )\r
 {\r
-  EFI_STATUS     Status;\r
-  UINTN          NumberOfProcessors;\r
-  UINTN          NumberOfEnabledProcessors;\r
+  EFI_STATUS  Status;\r
+  UINTN       NumberOfProcessors;\r
+  UINTN       NumberOfEnabledProcessors;\r
 \r
   //\r
   // Wakeup APs to do initialization\r
@@ -622,7 +760,12 @@ InitializeMpSupport (
 \r
   MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);\r
   mNumberOfProcessors = NumberOfProcessors;\r
-  DEBUG ((EFI_D_ERROR, "Detect CPU count: %d\n", mNumberOfProcessors));\r
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));\r
+\r
+  //\r
+  // Initialize special exception handlers for each logic processor.\r
+  //\r
+  InitializeMpExceptionHandlers ();\r
 \r
   //\r
   // Update CPU healthy information from Guided HOB\r
@@ -631,9 +774,9 @@ InitializeMpSupport (
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &mMpServiceHandle,\r
-                  &gEfiMpServiceProtocolGuid,  &mMpServicesTemplate,\r
+                  &gEfiMpServiceProtocolGuid,\r
+                  &mMpServicesTemplate,\r
                   NULL\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
-\r