]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/MpInitLib: Add ApWakeupFunction() executed by assembly code
authorJeff Fan <jeff.fan@intel.com>
Wed, 20 Jul 2016 16:20:26 +0000 (00:20 +0800)
committerJeff Fan <jeff.fan@intel.com>
Wed, 17 Aug 2016 12:00:54 +0000 (20:00 +0800)
ApWakeupFunction() is the first C function executed from AP reset vector. When
APs waken up at the first time, it will sync BSP's MTRR setting and load
microcode on APs and collect APs' BIST information.

When AP tasked finished, it will place APs it one loop specified by ApLoopMode.

v5:
  1. Rename ApCFunction to ApWakeupFunction to meet naming convention.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/Library/MpInitLib/MpLib.h

index 8dfbf5706ae45b817db8aef390a90d3118cc3627..a4a2c440c08dd7d55ba687aee1d36ac9987c0e7e 100644 (file)
@@ -174,6 +174,59 @@ GetApLoopMode (
 \r
   return ApLoopMode;\r
 }\r
+\r
+/**\r
+  Do sync on APs.\r
+\r
+  @param[in, out] Buffer  Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+ApInitializeSync (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  CPU_MP_DATA  *CpuMpData;\r
+\r
+  CpuMpData = (CPU_MP_DATA *) Buffer;\r
+  //\r
+  // Sync BSP's MTRR table to AP\r
+  //\r
+  MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
+  //\r
+  // Load microcode on AP\r
+  //\r
+  MicrocodeDetect (CpuMpData);\r
+}\r
+\r
+/**\r
+  Find the current Processor number by APIC ID.\r
+\r
+  @param[in] CpuMpData         Pointer to PEI CPU MP Data\r
+  @param[in] ProcessorNumber   Return the pocessor number found\r
+\r
+  @retval EFI_SUCCESS          ProcessorNumber is found and returned.\r
+  @retval EFI_NOT_FOUND        ProcessorNumber is not found.\r
+**/\r
+EFI_STATUS\r
+GetProcessorNumber (\r
+  IN CPU_MP_DATA               *CpuMpData,\r
+  OUT UINTN                    *ProcessorNumber\r
+  )\r
+{\r
+  UINTN                   TotalProcessorNumber;\r
+  UINTN                   Index;\r
+\r
+  TotalProcessorNumber = CpuMpData->CpuCount;\r
+  for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
+    if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {\r
+      *ProcessorNumber = Index;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
 /*\r
   Initialize CPU AP Data when AP is wakeup at the first time.\r
 \r
@@ -208,6 +261,151 @@ InitializeApData (
   SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
 }\r
 \r
+/**\r
+  This function will be called from AP reset code if BSP uses WakeUpAP.\r
+\r
+  @param[in] ExchangeInfo     Pointer to the MP exchange info buffer\r
+  @param[in] NumApsExecuting  Number of current executing AP\r
+**/\r
+VOID\r
+EFIAPI\r
+ApWakeupFunction (\r
+  IN MP_CPU_EXCHANGE_INFO      *ExchangeInfo,\r
+  IN UINTN                     NumApsExecuting\r
+  )\r
+{\r
+  CPU_MP_DATA                *CpuMpData;\r
+  UINTN                      ProcessorNumber;\r
+  EFI_AP_PROCEDURE           Procedure;\r
+  VOID                       *Parameter;\r
+  UINT32                     BistData;\r
+  volatile UINT32            *ApStartupSignalBuffer;\r
+\r
+  //\r
+  // AP finished assembly code and begin to execute C code\r
+  //\r
+  CpuMpData = ExchangeInfo->CpuMpData;\r
+\r
+  ProgramVirtualWireMode (); \r
+\r
+  while (TRUE) {\r
+    if (CpuMpData->InitFlag == ApInitConfig) {\r
+      //\r
+      // Add CPU number\r
+      //\r
+      InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
+      ProcessorNumber = NumApsExecuting;\r
+      //\r
+      // This is first time AP wakeup, get BIST information from AP stack\r
+      //\r
+      BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
+      //\r
+      // Do some AP initialize sync\r
+      //\r
+      ApInitializeSync (CpuMpData);\r
+      //\r
+      // Sync BSP's Control registers to APs\r
+      //\r
+      RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
+      InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
+      ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
+    } else {\r
+      //\r
+      // Execute AP function if AP is ready\r
+      //\r
+      GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
+      //\r
+      // Clear AP start-up signal when AP waken up\r
+      //\r
+      ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
+      InterlockedCompareExchange32 (\r
+        (UINT32 *) ApStartupSignalBuffer,\r
+        WAKEUP_AP_SIGNAL,\r
+        0\r
+        );\r
+      if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
+        //\r
+        // Restore AP's volatile registers saved\r
+        //\r
+        RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
+      }\r
+\r
+      if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
+        Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
+        Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
+        if (Procedure != NULL) {\r
+          SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
+          //\r
+          // Invoke AP function here\r
+          //\r
+          Procedure (Parameter);\r
+          //\r
+          // Re-get the CPU APICID and Initial APICID\r
+          //\r
+          CpuMpData->CpuData[ProcessorNumber].ApicId        = GetApicId ();\r
+          CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+        }\r
+        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
+      }\r
+    }\r
+\r
+    //\r
+    // AP finished executing C code\r
+    //\r
+    InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
+\r
+    //\r
+    // Place AP is specified loop mode\r
+    //\r
+    if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
+      //\r
+      // Save AP volatile registers\r
+      //\r
+      SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
+      //\r
+      // Place AP in HLT-loop\r
+      //\r
+      while (TRUE) {\r
+        DisableInterrupts ();\r
+        CpuSleep ();\r
+        CpuPause ();\r
+      }\r
+    }\r
+    while (TRUE) {\r
+      DisableInterrupts ();\r
+      if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
+        //\r
+        // Place AP in MWAIT-loop\r
+        //\r
+        AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
+        if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
+          //\r
+          // Check AP start-up signal again.\r
+          // If AP start-up signal is not set, place AP into\r
+          // the specified C-state\r
+          //\r
+          AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
+        }\r
+      } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
+        //\r
+        // Place AP in Run-loop\r
+        //\r
+        CpuPause ();\r
+      } else {\r
+        ASSERT (FALSE);\r
+      }\r
+\r
+      //\r
+      // If AP start-up signal is written, AP is waken up\r
+      // otherwise place AP in loop again\r
+      //\r
+      if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   MP Initialize Library initialization.\r
 \r
index 80ea0b4e095fe8fa16a428fdf4b3d13c52b4f4be..72a35ef7beb2601c29dbd64b4989edcf38da4ebd 100644 (file)
@@ -35,6 +35,8 @@
 #include <Library/MtrrLib.h>\r
 #include <Library/HobLib.h>\r
 \r
+#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')\r
+\r
 #define CPU_INIT_MP_LIB_HOB_GUID \\r
   { \\r
     0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \\r