]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Add ApWakeupFunction() executed by assembly code
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
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