Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Chen Fan <chen.fan.f...@cn.fujitsu.com>
---
 UefiCpuPkg/CpuDxe/CpuMp.c | 232 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 231 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
index f39e2db..7623a35 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.c
+++ b/UefiCpuPkg/CpuDxe/CpuMp.c
@@ -22,6 +22,15 @@ CPU_MP_SERVICE_DATA *mMpServiceData;
 UINTN mCpuIndex = 0;
 
 EFI_HANDLE              mMpServiceHandle = NULL;
+UINTN                   gPollInterval = 100; // 100us
+
+VOID
+SendCallFuncIpi (
+  IN UINT64  cpu
+  )
+{
+  SendFixedIpi (cpu, CALL_FUNCTION_VECTOR);
+}
 
 VOID
 SetApState (
@@ -226,6 +235,173 @@ MpServicesGetProcessorInfo (
 }
 
 /**
+  This service lets the caller get one enabled AP to execute a caller-provided
+  function. The caller can request the BSP to either wait for the completion
+  of the AP or just proceed with the next task by using the EFI event 
mechanism.
+  See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+  execution support.  This service may only be called from the BSP.
+
+  This function is used to dispatch one enabled AP to the function specified by
+  Procedure passing in the argument specified by ProcedureArgument.  If 
WaitEvent
+  is NULL, execution is in blocking mode. The BSP waits until the AP finishes 
or
+  TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+  BSP proceeds to the next task without waiting for the AP. If a non-blocking 
mode
+  is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+  then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before the AP 
returns
+  from Procedure, then execution of Procedure by the AP is terminated. The AP 
is
+  available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() 
and
+  EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The range is
+                                      from 0 to the total number of logical
+                                      processors minus 1. The total number of
+                                      logical processors can be retrieved by
+                                      
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in]  WaitEvent               The event created by the caller with 
CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until all APs 
finish
+                                      or TimeoutInMicroseconds expires.  If 
it's
+                                      not NULL, then execute in non-blocking 
mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on all the 
enabled
+                                      APs, and go on executing immediately. If
+                                      all return from Procedure or 
TimeoutInMicroseconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or 
WaitForEvent()
+                                      services to check the state of event.  
Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicrosecsond   Indicates the time limit in microseconds 
for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      all APs return from Procedure, then 
Procedure
+                                      on the failed APs is terminated. All 
enabled
+                                      APs are available for next function 
assigned
+                                      by 
EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+                                      or 
EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] Finished                If NULL, this parameter is ignored.  In
+                                      blocking mode, this parameter is ignored.
+                                      In non-blocking mode, if AP returns from
+                                      Procedure before the timeout expires, its
+                                      content is set to TRUE. Otherwise, the
+                                      value is set to FALSE. The caller can
+                                      determine if the AP returned from 
Procedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished 
before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has been
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after 
the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or 
disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpServicesStartupThisAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE          Procedure,
+  IN  UINTN                     ProcessorNumber,
+  IN  EFI_EVENT                 WaitEvent               OPTIONAL,
+  IN  UINTN                     TimeoutInMicroseconds,
+  IN  VOID                      *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN                   *Finished               OPTIONAL
+  )
+{
+  UINTN                 Timeout = 0;
+  PROCESSOR_DATA_BLOCK  *ProcessorData;
+  UINT64                ProcessorId;
+  EFI_STATUS            Status;
+
+  if (!IsBSP ()) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Procedure == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (ProcessorNumber >= mMpServiceData->NumberOfProcessors) {
+    return EFI_NOT_FOUND;
+  }
+
+  ProcessorData = mMpServiceData->ProcessorData[ProcessorNumber];
+  if (TestProcessorStatusFlag (ProcessorData, PROCESSOR_AS_BSP_BIT)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (GetApState (ProcessorData) != CPU_STATE_IDLE) {
+    return EFI_NOT_READY;
+  }
+
+  ProcessorId = ProcessorData->Info.ProcessorId;
+
+  SetApProcedure (ProcessorData, Procedure, ProcedureArgument);
+
+  SetApState (ProcessorData, CPU_STATE_READY);
+  SendCallFuncIpi (ProcessorId);
+  SetApState (ProcessorData, CPU_STATE_BUSY);
+
+  ProcessorData->MpData.Timeout = TimeoutInMicroseconds;
+  ProcessorData->MpData.WaitEvent = WaitEvent;
+  ProcessorData->MpData.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
+
+  Timeout = TimeoutInMicroseconds;
+
+  if (WaitEvent != NULL) {
+    // Non Blocking
+    Status = gBS->SetTimer (
+                    ProcessorData->CheckThisAPEvent,
+                    TimerPeriodic,
+                    EFI_TIMER_PERIOD_MICROSECONDS (1)
+                    );
+    return Status;
+  }
+
+  // Blocking
+  while (TRUE) {
+    if (GetApState (ProcessorData) == CPU_STATE_FINISHED) {
+      SetApState (ProcessorData, CPU_STATE_IDLE);
+      break;
+    }
+
+    if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) {
+      SetApState (ProcessorData, CPU_STATE_IDLE);
+      return EFI_TIMEOUT;
+    }
+
+    gBS->Stall (gPollInterval);
+    Timeout -= gPollInterval;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
   This service lets the caller enable or disable an AP from this point onward.
   This service may only be called from the BSP.
 
@@ -363,12 +539,53 @@ MpServicesWhoAmI (
   return EFI_SUCCESS;
 }
 
+VOID
+EFIAPI
+CpuCheckThisAPStatus (
+  IN  EFI_EVENT        Event,
+  IN  VOID             *Context
+  )
+{
+   PROCESSOR_DATA_BLOCK  *ProcessorData;
+   PROCESSOR_STATE       ProcessorState;
+
+   ProcessorData = (PROCESSOR_DATA_BLOCK *) Context;
+   if (ProcessorData->MpData.TimeoutActive) {
+     ProcessorData->MpData.Timeout -= gPollInterval;
+   }
+
+   ProcessorState = GetApState (ProcessorData);
+
+   if (ProcessorState == CPU_STATE_FINISHED) {
+     if (ProcessorData->Finished) {
+       *ProcessorData->Finished = TRUE;
+     }
+     goto out;
+   }
+
+   if (ProcessorData->MpData.TimeoutActive && ProcessorData->MpData.Timeout < 
0) {
+     if (ProcessorState != CPU_STATE_IDLE &&
+         ProcessorData->Finished) {
+       *ProcessorData->Finished = FALSE;
+     }
+     goto out;
+   }
+
+   return;
+
+out:
+   gBS->SetTimer (ProcessorData->CheckThisAPEvent, TimerCancel, 0);
+   gBS->SignalEvent (ProcessorData->MpData.WaitEvent);
+   SetApState (ProcessorData, CPU_STATE_IDLE);
+
+   return;
+}
 
 EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
   MpServicesGetNumberOfProcessors,
   MpServicesGetProcessorInfo,
   NULL, // MpServicesStartupAllAps,
-  NULL, // MpServicesStartupThisAP,
+  MpServicesStartupThisAP,
   NULL, // MpServicesSwitchBSP,
   MpServicesEnableDisableAP,
   MpServicesWhoAmI
@@ -400,6 +617,15 @@ InitMpSystemData (
     ProcessorData->MpData.Procedure = NULL;
     ProcessorData->MpData.Parameter = NULL;
     InitializeSpinLock (&ProcessorData->MpData.ProcedureLock);
+
+    Status = gBS->CreateEvent (
+                      EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                      TPL_CALLBACK,
+                      CpuCheckThisAPStatus,
+                      (VOID *) ProcessorData,
+                      &ProcessorData->CheckThisAPEvent
+                      );
+    ASSERT_EFI_ERROR (Status);
   }
 
   Status = gBS->InstallMultipleProtocolInterfaces (
@@ -456,6 +682,8 @@ CallFunctionInterrupt (
 
   ProcessorId = GetApicId();
 
+  DisableInterrupts ();
+
   for (CpuIndex = 0; CpuIndex < mMpServiceData->NumberOfProcessors; 
CpuIndex++) {
     if (mMpServiceData->ProcessorData[CpuIndex]->Info.ProcessorId == 
ProcessorId) {
       ProcessorData = mMpServiceData->ProcessorData[CpuIndex];
@@ -470,6 +698,8 @@ CallFunctionInterrupt (
     SetApProcedure (ProcessorData, NULL, NULL);
     SetApState (ProcessorData, CPU_STATE_FINISHED);
   }
+
+  EnableInterrupts ();
   SendApicEoi ();
 }
 
-- 
1.9.3


------------------------------------------------------------------------------
Infragistics Professional
Build stunning WinForms apps today!
Reboot your WinForms applications with our WinForms controls. 
Build a bridge from your legacy apps to the future.
http://pubads.g.doubleclick.net/gampad/clk?id=153845071&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to