]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/CpuDxe: Put APs in wait for SIPI state at ExitBootServices
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuMp.c
index b576d18ca451cd4a17478f8e1530a01f917fcad3..b65300c773c6b5ce1ec43daf33c178924bdc5a95 100644 (file)
@@ -20,21 +20,57 @@ UINTN gApStackSize;
 UINTN gPollInterval = 100; // 100 microseconds\r
 \r
 MP_SYSTEM_DATA mMpSystemData;\r
+EFI_HANDLE     mMpServiceHandle       = NULL;\r
+EFI_EVENT      mExitBootServicesEvent = (EFI_EVENT)NULL;\r
 \r
 VOID *mCommonStack = 0;\r
 VOID *mTopOfApCommonStack = 0;\r
 VOID *mApStackStart = 0;\r
 \r
+volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;\r
+volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;\r
+\r
 EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {\r
   GetNumberOfProcessors,\r
   GetProcessorInfo,\r
   StartupAllAPs,\r
   StartupThisAP,\r
-  NULL, // SwitchBSP,\r
+  SwitchBSP,\r
   EnableDisableAP,\r
   WhoAmI\r
 };\r
 \r
+/**\r
+   Get Mp Service Lock.\r
+\r
+  @param   CpuData    the pointer to CPU_DATA_BLOCK of specified processor\r
+\r
+**/\r
+VOID\r
+GetMpSpinLock (\r
+  IN  CPU_DATA_BLOCK  *CpuData\r
+  )\r
+{\r
+  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
+    CpuPause ();\r
+  }\r
+  CpuData->LockSelf = GetApicId ();\r
+}\r
+\r
+/**\r
+   Release Mp Service Lock.\r
+\r
+  @param   CpuData    the pointer to CPU_DATA_BLOCK of specified processor\r
+\r
+**/\r
+VOID\r
+ReleaseMpSpinLock (\r
+  IN  CPU_DATA_BLOCK  *CpuData\r
+  )\r
+{\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+}\r
+\r
 /**\r
   Check whether caller processor is BSP.\r
 \r
@@ -73,12 +109,9 @@ GetApState (
 {\r
   CPU_STATE State;\r
 \r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   State = CpuData->State;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 \r
   return State;\r
 }\r
@@ -96,12 +129,9 @@ SetApState (
   IN  CPU_STATE        State\r
   )\r
 {\r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   CpuData->State = State;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 }\r
 \r
 /**\r
@@ -120,13 +150,10 @@ SetApProcedure (
   IN   VOID                  *ProcedureArgument\r
   )\r
 {\r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   CpuData->Parameter  = ProcedureArgument;\r
   CpuData->Procedure  = Procedure;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 }\r
 \r
 /**\r
@@ -147,12 +174,9 @@ TestCpuStatusFlag (
 {\r
   UINT32 Ret;\r
 \r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   Ret = CpuData->Info.StatusFlag & Flags;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 \r
   return !!(Ret);\r
 }\r
@@ -170,12 +194,9 @@ CpuStatusFlagOr (
   IN  UINT32          Flags\r
   )\r
 {\r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   CpuData->Info.StatusFlag |= Flags;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 }\r
 \r
 /**\r
@@ -191,12 +212,9 @@ CpuStatusFlagAndNot (
   IN  UINT32          Flags\r
   )\r
 {\r
-  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
-    CpuPause ();\r
-  }\r
-\r
+  GetMpSpinLock (CpuData);\r
   CpuData->Info.StatusFlag &= ~Flags;\r
-  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  ReleaseMpSpinLock (CpuData);\r
 }\r
 \r
 /**\r
@@ -616,6 +634,11 @@ StartupAllAPs (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
+  //\r
+  mStopCheckAllAPsStatus = TRUE;\r
+\r
   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
     CpuData = &mMpSystemData.CpuDatas[Number];\r
     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
@@ -686,15 +709,20 @@ StartupAllAPs (
     }\r
   }\r
 \r
+  mStopCheckAllAPsStatus = FALSE;\r
+\r
   if (WaitEvent != NULL) {\r
-    Status = gBS->SetTimer (\r
-                    mMpSystemData.CheckAllAPsEvent,\r
-                    TimerPeriodic,\r
-                    EFI_TIMER_PERIOD_MICROSECONDS (100)\r
-                    );\r
-    return Status;\r
+    //\r
+    // non blocking\r
+    //\r
+    return EFI_SUCCESS;\r
   }\r
 \r
+  //\r
+  // Blocking temporarily stop CheckAllAPsStatus()\r
+  //\r
+  mStopCheckAllAPsStatus = TRUE;\r
+\r
   while (TRUE) {\r
     CheckAndUpdateAllAPsToIdleState ();\r
     if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {\r
@@ -819,7 +847,6 @@ StartupThisAP (
   )\r
 {\r
   CPU_DATA_BLOCK        *CpuData;\r
-  EFI_STATUS            Status;\r
 \r
   CpuData = NULL;\r
 \r
@@ -839,6 +866,11 @@ StartupThisAP (
     return EFI_NOT_FOUND;\r
   }\r
 \r
+  //\r
+  // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
+  //\r
+  mStopCheckAllAPsStatus = TRUE;\r
+\r
   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
   if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||\r
       !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
@@ -858,16 +890,13 @@ StartupThisAP (
   CpuData->TimeoutActive = !!(TimeoutInMicroseconds);\r
   CpuData->Finished = Finished;\r
 \r
+  mStopCheckAllAPsStatus = FALSE;\r
+\r
   if (WaitEvent != NULL) {\r
     //\r
     // Non Blocking\r
     //\r
-    Status = gBS->SetTimer (\r
-                    CpuData->CheckThisAPEvent,\r
-                    TimerPeriodic,\r
-                    EFI_TIMER_PERIOD_MICROSECONDS (100)\r
-                    );\r
-    return Status;\r
+    return EFI_SUCCESS;\r
   }\r
 \r
   //\r
@@ -891,6 +920,55 @@ StartupThisAP (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This service switches the requested AP to be the BSP from that point onward.\r
+  This service changes the BSP for all purposes.   This call can only be performed\r
+  by the current BSP.\r
+\r
+  This service switches the requested AP to be the BSP from that point onward.\r
+  This service changes the BSP for all purposes. The new BSP can take over the\r
+  execution of the old BSP and continue seamlessly from where the old one left\r
+  off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT\r
+  is signaled.\r
+\r
+  If the BSP cannot be switched prior to the return from this service, then\r
+  EFI_UNSUPPORTED must be returned.\r
+\r
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new\r
+                               BSP. The range is from 0 to the total number of\r
+                               logical processors minus 1. The total number of\r
+                               logical processors can be retrieved by\r
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an\r
+                               enabled AP. Otherwise, it will be disabled.\r
+\r
+  @retval EFI_SUCCESS             BSP successfully switched.\r
+  @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_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
+                                  a disabled AP.\r
+  @retval EFI_NOT_READY           The specified AP is busy.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SwitchBSP (\r
+  IN EFI_MP_SERVICES_PROTOCOL  *This,\r
+  IN  UINTN                    ProcessorNumber,\r
+  IN  BOOLEAN                  EnableOldBSP\r
+  )\r
+{\r
+   //\r
+   // Current always return unsupported.\r
+   //\r
+   return EFI_UNSUPPORTED;\r
+}\r
+\r
 /**\r
   This service lets the caller enable or disable an AP from this point onward.\r
   This service may only be called from the BSP.\r
@@ -942,6 +1020,10 @@ EnableDisableAP (
   )\r
 {\r
   CPU_DATA_BLOCK *CpuData;\r
+  BOOLEAN        TempStopCheckState;\r
+\r
+  CpuData = NULL;\r
+  TempStopCheckState = FALSE;\r
 \r
   if (!IsBSP ()) {\r
     return EFI_DEVICE_ERROR;\r
@@ -951,6 +1033,14 @@ EnableDisableAP (
     return EFI_NOT_FOUND;\r
   }\r
 \r
+  //\r
+  // temporarily stop checkAllAPsStatus for initialize parameters.\r
+  //\r
+  if (!mStopCheckAllAPsStatus) {\r
+    mStopCheckAllAPsStatus = TRUE;\r
+    TempStopCheckState = TRUE;\r
+  }\r
+\r
   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
   if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -977,6 +1067,10 @@ EnableDisableAP (
     CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));\r
   }\r
 \r
+  if (TempStopCheckState) {\r
+    mStopCheckAllAPsStatus = FALSE;\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1043,6 +1137,7 @@ ResetProcessorToIdleState (
   IN CPU_DATA_BLOCK  *CpuData\r
   )\r
 {\r
+  ResetApStackless ((UINT32)CpuData->Info.ProcessorId);\r
 }\r
 \r
 /**\r
@@ -1059,10 +1154,53 @@ ProcessorToIdleState (
   IN      VOID                      *Context2   OPTIONAL\r
   )\r
 {\r
-  DEBUG ((DEBUG_INFO, "Ap apicid is %d\n", GetApicId ()));\r
+  UINTN                 ProcessorNumber;\r
+  CPU_DATA_BLOCK        *CpuData;\r
+  EFI_AP_PROCEDURE      Procedure;\r
+  VOID                  *ProcedureArgument;\r
 \r
   AsmApDoneWithCommonStack ();\r
 \r
+  while (!mAPsAlreadyInitFinished) {\r
+    CpuPause ();\r
+  }\r
+\r
+  WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
+  CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
+\r
+  //\r
+  // Avoid forcibly reset AP caused the AP got lock not release.\r
+  //\r
+  if (CpuData->LockSelf == (INTN) GetApicId ()) {\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  }\r
+\r
+  //\r
+  // Avoid forcibly reset AP caused the AP State is not updated.\r
+  //\r
+  GetMpSpinLock (CpuData);\r
+  CpuData->State = CpuStateIdle;\r
+  CpuData->Procedure = NULL;\r
+  ReleaseMpSpinLock (CpuData);\r
+\r
+  while (TRUE) {\r
+    GetMpSpinLock (CpuData);\r
+    ProcedureArgument = CpuData->Parameter;\r
+    Procedure = CpuData->Procedure;\r
+    ReleaseMpSpinLock (CpuData);\r
+\r
+    if (Procedure != NULL) {\r
+      Procedure (ProcedureArgument);\r
+\r
+      GetMpSpinLock (CpuData);\r
+      CpuData->Procedure = NULL;\r
+      CpuData->State = CpuStateFinished;\r
+      ReleaseMpSpinLock (CpuData);\r
+    }\r
+\r
+    CpuPause ();\r
+  }\r
+\r
   CpuSleep ();\r
   CpuDeadLoop ();\r
 }\r
@@ -1114,11 +1252,9 @@ CheckThisAPStatus (
   return;\r
 \r
 out:\r
-  gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);\r
-  if (CpuData->WaitEvent) {\r
-    gBS->SignalEvent (CpuData->WaitEvent);\r
-    CpuData->WaitEvent = NULL;\r
-  }\r
+  CpuData->TimeoutActive = FALSE;\r
+  gBS->SignalEvent (CpuData->WaitEvent);\r
+  CpuData->WaitEvent = NULL;\r
 }\r
 \r
 /**\r
@@ -1138,37 +1274,70 @@ CheckAllAPsStatus (
   IN  VOID             *Context\r
   )\r
 {\r
+  CPU_DATA_BLOCK *CpuData;\r
+  UINTN          Number;\r
+  EFI_STATUS     Status;\r
+\r
   if (mMpSystemData.TimeoutActive) {\r
     mMpSystemData.Timeout -= gPollInterval;\r
   }\r
 \r
-  CheckAndUpdateAllAPsToIdleState ();\r
+  if (mStopCheckAllAPsStatus) {\r
+    return;\r
+  }\r
 \r
   //\r
-  // task timeout\r
+  // avoid next timer enter.\r
   //\r
-  if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
-    ResetAllFailedAPs();\r
+  Status = gBS->SetTimer (\r
+                  mMpSystemData.CheckAllAPsEvent,\r
+                  TimerCancel,\r
+                  0\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (mMpSystemData.WaitEvent != NULL) {\r
+    CheckAndUpdateAllAPsToIdleState ();\r
     //\r
-    // force exit\r
+    // task timeout\r
     //\r
-    mMpSystemData.FinishCount = mMpSystemData.StartCount;\r
-  }\r
-\r
-  if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {\r
-    return;\r
-  }\r
+    if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
+      ResetAllFailedAPs();\r
+      //\r
+      // force exit\r
+      //\r
+      mMpSystemData.FinishCount = mMpSystemData.StartCount;\r
+    }\r
 \r
-  gBS->SetTimer (\r
-         mMpSystemData.CheckAllAPsEvent,\r
-         TimerCancel,\r
-         0\r
-         );\r
+    if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {\r
+      goto EXIT;\r
+    }\r
 \r
-  if (mMpSystemData.WaitEvent) {\r
+    mMpSystemData.TimeoutActive = FALSE;\r
     gBS->SignalEvent (mMpSystemData.WaitEvent);\r
     mMpSystemData.WaitEvent = NULL;\r
+    mStopCheckAllAPsStatus = TRUE;\r
+\r
+    goto EXIT;\r
   }\r
+\r
+  //\r
+  // check each AP status for StartupThisAP\r
+  //\r
+  for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
+    CpuData = &mMpSystemData.CpuDatas[Number];\r
+    if (CpuData->WaitEvent) {\r
+      CheckThisAPStatus (NULL, (VOID *)CpuData);\r
+    }\r
+  }\r
+\r
+EXIT:\r
+  Status = gBS->SetTimer (\r
+                  mMpSystemData.CheckAllAPsEvent,\r
+                  TimerPeriodic,\r
+                  EFI_TIMER_PERIOD_MICROSECONDS (100)\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
 /**\r
@@ -1181,13 +1350,27 @@ ApEntryPointInC (
   VOID\r
   )\r
 {\r
-  VOID* TopOfApStack;\r
+  VOID*           TopOfApStack;\r
+  UINTN           ProcessorNumber;\r
 \r
-  FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);\r
-  TopOfApStack  = (UINT8*)mApStackStart + gApStackSize;\r
-  mApStackStart = TopOfApStack;\r
+  if (!mAPsAlreadyInitFinished) {\r
+    FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);\r
+    TopOfApStack  = (UINT8*)mApStackStart + gApStackSize;\r
+    mApStackStart = TopOfApStack;\r
 \r
-  mMpSystemData.NumberOfProcessors++;\r
+    //\r
+    // Store the Stack address, when reset the AP, We can found the original address.\r
+    //\r
+    mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;\r
+    mMpSystemData.NumberOfProcessors++;\r
+    mMpSystemData.NumberOfEnabledProcessors++;\r
+  } else {\r
+    WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
+    //\r
+    // Get the original stack address.\r
+    //\r
+    TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;\r
+  }\r
 \r
   SwitchStack (\r
     (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,\r
@@ -1229,6 +1412,7 @@ FillInProcessorInformation (
   CpuData->Procedure        = NULL;\r
   CpuData->Parameter        = NULL;\r
   InitializeSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->LockSelf         = -1;\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -1244,8 +1428,6 @@ InitMpSystemData (
   VOID\r
   )\r
 {\r
-  UINTN          ProcessorNumber;\r
-  CPU_DATA_BLOCK *CpuData;\r
   EFI_STATUS     Status;\r
 \r
   ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));\r
@@ -1265,17 +1447,15 @@ InitMpSystemData (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  for (ProcessorNumber = 0; ProcessorNumber < gMaxLogicalProcessorNumber; ProcessorNumber++) {\r
-    CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
-    Status = gBS->CreateEvent (\r
-                    EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
-                    TPL_CALLBACK,\r
-                    CheckThisAPStatus,\r
-                    (VOID *) CpuData,\r
-                    &CpuData->CheckThisAPEvent\r
-                    );\r
-    ASSERT_EFI_ERROR (Status);\r
-  }\r
+  //\r
+  // Set timer to check all APs status.\r
+  //\r
+  Status = gBS->SetTimer (\r
+                  mMpSystemData.CheckAllAPsEvent,\r
+                  TimerPeriodic,\r
+                  EFI_TIMER_PERIOD_MICROSECONDS (100)\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
   // BSP\r
@@ -1285,6 +1465,28 @@ InitMpSystemData (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Callback function for ExitBootServices.\r
+\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               The pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ExitBootServicesCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  //\r
+  // Avoid APs access invalid buff datas which allocated by BootServices,\r
+  // so we send INIT IPI to APs to let them wait for SIPI state.\r
+  //\r
+  SendInitIpiAllExcludingSelf ();\r
+}\r
+\r
 /**\r
   Initialize Multi-processor support.\r
 \r
@@ -1294,6 +1496,8 @@ InitializeMpSupport (
   VOID\r
   )\r
 {\r
+  EFI_STATUS Status;\r
+\r
   gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
   if (gMaxLogicalProcessorNumber < 1) {\r
     DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));\r
@@ -1320,14 +1524,43 @@ InitializeMpSupport (
 \r
   InitMpSystemData ();\r
 \r
+  PrepareAPStartupCode ();\r
+\r
+  StartApsStackless ();\r
+\r
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));\r
   if (mMpSystemData.NumberOfProcessors == 1) {\r
+    FreeApStartupCode ();\r
     FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));\r
     return;\r
   }\r
 \r
+  mMpSystemData.CpuDatas = ReallocatePool (\r
+                             sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,\r
+                             sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,\r
+                             mMpSystemData.CpuDatas);\r
+\r
+  mAPsAlreadyInitFinished = TRUE;\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mMpServiceHandle,\r
+                  &gEfiMpServiceProtocolGuid,  &mMpServicesTemplate,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {\r
     FreePages (mApStackStart, EFI_SIZE_TO_PAGES (\r
                                 (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *\r
                                 gApStackSize));\r
   }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+                  TPL_CALLBACK,\r
+                  ExitBootServicesCallback,\r
+                  NULL,\r
+                  &mExitBootServicesEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 }\r