]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg/MpInitLib: Implementation of MpInitLibStartupAllAPs()
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
index a7e9fb8ed3f6184081aae09ca56437418e85361d..5e714eaf19b5a464d2d2d4afbd13d180f4483414 100644 (file)
 **/\r
 \r
 #include "MpLib.h"\r
+#include <Ppi/EndOfPeiPhase.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+//\r
+// Global PEI notify function descriptor on EndofPei event\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMpInitLibNotifyList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEfiEndOfPeiSignalPpiGuid,\r
+  CpuMpEndOfPeiCallback\r
+};\r
+\r
+/**\r
+  Get pointer to CPU MP Data structure.\r
+\r
+  @return  The pointer to CPU MP Data structure.\r
+**/\r
+CPU_MP_DATA *\r
+GetCpuMpData (\r
+  VOID\r
+  )\r
+{\r
+  CPU_MP_DATA      *CpuMpData;\r
+\r
+  CpuMpData = GetCpuMpDataFromGuidedHob ();\r
+  ASSERT (CpuMpData != NULL);\r
+  return CpuMpData;\r
+}\r
+\r
+/**\r
+  Save the pointer to CPU MP Data structure.\r
+\r
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.\r
+**/\r
+VOID\r
+SaveCpuMpData (\r
+  IN CPU_MP_DATA   *CpuMpData\r
+  )\r
+{\r
+  UINT64           Data64;\r
+  //\r
+  // Build location of CPU MP DATA buffer in HOB\r
+  //\r
+  Data64 = (UINT64) (UINTN) CpuMpData;\r
+  BuildGuidDataHob (\r
+    &mCpuInitMpLibHobGuid,\r
+    (VOID *) &Data64,\r
+    sizeof (UINT64)\r
+    );\r
+}\r
+\r
+/**\r
+  Get available system memory below 1MB by specified size.\r
+\r
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data\r
+**/\r
+VOID\r
+BackupAndPrepareWakeupBuffer(\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  CopyMem (\r
+    (VOID *) CpuMpData->BackupBuffer,\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    CpuMpData->BackupBufferSize\r
+    );\r
+  CopyMem (\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
+    CpuMpData->AddressMap.RendezvousFunnelSize\r
+    );\r
+}\r
+\r
+/**\r
+  Restore wakeup buffer data.\r
+\r
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data\r
+**/\r
+VOID\r
+RestoreWakeupBuffer(\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  CopyMem (\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    (VOID *) CpuMpData->BackupBuffer,\r
+    CpuMpData->BackupBufferSize\r
+    );\r
+}\r
+\r
+/**\r
+  Notify function on End Of PEI PPI.\r
+\r
+  On S3 boot, this function will restore wakeup buffer data.\r
+  On normal boot, this function will flag wakeup buffer to be un-used type.\r
+\r
+  @param[in]  PeiServices        The pointer to the PEI Services Table.\r
+  @param[in]  NotifyDescriptor   Address of the notification descriptor data structure.\r
+  @param[in]  Ppi                Address of the PPI that was installed.\r
+\r
+  @retval EFI_SUCCESS        When everything is OK.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMpEndOfPeiCallback (\r
+  IN EFI_PEI_SERVICES             **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR    *NotifyDescriptor,\r
+  IN VOID                         *Ppi\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_BOOT_MODE             BootMode;\r
+  CPU_MP_DATA               *CpuMpData;\r
+  EFI_PEI_HOB_POINTERS      Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
+\r
+  DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n"));\r
+\r
+  Status = PeiServicesGetBootMode (&BootMode);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  CpuMpData = GetCpuMpData ();\r
+  if (BootMode != BOOT_ON_S3_RESUME) {\r
+    //\r
+    // Get the HOB list for processing\r
+    //\r
+    Hob.Raw = GetHobList ();\r
+    //\r
+    // Collect memory ranges\r
+    //\r
+    while (!END_OF_HOB_LIST (Hob)) {\r
+      if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+        MemoryHob = Hob.MemoryAllocation;\r
+        if (MemoryHob->AllocDescriptor.MemoryBaseAddress == CpuMpData->WakeupBuffer) {\r
+          //\r
+          // Flag this HOB type to un-used\r
+          //\r
+          GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
+          break;\r
+        }\r
+      }\r
+      Hob.Raw = GET_NEXT_HOB (Hob);\r
+    }\r
+  } else {\r
+    CpuMpData->EndOfPeiFlag = TRUE;\r
+    RestoreWakeupBuffer (CpuMpData);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if AP wakeup buffer is overlapped with existing allocated buffer.\r
+\r
+  @param[in]  WakeupBufferStart     AP wakeup buffer start address.\r
+  @param[in]  WakeupBufferEnd       AP wakeup buffer end address.\r
+\r
+  @retval  TRUE       There is overlap.\r
+  @retval  FALSE      There is no overlap.\r
+**/\r
+BOOLEAN\r
+CheckOverlapWithAllocatedBuffer (\r
+  IN UINTN                WakeupBufferStart,\r
+  IN UINTN                WakeupBufferEnd\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS      Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
+  BOOLEAN                   Overlapped;\r
+  UINTN                     MemoryStart;\r
+  UINTN                     MemoryEnd;\r
+\r
+  Overlapped = FALSE;\r
+  //\r
+  // Get the HOB list for processing\r
+  //\r
+  Hob.Raw = GetHobList ();\r
+  //\r
+  // Collect memory ranges\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+      MemoryHob   = Hob.MemoryAllocation;\r
+      MemoryStart = (UINTN) MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+      MemoryEnd   = (UINTN) (MemoryHob->AllocDescriptor.MemoryBaseAddress +\r
+                             MemoryHob->AllocDescriptor.MemoryLength);\r
+      if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
+        Overlapped = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+  return Overlapped;\r
+}\r
+\r
+/**\r
+  Get available system memory below 1MB by specified size.\r
+\r
+  @param[in] WakeupBufferSize   Wakeup buffer size required\r
+\r
+  @retval other   Return wakeup buffer address below 1MB.\r
+  @retval -1      Cannot find free memory below 1MB.\r
+**/\r
+UINTN\r
+GetWakeupBuffer (\r
+  IN UINTN                WakeupBufferSize\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS    Hob;\r
+  UINTN                   WakeupBufferStart;\r
+  UINTN                   WakeupBufferEnd;\r
+\r
+  WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
+\r
+  //\r
+  // Get the HOB list for processing\r
+  //\r
+  Hob.Raw = GetHobList ();\r
+\r
+  //\r
+  // Collect memory ranges\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
+          (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+          ((Hob.ResourceDescriptor->ResourceAttribute &\r
+            (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
+             EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
+             EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
+             )) == 0)\r
+           ) {\r
+        //\r
+        // Need memory under 1MB to be collected here\r
+        //\r
+        WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
+        if (WakeupBufferEnd > BASE_1MB) {\r
+          //\r
+          // Wakeup buffer should be under 1MB\r
+          //\r
+          WakeupBufferEnd = BASE_1MB;\r
+        }\r
+        while (WakeupBufferEnd > WakeupBufferSize) {\r
+          //\r
+          // Wakeup buffer should be aligned on 4KB\r
+          //\r
+          WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
+          if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
+            break;\r
+          }\r
+          if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {\r
+            //\r
+            // If this range is overlapped with existing allocated buffer, skip it\r
+            // and find the next range\r
+            //\r
+            WakeupBufferEnd -= WakeupBufferSize;\r
+            continue;\r
+          }\r
+          DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+                               WakeupBufferStart, WakeupBufferSize));\r
+          //\r
+          // Create a memory allocation HOB.\r
+          //\r
+          BuildMemoryAllocationHob (\r
+            WakeupBufferStart,\r
+            WakeupBufferSize,\r
+            EfiBootServicesData\r
+            );\r
+          return WakeupBufferStart;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // Find the next HOB\r
+    //\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Allocate reset vector buffer.\r
+\r
+  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateResetVector (\r
+  IN OUT CPU_MP_DATA          *CpuMpData\r
+  )\r
+{\r
+  UINTN           ApResetVectorSize;\r
+\r
+  if (CpuMpData->WakeupBuffer == (UINTN) -1) {\r
+    ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
+                          sizeof (MP_CPU_EXCHANGE_INFO);\r
+\r
+    CpuMpData->WakeupBuffer      = GetWakeupBuffer (ApResetVectorSize);\r
+    CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
+                    (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+    BackupAndPrepareWakeupBuffer (CpuMpData);\r
+  }\r
+\r
+  if (CpuMpData->EndOfPeiFlag) {\r
+    BackupAndPrepareWakeupBuffer (CpuMpData);\r
+  }\r
+}\r
+\r
+/**\r
+  Free AP reset vector buffer.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+FreeResetVector (\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  if (CpuMpData->EndOfPeiFlag) {\r
+    RestoreWakeupBuffer (CpuMpData);\r
+  }\r
+}\r
+\r
+/**\r
+  Checks APs status and updates APs status if needed.\r
+\r
+**/\r
+VOID\r
+CheckAndUpdateApsStatus (\r
+  VOID\r
+  )\r
+{\r
+}\r
+\r
+/**\r
+  Initialize global data for MP support.\r
+\r
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+InitMpGlobalData (\r
+  IN CPU_MP_DATA               *CpuMpData\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+\r
+  SaveCpuMpData (CpuMpData);\r
+  //\r
+  // Register an event for EndOfPei\r
+  //\r
+  Status  = PeiServicesNotifyPpi (&mMpInitLibNotifyList);\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
 \r
 /**\r
   This service executes a caller provided function on all enabled APs.\r
@@ -100,7 +453,18 @@ MpInitLibStartupAllAPs (
   OUT UINTN                     **FailedCpuList         OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  if (WaitEvent != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return StartupAllAPsWorker (\r
+           Procedure,\r
+           SingleThread,\r
+           NULL,\r
+           TimeoutInMicroseconds,\r
+           ProcedureArgument,\r
+           FailedCpuList\r
+           );\r
 }\r
 \r
 /**\r
@@ -185,7 +549,18 @@ MpInitLibStartupThisAP (
   OUT BOOLEAN                   *Finished               OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  if (WaitEvent != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return StartupThisAPWorker (\r
+           Procedure,\r
+           ProcessorNumber,\r
+           NULL,\r
+           TimeoutInMicroseconds,\r
+           ProcedureArgument,\r
+           Finished\r
+           );\r
 }\r
 \r
 /**\r
@@ -221,7 +596,7 @@ MpInitLibSwitchBSP (
   IN  BOOLEAN                  EnableOldBSP\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
 }\r
 \r
 /**\r
@@ -262,7 +637,7 @@ MpInitLibEnableDisableAP (
   IN  UINT32                    *HealthFlag OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
 }\r
 \r
 \r