Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Chen Fan <[email protected]>
---
 UefiCpuPkg/CpuDxe/CpuMp.c | 282 +++++++++++++++++++++++++++++++++++++++++++++-
 UefiCpuPkg/CpuDxe/CpuMp.h | 108 +++++++++++++++++-
 2 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
index ee107ef..883f598 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.c
+++ b/UefiCpuPkg/CpuDxe/CpuMp.c
@@ -16,6 +16,7 @@
 #include "CpuMp.h"
 
 UINTN gApStackSize;
+UINTN gPollInterval = 100; // 100 microseconds
 
 MP_SYSTEM_DATA mMpSystemData;
 
@@ -30,7 +31,7 @@ EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
   GetNumberOfProcessors,
   GetProcessorInfo,
   NULL, // StartupAllAps,
-  NULL, // StartupThisAP,
+  StartupThisAP,
   NULL, // SwitchBSP,
   EnableDisableAP,
   WhoAmI
@@ -85,6 +86,52 @@ GetApState (
 }
 
 /**
+  Set the Application Processors state.
+
+  @param   CpuData    The pointer to CPU_DATA_BLOCK of specified AP
+  @param   State      The AP status
+
+**/
+VOID
+SetApState (
+  IN  CPU_DATA_BLOCK   *CpuData,
+  IN  CPU_STATE        State
+  )
+{
+  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
+    CpuPause ();
+  }
+
+  CpuData->State = State;
+  ReleaseSpinLock (&CpuData->CpuDataLock);
+}
+
+/**
+  Set the Application Processor prepare to run a function specified
+  by Params.
+
+  @param CpuData           the pointer to CPU_DATA_BLOCK of specified AP
+  @param Procedure         A pointer to the function to be run on enabled APs 
of the system
+  @param ProcedureArgument Pointer to the optional parameter of the assigned 
function
+
+**/
+VOID
+SetApProcedure (
+  IN   CPU_DATA_BLOCK        *CpuData,
+  IN   EFI_AP_PROCEDURE      Procedure,
+  IN   VOID                  *ProcedureArgument
+  )
+{
+  while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
+    CpuPause ();
+  }
+
+  CpuData->Parameter  = ProcedureArgument;
+  CpuData->Procedure  = Procedure;
+  ReleaseSpinLock (&CpuData->CpuDataLock);
+}
+
+/**
   Check the Application Processors Status whether contains the Flags.
 
   @param     CpuData  the pointer to CPU_DATA_BLOCK of specified AP
@@ -262,6 +309,174 @@ GetProcessorInfo (
 }
 
 /**
+  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]  TimeoutInMicroseconds   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
+StartupThisAP (
+  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;
+  CPU_DATA_BLOCK        *CpuData;
+  EFI_STATUS            Status;
+
+  Timeout = 0;
+
+  if (!IsBSP ()) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Procedure == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
+    return EFI_NOT_FOUND;
+  }
+
+  CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
+  if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (GetApState (CpuData) != CpuStateIdle) {
+    return EFI_NOT_READY;
+  }
+
+  SetApState (CpuData, CpuStateReady);
+
+  SetApProcedure (CpuData, Procedure, ProcedureArgument);
+
+  CpuData->Timeout = TimeoutInMicroseconds;
+  CpuData->WaitEvent = WaitEvent;
+  CpuData->TimeoutActive = !!(TimeoutInMicroseconds);
+
+  Timeout = TimeoutInMicroseconds;
+
+  if (WaitEvent != NULL) {
+    //
+    // Non Blocking
+    //
+    Status = gBS->SetTimer (
+                    CpuData->CheckThisAPEvent,
+                    TimerPeriodic,
+                    EFI_TIMER_PERIOD_MICROSECONDS (100)
+                    );
+    return Status;
+  }
+
+  //
+  // Blocking
+  //
+  while (TRUE) {
+    if (GetApState (CpuData) == CpuStateFinished) {
+      SetApState (CpuData, CpuStateIdle);
+      break;
+    }
+
+    if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) {
+      SetApState (CpuData, CpuStateIdle);
+      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.
 
@@ -400,6 +615,61 @@ WhoAmI (
 }
 
 /**
+  Checks APs' status periodically.
+
+  This function is triggerred by timer perodically to check the
+  state of AP forStartupThisAP() executed in non-blocking mode.
+
+  @param  Event    Event triggered.
+  @param  Context  Parameter passed with the event.
+
+**/
+VOID
+EFIAPI
+CheckThisAPStatus (
+  IN  EFI_EVENT        Event,
+  IN  VOID             *Context
+  )
+{
+   CPU_DATA_BLOCK  *CpuData;
+   CPU_STATE       CpuState;
+
+   CpuData = (CPU_DATA_BLOCK *) Context;
+   if (CpuData->TimeoutActive) {
+     CpuData->Timeout -= gPollInterval;
+   }
+
+   CpuState = GetApState (CpuData);
+
+   if (CpuState == CpuStateFinished) {
+     if (CpuData->Finished) {
+       *CpuData->Finished = TRUE;
+     }
+     goto out;
+   }
+
+   if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
+     if (CpuState != CpuStateIdle &&
+         CpuData->Finished) {
+       *CpuData->Finished = FALSE;
+     }
+     goto out;
+   }
+
+   return;
+
+out:
+   gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);
+   if (CpuData->WaitEvent) {
+     gBS->SignalEvent (CpuData->WaitEvent);
+     CpuData->WaitEvent = NULL;
+   }
+   SetApState (CpuData, CpuStateIdle);
+
+   return;
+}
+
+/**
   Application Processor C code entry point.
 
 **/
@@ -439,6 +709,7 @@ InitMpSystemData (
 {
   UINTN          CpuIndex;
   CPU_DATA_BLOCK *CpuData;
+  EFI_STATUS     Status;
 
   for (CpuIndex = 0; CpuIndex < mMpSystemData.NumberOfProcessors; CpuIndex++) {
     CpuData = &mMpSystemData.CpuDatas[CpuIndex];
@@ -452,6 +723,15 @@ InitMpSystemData (
     CpuData->Info.Location.Thread  = 0;
 
     InitializeSpinLock (&CpuData->CpuDataLock);
+
+    Status = gBS->CreateEvent (
+                    EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    CheckThisAPStatus,
+                    (VOID *) CpuData,
+                     &CpuData->CheckThisAPEvent
+                   );
+    ASSERT_EFI_ERROR (Status);
   }
 
   return EFI_SUCCESS;
diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h
index 256e62d..af20856 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.h
+++ b/UefiCpuPkg/CpuDxe/CpuMp.h
@@ -92,7 +92,15 @@ typedef enum {
 typedef struct {
   EFI_PROCESSOR_INFORMATION      Info;
   SPIN_LOCK                      CpuDataLock;
-  CPU_STATE volatile             State;
+  volatile CPU_STATE             State;
+
+  EFI_AP_PROCEDURE               Procedure;
+  VOID                           *Parameter;
+  BOOLEAN                        *Finished;
+  UINTN                          Timeout;
+  EFI_EVENT                      WaitEvent;
+  BOOLEAN                        TimeoutActive;
+  EFI_EVENT                      CheckThisAPEvent;
 } CPU_DATA_BLOCK;
 
 /**
@@ -184,6 +192,104 @@ GetProcessorInfo (
   );
 
 /**
+  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]  TimeoutInMicroseconds   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
+StartupThisAP (
+  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
+  );
+
+/**
   This service lets the caller enable or disable an AP from this point onward.
   This service may only be called from the BSP.
 
-- 
1.9.3


------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to