]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
index cdec0108c54b06482d1990496bd0bbb49c3a9a74..35dff91fd2a5352a525d522d010ec445f10bf5d1 100644 (file)
@@ -1,32 +1,94 @@
 /** @file\r
   MP initialize support functions for PEI phase.\r
 \r
-  Copyright (c) 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) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "MpLib.h"\r
-#include <Ppi/EndOfPeiPhase.h>\r
 #include <Library/PeiServicesLib.h>\r
+#include <Guid/S3SmmInitDone.h>\r
+\r
+/**\r
+  S3 SMM Init Done notification function.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnS3SmmInitDonePpi (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,\r
+  IN  VOID                                          *InvokePpi\r
+  );\r
+\r
 \r
 //\r
-// Global PEI notify function descriptor on EndofPei event\r
+// Global function\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
+EFI_PEI_NOTIFY_DESCRIPTOR        mS3SmmInitDoneNotifyDesc = {\r
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gEdkiiS3SmmInitDoneGuid,\r
+  NotifyOnS3SmmInitDonePpi\r
 };\r
 \r
+/**\r
+  S3 SMM Init Done notification function.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnS3SmmInitDonePpi (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,\r
+  IN  VOID                                          *InvokePpi\r
+  )\r
+{\r
+  CPU_MP_DATA     *CpuMpData;\r
+\r
+  CpuMpData = GetCpuMpData ();\r
+\r
+  //\r
+  // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.\r
+  // So in this notify function, code need to check the current loop\r
+  // mode, if it is not HLT mode, code need to change loop mode back\r
+  // to the original mode.\r
+  //\r
+  if (CpuMpData->ApLoopMode != ApInHltLoop) {\r
+    CpuMpData->WakeUpByInitSipiSipi = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enable Debug Agent to support source debugging on AP function.\r
+\r
+**/\r
+VOID\r
+EnableDebugAgent (\r
+  VOID\r
+  )\r
+{\r
+}\r
+\r
 /**\r
   Get pointer to CPU MP Data structure.\r
+  For BSP, the pointer is retrieved from HOB.\r
+  For AP, the structure is just after IDT.\r
 \r
   @return  The pointer to CPU MP Data structure.\r
 **/\r
@@ -35,10 +97,18 @@ GetCpuMpData (
   VOID\r
   )\r
 {\r
-  CPU_MP_DATA      *CpuMpData;\r
-\r
-  CpuMpData = GetCpuMpDataFromGuidedHob ();\r
-  ASSERT (CpuMpData != NULL);\r
+  CPU_MP_DATA                  *CpuMpData;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+  IA32_DESCRIPTOR              Idtr;\r
+\r
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+  if (ApicBaseMsr.Bits.BSP == 1) {\r
+    CpuMpData = GetCpuMpDataFromGuidedHob ();\r
+    ASSERT (CpuMpData != NULL);\r
+  } else {\r
+    AsmReadIdtr (&Idtr);\r
+    CpuMpData = (CPU_MP_DATA *) (Idtr.Base + Idtr.Limit + 1);\r
+  }\r
   return CpuMpData;\r
 }\r
 \r
@@ -64,105 +134,6 @@ SaveCpuMpData (
     );\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
@@ -174,15 +145,15 @@ CpuMpEndOfPeiCallback (
 **/\r
 BOOLEAN\r
 CheckOverlapWithAllocatedBuffer (\r
-  IN UINT               WakeupBufferStart,\r
-  IN UINT               WakeupBufferEnd\r
+  IN UINT64               WakeupBufferStart,\r
+  IN UINT64               WakeupBufferEnd\r
   )\r
 {\r
   EFI_PEI_HOB_POINTERS      Hob;\r
   EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
   BOOLEAN                   Overlapped;\r
-  UINT                    MemoryStart;\r
-  UINT                    MemoryEnd;\r
+  UINT64                    MemoryStart;\r
+  UINT64                    MemoryEnd;\r
 \r
   Overlapped = FALSE;\r
   //\r
@@ -195,9 +166,8 @@ CheckOverlapWithAllocatedBuffer (
   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
+      MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+      MemoryEnd   = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
       if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
         Overlapped = TRUE;\r
         break;\r
@@ -222,8 +192,8 @@ GetWakeupBuffer (
   )\r
 {\r
   EFI_PEI_HOB_POINTERS    Hob;\r
-  UINT                  WakeupBufferStart;\r
-  UINT                  WakeupBufferEnd;\r
+  UINT64                  WakeupBufferStart;\r
+  UINT64                  WakeupBufferEnd;\r
 \r
   WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
 \r
@@ -248,7 +218,7 @@ GetWakeupBuffer (
         //\r
         // Need memory under 1MB to be collected here\r
         //\r
-        WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
+        WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;\r
         if (WakeupBufferEnd > BASE_1MB) {\r
           //\r
           // Wakeup buffer should be under 1MB\r
@@ -273,15 +243,7 @@ GetWakeupBuffer (
           }\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
+          return (UINTN)WakeupBufferStart;\r
         }\r
       }\r
     }\r
@@ -295,45 +257,37 @@ GetWakeupBuffer (
 }\r
 \r
 /**\r
-  Allocate reset vector buffer.\r
+  Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+  This buffer is required to safely transfer AP from real address mode to\r
+  protected mode or long mode, due to the fact that the buffer returned by\r
+  GetWakeupBuffer() may be marked as non-executable.\r
 \r
-  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
+  @param[in] BufferSize   Wakeup transition buffer size.\r
+\r
+  @retval other   Return wakeup transition buffer address below 4GB.\r
+  @retval 0       Cannot find free memory below 4GB.\r
 **/\r
-VOID\r
-AllocateResetVector (\r
-  IN OUT CPU_MP_DATA          *CpuMpData\r
+UINTN\r
+GetModeTransitionBuffer (\r
+  IN UINTN                BufferSize\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
+  // PEI phase doesn't need to do such transition. So simply return 0.\r
+  //\r
+  return 0;\r
 }\r
 \r
 /**\r
-  Free AP reset vector buffer.\r
+  Checks APs status and updates APs status if needed.\r
 \r
-  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
 **/\r
 VOID\r
-FreeResetVector (\r
-  IN CPU_MP_DATA              *CpuMpData\r
+CheckAndUpdateApsStatus (\r
+  VOID\r
   )\r
 {\r
-  if (CpuMpData->EndOfPeiFlag) {\r
-    RestoreWakeupBuffer (CpuMpData);\r
-  }\r
 }\r
 \r
 /**\r
@@ -346,13 +300,14 @@ InitMpGlobalData (
   IN CPU_MP_DATA               *CpuMpData\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
+  EFI_STATUS  Status;\r
 \r
   SaveCpuMpData (CpuMpData);\r
-  //\r
-  // Register an event for EndOfPei\r
-  //\r
-  Status  = PeiServicesNotifyPpi (&mMpInitLibNotifyList);\r
+\r
+  ///\r
+  /// Install Notify\r
+  ///\r
+  Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
@@ -383,7 +338,7 @@ InitMpGlobalData (
                                       EFI_EVENT is defined in CreateEvent() in\r
                                       the Unified Extensible Firmware Interface\r
                                       Specification.\r
-  @param[in]  TimeoutInMicrosecsond   Indicates the time limit in microseconds for\r
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
                                       APs to return from Procedure, either for\r
                                       blocking or non-blocking mode. Zero means\r
                                       infinity.  If the timeout expires before\r
@@ -442,7 +397,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
@@ -472,7 +438,7 @@ MpInitLibStartupAllAPs (
                                       EFI_EVENT is defined in CreateEvent() in\r
                                       the Unified Extensible Firmware Interface\r
                                       Specification.\r
-  @param[in]  TimeoutInMicrosecsond   Indicates the time limit in microseconds for\r
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
                                       this AP to finish this Procedure, either for\r
                                       blocking or non-blocking mode. Zero means\r
                                       infinity.  If the timeout expires before\r
@@ -527,7 +493,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
@@ -604,7 +581,7 @@ MpInitLibEnableDisableAP (
   IN  UINT32                    *HealthFlag OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
 }\r
 \r
 \r