]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol
authorEric Dong <eric.dong@intel.com>
Wed, 10 Jul 2019 07:49:11 +0000 (15:49 +0800)
committerEric Dong <eric.dong@intel.com>
Tue, 16 Jul 2019 03:54:55 +0000 (11:54 +0800)
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1937

Add MM Mp Protocol in PiSmmCpuDxeSmm driver.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c [new file with mode: 0644]
UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h [new file with mode: 0644]

index 64fb4d6344d5f2aa2ff2fe54ecd1d507996cc443..ef16997547b84e1b36f99ca210c5f4534b73eb21 100644 (file)
@@ -136,11 +136,9 @@ ReleaseAllAPs (
   )\r
 {\r
   UINTN                             Index;\r
-  UINTN                             BspIndex;\r
 \r
-  BspIndex = mSmmMpSyncData->BspIndex;\r
   for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-    if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
+    if (IsPresentAp (Index)) {\r
       ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);\r
     }\r
   }\r
@@ -347,6 +345,165 @@ ReplaceOSMtrrs (
   MtrrSetAllMtrrs (&gSmiMtrrs);\r
 }\r
 \r
+/**\r
+  Wheck whether task has been finished by all APs.\r
+\r
+  @param       BlockMode   Whether did it in block mode or non-block mode.\r
+\r
+  @retval      TRUE        Task has been finished by all APs.\r
+  @retval      FALSE       Task not has been finished by all APs.\r
+\r
+**/\r
+BOOLEAN\r
+WaitForAllAPsNotBusy (\r
+  IN BOOLEAN                        BlockMode\r
+  )\r
+{\r
+  UINTN                             Index;\r
+\r
+  for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+    //\r
+    // Ignore BSP and APs which not call in SMM.\r
+    //\r
+    if (!IsPresentAp(Index)) {\r
+      continue;\r
+    }\r
+\r
+    if (BlockMode) {\r
+      AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+      ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+    } else {\r
+      if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {\r
+        ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+      } else {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Check whether it is an present AP.\r
+\r
+  @param   CpuIndex      The AP index which calls this function.\r
+\r
+  @retval  TRUE           It's a present AP.\r
+  @retval  TRUE           This is not an AP or it is not present.\r
+\r
+**/\r
+BOOLEAN\r
+IsPresentAp (\r
+  IN UINTN        CpuIndex\r
+  )\r
+{\r
+  return ((CpuIndex != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) &&\r
+    *(mSmmMpSyncData->CpuData[CpuIndex].Present));\r
+}\r
+\r
+/**\r
+  Check whether execute in single AP or all APs.\r
+\r
+  Compare two Tokens used by different APs to know whether in StartAllAps call.\r
+\r
+  Whether is an valid AP base on AP's Present flag.\r
+\r
+  @retval  TRUE      IN StartAllAps call.\r
+  @retval  FALSE     Not in StartAllAps call.\r
+\r
+**/\r
+BOOLEAN\r
+InStartAllApsCall (\r
+  VOID\r
+  )\r
+{\r
+  UINTN      ApIndex;\r
+  UINTN      ApIndex2;\r
+\r
+  for (ApIndex = mMaxNumberOfCpus; ApIndex-- > 0;) {\r
+    if (IsPresentAp (ApIndex) && (mSmmMpSyncData->CpuData[ApIndex].Token != NULL)) {\r
+      for (ApIndex2 = ApIndex; ApIndex2-- > 0;) {\r
+        if (IsPresentAp (ApIndex2) && (mSmmMpSyncData->CpuData[ApIndex2].Token != NULL)) {\r
+          return mSmmMpSyncData->CpuData[ApIndex2].Token == mSmmMpSyncData->CpuData[ApIndex].Token;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Clean up the status flags used during executing the procedure.\r
+\r
+  @param   CpuIndex      The AP index which calls this function.\r
+\r
+**/\r
+VOID\r
+ReleaseToken (\r
+  IN UINTN                  CpuIndex\r
+  )\r
+{\r
+  UINTN                             Index;\r
+  BOOLEAN                           Released;\r
+\r
+  if (InStartAllApsCall ()) {\r
+    //\r
+    // In Start All APs mode, make sure all APs have finished task.\r
+    //\r
+    if (WaitForAllAPsNotBusy (FALSE)) {\r
+      //\r
+      // Clean the flags update in the function call.\r
+      //\r
+      Released = FALSE;\r
+      for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+        //\r
+        // Only In SMM APs need to be clean up.\r
+        //\r
+        if (mSmmMpSyncData->CpuData[Index].Present && mSmmMpSyncData->CpuData[Index].Token != NULL) {\r
+          if (!Released) {\r
+            ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token);\r
+            Released = TRUE;\r
+          }\r
+          mSmmMpSyncData->CpuData[Index].Token = NULL;\r
+        }\r
+      }\r
+    }\r
+  } else {\r
+    //\r
+    // In single AP mode.\r
+    //\r
+    if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {\r
+      ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token);\r
+      mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Free the tokens in the maintained list.\r
+\r
+**/\r
+VOID\r
+FreeTokens (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY            *Link;\r
+  PROCEDURE_TOKEN       *ProcToken;\r
+\r
+  while (!IsListEmpty (&gSmmCpuPrivate->TokenList)) {\r
+    Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
+    ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
+\r
+    RemoveEntryList (&ProcToken->Link);\r
+\r
+    FreePool ((VOID *)ProcToken->ProcedureToken);\r
+    FreePool (ProcToken);\r
+  }\r
+}\r
+\r
 /**\r
   SMI handler for BSP.\r
 \r
@@ -476,12 +633,7 @@ BSPHandler (
   //\r
   // Make sure all APs have completed their pending none-block tasks\r
   //\r
-  for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-    if (Index != CpuIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
-      AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
-      ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
-    }\r
-  }\r
+  WaitForAllAPsNotBusy (TRUE);\r
 \r
   //\r
   // Perform the remaining tasks\r
@@ -572,6 +724,11 @@ BSPHandler (
   //\r
   WaitForAllAPs (ApCount);\r
 \r
+  //\r
+  // Clean the tokens buffer.\r
+  //\r
+  FreeTokens ();\r
+\r
   //\r
   // Reset BspIndex to -1, meaning BSP has not been elected.\r
   //\r
@@ -604,6 +761,7 @@ APHandler (
   UINT64                            Timer;\r
   UINTN                             BspIndex;\r
   MTRR_SETTINGS                     Mtrrs;\r
+  EFI_STATUS                        ProcedureStatus;\r
 \r
   //\r
   // Timeout BSP\r
@@ -730,14 +888,19 @@ APHandler (
     //\r
     // Invoke the scheduled procedure\r
     //\r
-    (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (\r
-      (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter\r
-      );\r
+    ProcedureStatus = (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (\r
+                          (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter\r
+                          );\r
+    if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
+      *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;\r
+    }\r
 \r
     //\r
     // Release BUSY\r
     //\r
     ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+\r
+    ReleaseToken (CpuIndex);\r
   }\r
 \r
   if (SmmCpuFeaturesNeedConfigureMtrrs()) {\r
@@ -906,13 +1069,124 @@ Gen4GPageTable (
   return (UINT32)(UINTN)PageTable;\r
 }\r
 \r
+/**\r
+  Checks whether the input token is the current used token.\r
+\r
+  @param[in]  Token      This parameter describes the token that was passed into DispatchProcedure or\r
+                         BroadcastProcedure.\r
+\r
+  @retval TRUE           The input token is the current used token.\r
+  @retval FALSE          The input token is not the current used token.\r
+**/\r
+BOOLEAN\r
+IsTokenInUse (\r
+  IN SPIN_LOCK           *Token\r
+  )\r
+{\r
+  LIST_ENTRY        *Link;\r
+  PROCEDURE_TOKEN   *ProcToken;\r
+\r
+  if (Token == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
+  while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {\r
+    ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
+\r
+    if (ProcToken->ProcedureToken == Token) {\r
+      return TRUE;\r
+    }\r
+\r
+    Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  create token and save it to the maintain list.\r
+\r
+  @retval    return the spin lock used as token.\r
+\r
+**/\r
+SPIN_LOCK *\r
+CreateToken (\r
+  VOID\r
+  )\r
+{\r
+  PROCEDURE_TOKEN    *ProcToken;\r
+  SPIN_LOCK           *CpuToken;\r
+  UINTN               SpinLockSize;\r
+\r
+  SpinLockSize = GetSpinLockProperties ();\r
+  CpuToken = AllocatePool (SpinLockSize);\r
+  ASSERT (CpuToken != NULL);\r
+  InitializeSpinLock (CpuToken);\r
+  AcquireSpinLock (CpuToken);\r
+\r
+  ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN));\r
+  ASSERT (ProcToken != NULL);\r
+  ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;\r
+  ProcToken->ProcedureToken = CpuToken;\r
+\r
+  InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);\r
+\r
+  return CpuToken;\r
+}\r
+\r
+/**\r
+  Checks status of specified AP.\r
+\r
+  This function checks whether the specified AP has finished the task assigned\r
+  by StartupThisAP(), and whether timeout expires.\r
+\r
+  @param[in]  Token             This parameter describes the token that was passed into DispatchProcedure or\r
+                                BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().\r
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.\r
+**/\r
+EFI_STATUS\r
+IsApReady (\r
+  IN SPIN_LOCK          *Token\r
+  )\r
+{\r
+  if (AcquireSpinLockOrFail (Token)) {\r
+    ReleaseSpinLock (Token);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
 /**\r
   Schedule a procedure to run on the specified CPU.\r
 \r
   @param[in]       Procedure                The address of the procedure to run\r
   @param[in]       CpuIndex                 Target CPU Index\r
-  @param[in, out]  ProcArguments            The parameter to pass to the procedure\r
-  @param[in]       BlockingMode             Startup AP in blocking mode or not\r
+  @param[in,out]   ProcArguments            The parameter to pass to the procedure\r
+  @param[in]       Token                    This is an optional parameter that allows the caller to execute the\r
+                                            procedure in a blocking or non-blocking fashion. If it is NULL the\r
+                                            call is blocking, and the call will not return until the AP has\r
+                                            completed the procedure. If the token is not NULL, the call will\r
+                                            return immediately. The caller can check whether the procedure has\r
+                                            completed with CheckOnProcedure or WaitForProcedure.\r
+  @param[in]       TimeoutInMicroseconds    Indicates the time limit in microseconds for the APs to finish\r
+                                            execution of Procedure, either for blocking or non-blocking mode.\r
+                                            Zero means infinity. If the timeout expires before all APs return\r
+                                            from Procedure, then Procedure on the failed APs is terminated. If\r
+                                            the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+                                            If the timeout expires in non-blocking mode, the timeout determined\r
+                                            can be through CheckOnProcedure or WaitForProcedure.\r
+                                            Note that timeout support is optional. Whether an implementation\r
+                                            supports this feature can be determined via the Attributes data\r
+                                            member.\r
+  @param[in,out]   CpuStatus                This optional pointer may be used to get the status code returned\r
+                                            by Procedure when it completes execution on the target AP, or with\r
+                                            EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                            timeout. The implementation will update this variable with\r
+                                            EFI_NOT_READY prior to starting Procedure on the target AP.\r
 \r
   @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
   @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
@@ -923,10 +1197,12 @@ Gen4GPageTable (
 **/\r
 EFI_STATUS\r
 InternalSmmStartupThisAp (\r
-  IN      EFI_AP_PROCEDURE          Procedure,\r
-  IN      UINTN                     CpuIndex,\r
-  IN OUT  VOID                      *ProcArguments OPTIONAL,\r
-  IN      BOOLEAN                   BlockingMode\r
+  IN      EFI_AP_PROCEDURE2              Procedure,\r
+  IN      UINTN                          CpuIndex,\r
+  IN OUT  VOID                           *ProcArguments OPTIONAL,\r
+  IN      MM_COMPLETION                  *Token,\r
+  IN      UINTN                          TimeoutInMicroseconds,\r
+  IN OUT  EFI_STATUS                     *CpuStatus\r
   )\r
 {\r
   if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {\r
@@ -952,24 +1228,190 @@ InternalSmmStartupThisAp (
     }\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+  if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Procedure == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
-  if (BlockingMode) {\r
+  if (Token == NULL) {\r
     AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
   } else {\r
     if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
-      DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
-      return EFI_INVALID_PARAMETER;\r
+      DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
+      return EFI_NOT_READY;\r
     }\r
+\r
+    *Token = (MM_COMPLETION) CreateToken ();\r
   }\r
 \r
   mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
   mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
+  if (Token != NULL) {\r
+    mSmmMpSyncData->CpuData[CpuIndex].Token   = (SPIN_LOCK *)(*Token);\r
+  }\r
+  mSmmMpSyncData->CpuData[CpuIndex].Status    = CpuStatus;\r
+  if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
+    *mSmmMpSyncData->CpuData[CpuIndex].Status = EFI_NOT_READY;\r
+  }\r
+\r
   ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
-  if (BlockingMode) {\r
+  if (Token == NULL) {\r
     AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
     ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
   }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Worker function to execute a caller provided function on all enabled APs.\r
+\r
+  @param[in]     Procedure               A pointer to the function to be run on\r
+                                         enabled APs of the system.\r
+  @param[in]     TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
+                                         APs to return from Procedure, either for\r
+                                         blocking or non-blocking mode.\r
+  @param[in,out] ProcedureArguments      The parameter passed into Procedure for\r
+                                         all APs.\r
+  @param[in,out] Token                   This is an optional parameter that allows the caller to execute the\r
+                                         procedure in a blocking or non-blocking fashion. If it is NULL the\r
+                                         call is blocking, and the call will not return until the AP has\r
+                                         completed the procedure. If the token is not NULL, the call will\r
+                                         return immediately. The caller can check whether the procedure has\r
+                                         completed with CheckOnProcedure or WaitForProcedure.\r
+  @param[in,out] CPUStatus               This optional pointer may be used to get the status code returned\r
+                                         by Procedure when it completes execution on the target AP, or with\r
+                                         EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                         timeout. The implementation will update this variable with\r
+                                         EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+\r
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before\r
+                                  the timeout expired.\r
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched\r
+                                  to all enabled APs.\r
+  @retval others                  Failed to Startup all APs.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupAllAPs (\r
+  IN       EFI_AP_PROCEDURE2             Procedure,\r
+  IN       UINTN                         TimeoutInMicroseconds,\r
+  IN OUT   VOID                          *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                 *Token,\r
+  IN OUT   EFI_STATUS                    *CPUStatus\r
+  )\r
+{\r
+  UINTN               Index;\r
+  UINTN               CpuCount;\r
+\r
+  if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Procedure == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CpuCount = 0;\r
+  for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+    if (IsPresentAp (Index)) {\r
+      CpuCount ++;\r
+\r
+      if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) {\r
+        return EFI_NOT_READY;\r
+      }\r
+      ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
+    }\r
+  }\r
+  if (CpuCount == 0) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (Token != NULL) {\r
+    *Token = (MM_COMPLETION) CreateToken ();\r
+  }\r
+\r
+  //\r
+  // Make sure all BUSY should be acquired.\r
+  //\r
+  // Because former code already check mSmmMpSyncData->CpuData[***].Busy for each AP.\r
+  // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail for not\r
+  // block mode.\r
+  //\r
+  for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+    if (IsPresentAp (Index)) {\r
+      AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
+    }\r
+  }\r
+\r
+  for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+    if (IsPresentAp (Index)) {\r
+      mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure;\r
+      mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments;\r
+      if (Token != NULL) {\r
+        mSmmMpSyncData->CpuData[Index].Token   = (SPIN_LOCK *)(*Token);\r
+      }\r
+      if (CPUStatus != NULL) {\r
+        mSmmMpSyncData->CpuData[Index].Status    = &CPUStatus[Index];\r
+        if (mSmmMpSyncData->CpuData[Index].Status != NULL) {\r
+          *mSmmMpSyncData->CpuData[Index].Status = EFI_NOT_READY;\r
+        }\r
+      }\r
+    } else {\r
+      //\r
+      // PI spec requirement:\r
+      // For every excluded processor, the array entry must contain a value of EFI_NOT_STARTED.\r
+      //\r
+      if (CPUStatus != NULL) {\r
+        CPUStatus[Index] = EFI_NOT_STARTED;\r
+      }\r
+    }\r
+  }\r
+\r
+  ReleaseAllAPs ();\r
+\r
+  if (Token == NULL) {\r
+    //\r
+    // Make sure all APs have completed their tasks.\r
+    //\r
+    WaitForAllAPsNotBusy (TRUE);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  ISO C99 6.5.2.2 "Function calls", paragraph 9:\r
+  If the function is defined with a type that is not compatible with\r
+  the type (of the expression) pointed to by the expression that\r
+  denotes the called function, the behavior is undefined.\r
+\r
+  So add below wrapper function to convert between EFI_AP_PROCEDURE\r
+  and EFI_AP_PROCEDURE2.\r
+\r
+  Wrapper for Procedures.\r
+\r
+  @param[in]  Buffer              Pointer to PROCEDURE_WRAPPER buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcedureWrapper (\r
+  IN OUT VOID *Buffer\r
+  )\r
+{\r
+  PROCEDURE_WRAPPER *Wrapper;\r
+\r
+  Wrapper = Buffer;\r
+  Wrapper->Procedure (Wrapper->ProcedureArgument);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -995,7 +1437,15 @@ SmmBlockingStartupThisAp (
   IN OUT  VOID                      *ProcArguments OPTIONAL\r
   )\r
 {\r
-  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);\r
+  PROCEDURE_WRAPPER  Wrapper;\r
+\r
+  Wrapper.Procedure = Procedure;\r
+  Wrapper.ProcedureArgument = ProcArguments;\r
+\r
+  //\r
+  // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
+  //\r
+  return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, &Wrapper, NULL, 0, NULL);\r
 }\r
 \r
 /**\r
@@ -1020,7 +1470,22 @@ SmmStartupThisAp (
   IN OUT  VOID                      *ProcArguments OPTIONAL\r
   )\r
 {\r
-  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));\r
+  MM_COMPLETION               Token;\r
+\r
+  gSmmCpuPrivate->ApWrapperFunc[CpuIndex].Procedure = Procedure;\r
+  gSmmCpuPrivate->ApWrapperFunc[CpuIndex].ProcedureArgument = ProcArguments;\r
+\r
+  //\r
+  // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
+  //\r
+  return InternalSmmStartupThisAp (\r
+    ProcedureWrapper,\r
+    CpuIndex,\r
+    &gSmmCpuPrivate->ApWrapperFunc[CpuIndex],\r
+    FeaturePcdGet (PcdCpuSmmBlockStartupThisAp) ? NULL : &Token,\r
+    0,\r
+    NULL\r
+    );\r
 }\r
 \r
 /**\r
@@ -1112,6 +1577,13 @@ SmiRendezvous (
   Cr2 = 0;\r
   SaveCr2 (&Cr2);\r
 \r
+  //\r
+  // Call the user register Startup function first.\r
+  //\r
+  if (mSmmMpSyncData->StartupProcedure != NULL) {\r
+    mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs);\r
+  }\r
+\r
   //\r
   // Perform CPU specific entry hooks\r
   //\r
@@ -1256,6 +1728,21 @@ Exit:
   RestoreCr2 (Cr2);\r
 }\r
 \r
+/**\r
+  Allocate buffer for SpinLock and Wrapper function buffer.\r
+\r
+**/\r
+VOID\r
+InitializeDataForMmMp (\r
+  VOID\r
+  )\r
+{\r
+  gSmmCpuPrivate->ApWrapperFunc = AllocatePool (sizeof (PROCEDURE_WRAPPER) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
+  ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL);\r
+\r
+  InitializeListHead (&gSmmCpuPrivate->TokenList);\r
+}\r
+\r
 /**\r
   Allocate buffer for all semaphores and spin locks.\r
 \r
@@ -1469,3 +1956,40 @@ RegisterSmmEntry (
   gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;\r
   return EFI_SUCCESS;\r
 }\r
+\r
+/**\r
+\r
+  Register the SMM Foundation entry point.\r
+\r
+  @param[in]      Procedure            A pointer to the code stream to be run on the designated target AP\r
+                                       of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+                                       with the related definitions of\r
+                                       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+                                       If caller may pass a value of NULL to deregister any existing\r
+                                       startup procedure.\r
+  @param[in]      ProcedureArguments   Allows the caller to pass a list of parameters to the code that is\r
+                                       run by the AP. It is an optional common mailbox between APs and\r
+                                       the caller to share information\r
+\r
+  @retval EFI_SUCCESS                  The Procedure has been set successfully.\r
+  @retval EFI_INVALID_PARAMETER        The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterStartupProcedure (\r
+  IN EFI_AP_PROCEDURE    Procedure,\r
+  IN VOID                *ProcedureArguments OPTIONAL\r
+  )\r
+{\r
+  if (Procedure == NULL && ProcedureArguments != NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (mSmmMpSyncData == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  mSmmMpSyncData->StartupProcedure = Procedure;\r
+  mSmmMpSyncData->StartupProcArgs  = ProcedureArguments;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
index 2f7d777ee749cdb481d731fe96aa5eaacd9880e9..69a04dfb2311b65699ff51efffc643bd1ba4767d 100644 (file)
@@ -34,6 +34,8 @@ SMM_CPU_PRIVATE_DATA  mSmmCpuPrivateData = {
     mSmmCpuPrivateData.SmmReservedSmramRegion,  // SmmConfiguration.SmramReservedRegions\r
     RegisterSmmEntry                            // SmmConfiguration.RegisterSmmEntry\r
   },\r
+  NULL,                                         // pointer to Ap Wrapper Func array\r
+  {NULL, NULL},                                 // List_Entry for Tokens.\r
 };\r
 \r
 CPU_HOT_PLUG_DATA mCpuHotPlugData = {\r
@@ -996,6 +998,22 @@ PiCpuSmmEntry (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  //\r
+  // Initialize global buffer for MM MP.\r
+  //\r
+  InitializeDataForMmMp ();\r
+\r
+  //\r
+  // Install the SMM Mp Protocol into SMM protocol database\r
+  //\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &mSmmCpuHandle,\r
+                    &gEfiMmMpProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &mSmmMp\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   //\r
   // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.\r
   //\r
index 2bb35a424d00659a62025a4edaf467ccc89fa060..186809f43119e5d6af88e5732fbcc3a7ada8299d 100644 (file)
@@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Protocol/SmmReadyToLock.h>\r
 #include <Protocol/SmmCpuService.h>\r
 #include <Protocol/SmmMemoryAttribute.h>\r
+#include <Protocol/MmMp.h>\r
 \r
 #include <Guid/AcpiS3Context.h>\r
 #include <Guid/MemoryAttributesTable.h>\r
@@ -197,6 +198,25 @@ typedef UINT32                              SMM_CPU_ARRIVAL_EXCEPTIONS;
 #define ARRIVAL_EXCEPTION_DELAYED           0x2\r
 #define ARRIVAL_EXCEPTION_SMI_DISABLED      0x4\r
 \r
+//\r
+// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE.\r
+//\r
+typedef struct {\r
+  EFI_AP_PROCEDURE  Procedure;\r
+  VOID              *ProcedureArgument;\r
+} PROCEDURE_WRAPPER;\r
+\r
+#define PROCEDURE_TOKEN_SIGNATURE  SIGNATURE_32 ('P', 'R', 'T', 'S')\r
+\r
+typedef struct {\r
+  UINTN                   Signature;\r
+  LIST_ENTRY              Link;\r
+\r
+  SPIN_LOCK               *ProcedureToken;\r
+} PROCEDURE_TOKEN;\r
+\r
+#define PROCEDURE_TOKEN_FROM_LINK(a)  CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE)\r
+\r
 //\r
 // Private structure for the SMM CPU module that is stored in DXE Runtime memory\r
 // Contains the SMM Configuration Protocols that is produced.\r
@@ -219,6 +239,10 @@ typedef struct {
   EFI_SMM_ENTRY_POINT             SmmCoreEntry;\r
 \r
   EFI_SMM_CONFIGURATION_PROTOCOL  SmmConfiguration;\r
+\r
+  PROCEDURE_WRAPPER               *ApWrapperFunc;\r
+  LIST_ENTRY                      TokenList;\r
+\r
 } SMM_CPU_PRIVATE_DATA;\r
 \r
 extern SMM_CPU_PRIVATE_DATA  *gSmmCpuPrivate;\r
@@ -226,6 +250,7 @@ extern CPU_HOT_PLUG_DATA      mCpuHotPlugData;
 extern UINTN                  mMaxNumberOfCpus;\r
 extern UINTN                  mNumberOfCpus;\r
 extern EFI_SMM_CPU_PROTOCOL   mSmmCpu;\r
+extern EFI_MM_MP_PROTOCOL     mSmmMp;\r
 \r
 ///\r
 /// The mode of the CPU at the time an SMI occurs\r
@@ -363,10 +388,12 @@ SmmRelocationSemaphoreComplete (
 ///\r
 typedef struct {\r
   SPIN_LOCK                         *Busy;\r
-  volatile EFI_AP_PROCEDURE         Procedure;\r
+  volatile EFI_AP_PROCEDURE2        Procedure;\r
   volatile VOID                     *Parameter;\r
   volatile UINT32                   *Run;\r
   volatile BOOLEAN                  *Present;\r
+  SPIN_LOCK                         *Token;\r
+  EFI_STATUS                        *Status;\r
 } SMM_CPU_DATA_BLOCK;\r
 \r
 typedef enum {\r
@@ -388,6 +415,8 @@ typedef struct {
   volatile SMM_CPU_SYNC_MODE    EffectiveSyncMode;\r
   volatile BOOLEAN              SwitchBsp;\r
   volatile BOOLEAN              *CandidateBsp;\r
+  EFI_AP_PROCEDURE              StartupProcedure;\r
+  VOID                          *StartupProcArgs;\r
 } SMM_DISPATCHER_MP_SYNC_DATA;\r
 \r
 #define SMM_PSD_OFFSET              0xfb00\r
@@ -410,6 +439,7 @@ typedef struct {
   SPIN_LOCK                         *Busy;\r
   volatile UINT32                   *Run;\r
   volatile BOOLEAN                  *Present;\r
+  SPIN_LOCK                         *Token;\r
 } SMM_CPU_SEMAPHORE_CPU;\r
 \r
 ///\r
@@ -1259,4 +1289,165 @@ RestoreCr2 (
   IN UINTN  Cr2\r
   );\r
 \r
+/**\r
+  Schedule a procedure to run on the specified CPU.\r
+\r
+  @param[in]       Procedure                The address of the procedure to run\r
+  @param[in]       CpuIndex                 Target CPU Index\r
+  @param[in,out]   ProcArguments            The parameter to pass to the procedure\r
+  @param[in,out]   Token                    This is an optional parameter that allows the caller to execute the\r
+                                            procedure in a blocking or non-blocking fashion. If it is NULL the\r
+                                            call is blocking, and the call will not return until the AP has\r
+                                            completed the procedure. If the token is not NULL, the call will\r
+                                            return immediately. The caller can check whether the procedure has\r
+                                            completed with CheckOnProcedure or WaitForProcedure.\r
+  @param[in]       TimeoutInMicroseconds    Indicates the time limit in microseconds for the APs to finish\r
+                                            execution of Procedure, either for blocking or non-blocking mode.\r
+                                            Zero means infinity. If the timeout expires before all APs return\r
+                                            from Procedure, then Procedure on the failed APs is terminated. If\r
+                                            the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+                                            If the timeout expires in non-blocking mode, the timeout determined\r
+                                            can be through CheckOnProcedure or WaitForProcedure.\r
+                                            Note that timeout support is optional. Whether an implementation\r
+                                            supports this feature can be determined via the Attributes data\r
+                                            member.\r
+  @param[in,out]   CPUStatus                This optional pointer may be used to get the status code returned\r
+                                            by Procedure when it completes execution on the target AP, or with\r
+                                            EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                            timeout. The implementation will update this variable with\r
+                                            EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy\r
+  @retval EFI_SUCCESS              The procedure has been successfully scheduled\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupThisAp (\r
+  IN      EFI_AP_PROCEDURE2              Procedure,\r
+  IN      UINTN                          CpuIndex,\r
+  IN OUT  VOID                           *ProcArguments OPTIONAL,\r
+  IN      MM_COMPLETION                  *Token,\r
+  IN      UINTN                          TimeoutInMicroseconds,\r
+  IN OUT  EFI_STATUS                     *CpuStatus\r
+  );\r
+\r
+/**\r
+  Checks whether the input token is the current used token.\r
+\r
+  @param[in]  Token      This parameter describes the token that was passed into DispatchProcedure or\r
+                         BroadcastProcedure.\r
+\r
+  @retval TRUE           The input token is the current used token.\r
+  @retval FALSE          The input token is not the current used token.\r
+**/\r
+BOOLEAN\r
+IsTokenInUse (\r
+  IN SPIN_LOCK           *Token\r
+  );\r
+\r
+/**\r
+  Checks status of specified AP.\r
+\r
+  This function checks whether the specified AP has finished the task assigned\r
+  by StartupThisAP(), and whether timeout expires.\r
+\r
+  @param[in]  Token             This parameter describes the token that was passed into DispatchProcedure or\r
+                                BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().\r
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.\r
+**/\r
+EFI_STATUS\r
+IsApReady (\r
+  IN SPIN_LOCK  *Token\r
+  );\r
+\r
+/**\r
+  Check whether it is an present AP.\r
+\r
+  @param   CpuIndex      The AP index which calls this function.\r
+\r
+  @retval  TRUE           It's a present AP.\r
+  @retval  TRUE           This is not an AP or it is not present.\r
+\r
+**/\r
+BOOLEAN\r
+IsPresentAp (\r
+  IN UINTN        CpuIndex\r
+  );\r
+\r
+/**\r
+  Worker function to execute a caller provided function on all enabled APs.\r
+\r
+  @param[in]     Procedure               A pointer to the function to be run on\r
+                                         enabled APs of the system.\r
+  @param[in]     TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
+                                         APs to return from Procedure, either for\r
+                                         blocking or non-blocking mode.\r
+  @param[in,out] ProcedureArgument       The parameter passed into Procedure for\r
+                                         all APs.\r
+  @param[in,out] Token                   This is an optional parameter that allows the caller to execute the\r
+                                         procedure in a blocking or non-blocking fashion. If it is NULL the\r
+                                         call is blocking, and the call will not return until the AP has\r
+                                         completed the procedure. If the token is not NULL, the call will\r
+                                         return immediately. The caller can check whether the procedure has\r
+                                         completed with CheckOnProcedure or WaitForProcedure.\r
+  @param[in,out] CPUStatus               This optional pointer may be used to get the status code returned\r
+                                         by Procedure when it completes execution on the target AP, or with\r
+                                         EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                         timeout. The implementation will update this variable with\r
+                                         EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before\r
+                                  the timeout expired.\r
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched\r
+                                  to all enabled APs.\r
+  @retval others                  Failed to Startup all APs.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupAllAPs (\r
+  IN       EFI_AP_PROCEDURE2             Procedure,\r
+  IN       UINTN                         TimeoutInMicroseconds,\r
+  IN OUT   VOID                          *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                 *Token,\r
+  IN OUT   EFI_STATUS                    *CPUStatus\r
+  );\r
+\r
+/**\r
+\r
+  Register the SMM Foundation entry point.\r
+\r
+  @param[in]      Procedure            A pointer to the code stream to be run on the designated target AP\r
+                                       of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+                                       with the related definitions of\r
+                                       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+                                       If caller may pass a value of NULL to deregister any existing\r
+                                       startup procedure.\r
+  @param[in,out]  ProcedureArguments   Allows the caller to pass a list of parameters to the code that is\r
+                                       run by the AP. It is an optional common mailbox between APs and\r
+                                       the caller to share information\r
+\r
+  @retval EFI_SUCCESS                  The Procedure has been set successfully.\r
+  @retval EFI_INVALID_PARAMETER        The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterStartupProcedure (\r
+  IN EFI_AP_PROCEDURE    Procedure,\r
+  IN VOID                *ProcedureArguments OPTIONAL\r
+  );\r
+\r
+/**\r
+  Allocate buffer for SpinLock and Wrapper function buffer.\r
+\r
+**/\r
+VOID\r
+InitializeDataForMmMp (\r
+  VOID\r
+  );\r
+\r
 #endif\r
index 466c568d49f5ce75ff021b9b1ecfba82009821cb..da0308c47f2aeb5a5835ba04fba4b313fa263003 100644 (file)
@@ -40,6 +40,8 @@
   SmmProfileInternal.h\r
   SmramSaveState.c\r
   SmmCpuMemoryManagement.c\r
+  SmmMp.h\r
+  SmmMp.c\r
 \r
 [Sources.Ia32]\r
   Ia32/Semaphore.c\r
   gEfiSmmReadyToLockProtocolGuid           ## NOTIFY\r
   gEfiSmmCpuServiceProtocolGuid            ## PRODUCES\r
   gEdkiiSmmMemoryAttributeProtocolGuid     ## PRODUCES\r
+  gEfiMmMpProtocolGuid                    ## PRODUCES\r
 \r
 [Guids]\r
   gEfiAcpiVariableGuid                     ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.\r
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
new file mode 100644 (file)
index 0000000..9b2b191
--- /dev/null
@@ -0,0 +1,344 @@
+/** @file\r
+SMM MP protocol implementation\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "PiSmmCpuDxeSmm.h"\r
+#include "SmmMp.h"\r
+\r
+///\r
+/// SMM MP Protocol instance\r
+///\r
+EFI_MM_MP_PROTOCOL  mSmmMp  = {\r
+  EFI_MM_MP_PROTOCOL_REVISION,\r
+  0,\r
+  SmmMpGetNumberOfProcessors,\r
+  SmmMpDispatchProcedure,\r
+  SmmMpBroadcastProcedure,\r
+  SmmMpSetStartupProcedure,\r
+  SmmMpCheckForProcedure,\r
+  SmmMpWaitForProcedure\r
+};\r
+\r
+/**\r
+  Service to retrieves the number of logical processor in the platform.\r
+\r
+  @param[in]  This                The EFI_MM_MP_PROTOCOL instance.\r
+  @param[out] NumberOfProcessors  Pointer to the total number of logical processors in the system,\r
+                                  including the BSP and all APs.\r
+\r
+  @retval EFI_SUCCESS             The number of processors was retrieved successfully\r
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpGetNumberOfProcessors (\r
+  IN CONST EFI_MM_MP_PROTOCOL   *This,\r
+  OUT      UINTN                *NumberOfProcessors\r
+  )\r
+{\r
+  if (NumberOfProcessors == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *NumberOfProcessors = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This service allows the caller to invoke a procedure one of the application processors (AP). This\r
+  function uses an optional token parameter to support blocking and non-blocking modes. If the token\r
+  is passed into the call, the function will operate in a non-blocking fashion and the caller can\r
+  check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+  @param[in]     This                   The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]     Procedure              A pointer to the procedure to be run on the designated target\r
+                                        AP of the system. Type EFI_AP_PROCEDURE2 is defined below in\r
+                                        related definitions.\r
+  @param[in]     CpuNumber              The zero-based index of the processor number of the target\r
+                                        AP, on which the code stream is supposed to run. If the number\r
+                                        points to the calling processor then it will not run the\r
+                                        supplied code.\r
+  @param[in]     TimeoutInMicroseconds  Indicates the time limit in microseconds for this AP to\r
+                                        finish execution of Procedure, either for blocking or\r
+                                        non-blocking mode. Zero means infinity. If the timeout\r
+                                        expires before this AP returns from Procedure, then Procedure\r
+                                        on the AP is terminated. If the timeout expires in blocking\r
+                                        mode, the call returns EFI_TIMEOUT. If the timeout expires\r
+                                        in non-blocking mode, the timeout determined can be through\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        Note that timeout support is optional. Whether an\r
+                                        implementation supports this feature, can be determined via\r
+                                        the Attributes data member.\r
+  @param[in,out] ProcedureArguments     Allows the caller to pass a list of parameters to the code\r
+                                        that is run by the AP. It is an optional common mailbox\r
+                                        between APs and the caller to share information.\r
+  @param[in,out] Token                  This is parameter is broken into two components:\r
+                                        1.Token->Completion is an optional parameter that allows the\r
+                                        caller to execute the procedure in a blocking or non-blocking\r
+                                        fashion. If it is NULL the call is blocking, and the call will\r
+                                        not return until the AP has completed the procedure. If the\r
+                                        token is not NULL, the call will return immediately. The caller\r
+                                        can check whether the procedure has completed with\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        2.Token->Status The implementation updates the address pointed\r
+                                        at by this variable with the status code returned by Procedure\r
+                                        when it completes execution on the target AP, or with EFI_TIMEOUT\r
+                                        if the Procedure fails to complete within the optional timeout.\r
+                                        The implementation will update this variable with EFI_NOT_READY\r
+                                        prior to starting Procedure on the target AP\r
+  @param[in,out] CPUStatus              This optional pointer may be used to get the status code returned\r
+                                        by Procedure when it completes execution on the target AP, or with\r
+                                        EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                        timeout. The implementation will update this variable with\r
+                                        EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+  @retval EFI_SUCCESS                   In the blocking case, this indicates that Procedure has completed\r
+                                        execution on the target AP.\r
+                                        In the non-blocking case this indicates that the procedure has\r
+                                        been successfully scheduled for execution on the target AP.\r
+  @retval EFI_INVALID_PARAMETER         The input arguments are out of range. Either the target AP is the\r
+                                        caller of the function, or the Procedure or Token is NULL\r
+  @retval EFI_NOT_READY                 If the target AP is busy executing another procedure\r
+  @retval EFI_ALREADY_STARTED           Token is already in use for another procedure\r
+  @retval EFI_TIMEOUT                   In blocking mode, the timeout expired before the specified AP\r
+                                        has finished\r
+  @retval EFI_OUT_OF_RESOURCES          Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpDispatchProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL            *This,\r
+  IN       EFI_AP_PROCEDURE2             Procedure,\r
+  IN       UINTN                         CpuNumber,\r
+  IN       UINTN                         TimeoutInMicroseconds,\r
+  IN OUT   VOID                          *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                 *Token,\r
+  IN OUT   EFI_STATUS                    *CPUStatus\r
+  )\r
+{\r
+  return InternalSmmStartupThisAp (\r
+    Procedure,\r
+    CpuNumber,\r
+    ProcedureArguments,\r
+    Token,\r
+    TimeoutInMicroseconds,\r
+    CPUStatus\r
+    );\r
+}\r
+\r
+/**\r
+  This service allows the caller to invoke a procedure on all running application processors (AP)\r
+  except the caller. This function uses an optional token parameter to support blocking and\r
+  nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking\r
+  fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+  It is not necessary for the implementation to run the procedure on every processor on the platform.\r
+  Processors that are powered down in such a way that they cannot respond to interrupts, may be\r
+  excluded from the broadcast.\r
+\r
+\r
+  @param[in]     This                   The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]     Procedure              A pointer to the code stream to be run on the APs that have\r
+                                        entered MM. Type EFI_AP_PROCEDURE is defined below in related\r
+                                        definitions.\r
+  @param[in]     TimeoutInMicroseconds  Indicates the time limit in microseconds for the APs to finish\r
+                                        execution of Procedure, either for blocking or non-blocking mode.\r
+                                        Zero means infinity. If the timeout expires before all APs return\r
+                                        from Procedure, then Procedure on the failed APs is terminated. If\r
+                                        the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+                                        If the timeout expires in non-blocking mode, the timeout determined\r
+                                        can be through CheckOnProcedure or WaitForProcedure.\r
+                                        Note that timeout support is optional. Whether an implementation\r
+                                        supports this feature can be determined via the Attributes data\r
+                                        member.\r
+  @param[in,out] ProcedureArguments     Allows the caller to pass a list of parameters to the code\r
+                                        that is run by the AP. It is an optional common mailbox\r
+                                        between APs and the caller to share information.\r
+  @param[in,out] Token                  This is parameter is broken into two components:\r
+                                        1.Token->Completion is an optional parameter that allows the\r
+                                        caller to execute the procedure in a blocking or non-blocking\r
+                                        fashion. If it is NULL the call is blocking, and the call will\r
+                                        not return until the AP has completed the procedure. If the\r
+                                        token is not NULL, the call will return immediately. The caller\r
+                                        can check whether the procedure has completed with\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        2.Token->Status The implementation updates the address pointed\r
+                                        at by this variable with the status code returned by Procedure\r
+                                        when it completes execution on the target AP, or with EFI_TIMEOUT\r
+                                        if the Procedure fails to complete within the optional timeout.\r
+                                        The implementation will update this variable with EFI_NOT_READY\r
+                                        prior to starting Procedure on the target AP\r
+  @param[in,out] CPUStatus              This optional pointer may be used to get the individual status\r
+                                        returned by every AP that participated in the broadcast. This\r
+                                        parameter if used provides the base address of an array to hold\r
+                                        the EFI_STATUS value of each AP in the system. The size of the\r
+                                        array can be ascertained by the GetNumberOfProcessors function.\r
+                                        As mentioned above, the broadcast may not include every processor\r
+                                        in the system. Some implementations may exclude processors that\r
+                                        have been powered down in such a way that they are not responsive\r
+                                        to interrupts. Additionally the broadcast excludes the processor\r
+                                        which is making the BroadcastProcedure call. For every excluded\r
+                                        processor, the array entry must contain a value of EFI_NOT_STARTED\r
+\r
+  @retval EFI_SUCCESS                   In the blocking case, this indicates that Procedure has completed\r
+                                        execution on the APs.\r
+                                        In the non-blocking case this indicates that the procedure has\r
+                                        been successfully scheduled for execution on the APs.\r
+  @retval EFI_INVALID_PARAMETER         The Procedure or Token is NULL\r
+  @retval EFI_NOT_READY                 If the target AP is busy executing another procedure\r
+  @retval EFI_ALREADY_STARTED           Token is already in use for another procedure\r
+  @retval EFI_TIMEOUT                   In blocking mode, the timeout expired before the specified AP\r
+                                        has finished.\r
+  @retval EFI_OUT_OF_RESOURCES          Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpBroadcastProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL            *This,\r
+  IN       EFI_AP_PROCEDURE2             Procedure,\r
+  IN       UINTN                         TimeoutInMicroseconds,\r
+  IN OUT   VOID                          *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                 *Token,\r
+  IN OUT   EFI_STATUS                    *CPUStatus\r
+  )\r
+{\r
+  return InternalSmmStartupAllAPs(\r
+    Procedure,\r
+    TimeoutInMicroseconds,\r
+    ProcedureArguments,\r
+    Token,\r
+    CPUStatus\r
+    );\r
+}\r
+\r
+/**\r
+  This service allows the caller to set a startup procedure that will be executed when an AP powers\r
+  up from a state where core configuration and context is lost. The procedure is execution has the\r
+  following properties:\r
+  1. The procedure executes before the processor is handed over to the operating system.\r
+  2. All processors execute the same startup procedure.\r
+  3. The procedure may run in parallel with other procedures invoked through the functions in this\r
+  protocol, or with processors that are executing an MM handler or running in the operating system.\r
+\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Procedure            A pointer to the code stream to be run on the designated target AP\r
+                                       of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+                                       with the related definitions of\r
+                                       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+                                       If caller may pass a value of NULL to deregister any existing\r
+                                       startup procedure.\r
+  @param[in,out]  ProcedureArguments   Allows the caller to pass a list of parameters to the code that is\r
+                                       run by the AP. It is an optional common mailbox between APs and\r
+                                       the caller to share information\r
+\r
+  @retval EFI_SUCCESS                  The Procedure has been set successfully.\r
+  @retval EFI_INVALID_PARAMETER        The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpSetStartupProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL  *This,\r
+  IN       EFI_AP_PROCEDURE    Procedure,\r
+  IN OUT   VOID                *ProcedureArguments OPTIONAL\r
+  )\r
+{\r
+  return RegisterStartupProcedure (Procedure, ProcedureArguments);\r
+}\r
+\r
+/**\r
+  When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,\r
+  via the use of a token, this function can be used to check for completion of the procedure on the AP.\r
+  The function takes the token that was passed into the DispatchProcedure call. If the procedure\r
+  is complete, and therefore it is now possible to run another procedure on the same AP, this function\r
+  returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is\r
+  returned in the token's Status field. If the procedure has not yet completed, then this function\r
+  returns EFI_NOT_READY.\r
+\r
+  When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the\r
+  use of a token, this function can be used to check for completion of the procedure on all the\r
+  broadcast APs. The function takes the token that was passed into the BroadcastProcedure\r
+  call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this\r
+  case the Status field in the token passed into the function reflects the overall result of the\r
+  invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.\r
+  If the procedure has not yet completed on the broadcast APs, the function returns\r
+  EFI_NOT_READY.\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Token                This parameter describes the token that was passed into\r
+                                       DispatchProcedure or BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS                  Procedure has completed.\r
+  @retval EFI_NOT_READY                The Procedure has not completed.\r
+  @retval EFI_INVALID_PARAMETER        Token or Token->Completion is NULL\r
+  @retval EFI_NOT_FOUND                Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpCheckForProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL            *This,\r
+  IN       MM_COMPLETION                 Token\r
+  )\r
+{\r
+  if (Token == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!IsTokenInUse ((SPIN_LOCK *)Token)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return IsApReady ((SPIN_LOCK *)Token);\r
+}\r
+\r
+/**\r
+  When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,\r
+  this function will block the caller until the remote procedure has completed on the designated AP.\r
+  The non-blocking procedure invocation is identified by the Token parameter, which must match the\r
+  token that used when DispatchProcedure was called. Upon completion the status returned by\r
+  the procedure that executed on the AP is used to update the token's Status field.\r
+\r
+  When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure\r
+  this function will block the caller until the remote procedure has completed on all of the APs that\r
+  entered MM. The non-blocking procedure invocation is identified by the Token parameter, which\r
+  must match the token that used when BroadcastProcedure was called. Upon completion the\r
+  overall status returned by the procedures that executed on the broadcast AP is used to update the\r
+  token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the\r
+  first observed failure.\r
+\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Token                This parameter describes the token that was passed into\r
+                                       DispatchProcedure or BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS                  Procedure has completed.\r
+  @retval EFI_INVALID_PARAMETER        Token or Token->Completion is NULL\r
+  @retval EFI_NOT_FOUND                Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpWaitForProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL            *This,\r
+  IN       MM_COMPLETION                 Token\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  do {\r
+    Status = SmmMpCheckForProcedure (This, Token);\r
+  } while (Status == EFI_NOT_READY);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
new file mode 100644 (file)
index 0000000..e0d823a
--- /dev/null
@@ -0,0 +1,286 @@
+/** @file\r
+Include file for SMM MP protocol implementation.\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _SMM_MP_PROTOCOL_H_\r
+#define _SMM_MP_PROTOCOL_H_\r
+\r
+//\r
+// SMM MP Protocol function prototypes.\r
+//\r
+\r
+/**\r
+  Service to retrieves the number of logical processor in the platform.\r
+\r
+  @param[in]  This                The EFI_MM_MP_PROTOCOL instance.\r
+  @param[out] NumberOfProcessors  Pointer to the total number of logical processors in the system,\r
+                                  including the BSP and all APs.\r
+\r
+  @retval EFI_SUCCESS             The number of processors was retrieved successfully\r
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpGetNumberOfProcessors (\r
+  IN CONST EFI_MM_MP_PROTOCOL   *This,\r
+  OUT      UINTN                *NumberOfProcessors\r
+  );\r
+\r
+\r
+/**\r
+  This service allows the caller to invoke a procedure one of the application processors (AP). This\r
+  function uses an optional token parameter to support blocking and non-blocking modes. If the token\r
+  is passed into the call, the function will operate in a non-blocking fashion and the caller can\r
+  check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+  @param[in]     This                   The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]     Procedure              A pointer to the procedure to be run on the designated target\r
+                                        AP of the system. Type EFI_AP_PROCEDURE2 is defined below in\r
+                                        related definitions.\r
+  @param[in]     CpuNumber              The zero-based index of the processor number of the target\r
+                                        AP, on which the code stream is supposed to run. If the number\r
+                                        points to the calling processor then it will not run the\r
+                                        supplied code.\r
+  @param[in]     TimeoutInMicroseconds  Indicates the time limit in microseconds for this AP to\r
+                                        finish execution of Procedure, either for blocking or\r
+                                        non-blocking mode. Zero means infinity. If the timeout\r
+                                        expires before this AP returns from Procedure, then Procedure\r
+                                        on the AP is terminated. If the timeout expires in blocking\r
+                                        mode, the call returns EFI_TIMEOUT. If the timeout expires\r
+                                        in non-blocking mode, the timeout determined can be through\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        Note that timeout support is optional. Whether an\r
+                                        implementation supports this feature, can be determined via\r
+                                        the Attributes data member.\r
+  @param[in,out] ProcedureArguments     Allows the caller to pass a list of parameters to the code\r
+                                        that is run by the AP. It is an optional common mailbox\r
+                                        between APs and the caller to share information.\r
+  @param[in,out] Token                  This is parameter is broken into two components:\r
+                                        1.Token->Completion is an optional parameter that allows the\r
+                                        caller to execute the procedure in a blocking or non-blocking\r
+                                        fashion. If it is NULL the call is blocking, and the call will\r
+                                        not return until the AP has completed the procedure. If the\r
+                                        token is not NULL, the call will return immediately. The caller\r
+                                        can check whether the procedure has completed with\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        2.Token->Status The implementation updates the address pointed\r
+                                        at by this variable with the status code returned by Procedure\r
+                                        when it completes execution on the target AP, or with EFI_TIMEOUT\r
+                                        if the Procedure fails to complete within the optional timeout.\r
+                                        The implementation will update this variable with EFI_NOT_READY\r
+                                        prior to starting Procedure on the target AP\r
+  @param[in,out] CPUStatus              This optional pointer may be used to get the status code returned\r
+                                        by Procedure when it completes execution on the target AP, or with\r
+                                        EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+                                        timeout. The implementation will update this variable with\r
+                                        EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+  @retval EFI_SUCCESS                   In the blocking case, this indicates that Procedure has completed\r
+                                        execution on the target AP.\r
+                                        In the non-blocking case this indicates that the procedure has\r
+                                        been successfully scheduled for execution on the target AP.\r
+  @retval EFI_INVALID_PARAMETER         The input arguments are out of range. Either the target AP is the\r
+                                        caller of the function, or the Procedure or Token is NULL\r
+  @retval EFI_NOT_READY                 If the target AP is busy executing another procedure\r
+  @retval EFI_ALREADY_STARTED           Token is already in use for another procedure\r
+  @retval EFI_TIMEOUT                   In blocking mode, the timeout expired before the specified AP\r
+                                        has finished\r
+  @retval EFI_OUT_OF_RESOURCES          Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpDispatchProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL             *This,\r
+  IN       EFI_AP_PROCEDURE2              Procedure,\r
+  IN       UINTN                          CpuNumber,\r
+  IN       UINTN                          TimeoutInMicroseconds,\r
+  IN OUT   VOID                           *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                  *Token,\r
+  IN OUT   EFI_STATUS                     *CPUStatus\r
+  );\r
+\r
+/**\r
+  This service allows the caller to invoke a procedure on all running application processors (AP)\r
+  except the caller. This function uses an optional token parameter to support blocking and\r
+  nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking\r
+  fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+  It is not necessary for the implementation to run the procedure on every processor on the platform.\r
+  Processors that are powered down in such a way that they cannot respond to interrupts, may be\r
+  excluded from the broadcast.\r
+\r
+\r
+  @param[in]     This                   The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]     Procedure              A pointer to the code stream to be run on the APs that have\r
+                                        entered MM. Type EFI_AP_PROCEDURE is defined below in related\r
+                                        definitions.\r
+  @param[in]     TimeoutInMicroseconds  Indicates the time limit in microseconds for the APs to finish\r
+                                        execution of Procedure, either for blocking or non-blocking mode.\r
+                                        Zero means infinity. If the timeout expires before all APs return\r
+                                        from Procedure, then Procedure on the failed APs is terminated. If\r
+                                        the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+                                        If the timeout expires in non-blocking mode, the timeout determined\r
+                                        can be through CheckOnProcedure or WaitForProcedure.\r
+                                        Note that timeout support is optional. Whether an implementation\r
+                                        supports this feature can be determined via the Attributes data\r
+                                        member.\r
+  @param[in,out] ProcedureArguments     Allows the caller to pass a list of parameters to the code\r
+                                        that is run by the AP. It is an optional common mailbox\r
+                                        between APs and the caller to share information.\r
+  @param[in,out] Token                  This is parameter is broken into two components:\r
+                                        1.Token->Completion is an optional parameter that allows the\r
+                                        caller to execute the procedure in a blocking or non-blocking\r
+                                        fashion. If it is NULL the call is blocking, and the call will\r
+                                        not return until the AP has completed the procedure. If the\r
+                                        token is not NULL, the call will return immediately. The caller\r
+                                        can check whether the procedure has completed with\r
+                                        CheckOnProcedure or WaitForProcedure.\r
+                                        2.Token->Status The implementation updates the address pointed\r
+                                        at by this variable with the status code returned by Procedure\r
+                                        when it completes execution on the target AP, or with EFI_TIMEOUT\r
+                                        if the Procedure fails to complete within the optional timeout.\r
+                                        The implementation will update this variable with EFI_NOT_READY\r
+                                        prior to starting Procedure on the target AP\r
+  @param[in,out] CPUStatus              This optional pointer may be used to get the individual status\r
+                                        returned by every AP that participated in the broadcast. This\r
+                                        parameter if used provides the base address of an array to hold\r
+                                        the EFI_STATUS value of each AP in the system. The size of the\r
+                                        array can be ascertained by the GetNumberOfProcessors function.\r
+                                        As mentioned above, the broadcast may not include every processor\r
+                                        in the system. Some implementations may exclude processors that\r
+                                        have been powered down in such a way that they are not responsive\r
+                                        to interrupts. Additionally the broadcast excludes the processor\r
+                                        which is making the BroadcastProcedure call. For every excluded\r
+                                        processor, the array entry must contain a value of EFI_NOT_STARTED\r
+\r
+  @retval EFI_SUCCESS                   In the blocking case, this indicates that Procedure has completed\r
+                                        execution on the APs.\r
+                                        In the non-blocking case this indicates that the procedure has\r
+                                        been successfully scheduled for execution on the APs.\r
+  @retval EFI_INVALID_PARAMETER         The Procedure or Token is NULL\r
+  @retval EFI_NOT_READY                 If the target AP is busy executing another procedure\r
+  @retval EFI_ALREADY_STARTED           Token is already in use for another procedure\r
+  @retval EFI_TIMEOUT                   In blocking mode, the timeout expired before the specified AP\r
+                                        has finished\r
+  @retval EFI_OUT_OF_RESOURCES          Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpBroadcastProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL             *This,\r
+  IN       EFI_AP_PROCEDURE2              Procedure,\r
+  IN       UINTN                          TimeoutInMicroseconds,\r
+  IN OUT   VOID                           *ProcedureArguments OPTIONAL,\r
+  IN OUT   MM_COMPLETION                  *Token,\r
+  IN OUT   EFI_STATUS                     *CPUStatus\r
+  );\r
+\r
+\r
+/**\r
+  This service allows the caller to set a startup procedure that will be executed when an AP powers\r
+  up from a state where core configuration and context is lost. The procedure is execution has the\r
+  following properties:\r
+  1. The procedure executes before the processor is handed over to the operating system.\r
+  2. All processors execute the same startup procedure.\r
+  3. The procedure may run in parallel with other procedures invoked through the functions in this\r
+  protocol, or with processors that are executing an MM handler or running in the operating system.\r
+\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Procedure            A pointer to the code stream to be run on the designated target AP\r
+                                       of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+                                       with the related definitions of\r
+                                       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+                                       If caller may pass a value of NULL to deregister any existing\r
+                                       startup procedure.\r
+  @param[in,out]  ProcedureArguments   Allows the caller to pass a list of parameters to the code that is\r
+                                       run by the AP. It is an optional common mailbox between APs and\r
+                                       the caller to share information\r
+\r
+  @retval EFI_SUCCESS                  The Procedure has been set successfully.\r
+  @retval EFI_INVALID_PARAMETER        The Procedure is NULL but ProcedureArguments not NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpSetStartupProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL  *This,\r
+  IN       EFI_AP_PROCEDURE    Procedure,\r
+  IN OUT   VOID                *ProcedureArguments OPTIONAL\r
+  );\r
+\r
+/**\r
+  When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,\r
+  via the use of a token, this function can be used to check for completion of the procedure on the AP.\r
+  The function takes the token that was passed into the DispatchProcedure call. If the procedure\r
+  is complete, and therefore it is now possible to run another procedure on the same AP, this function\r
+  returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is\r
+  returned in the token's Status field. If the procedure has not yet completed, then this function\r
+  returns EFI_NOT_READY.\r
+\r
+  When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the\r
+  use of a token, this function can be used to check for completion of the procedure on all the\r
+  broadcast APs. The function takes the token that was passed into the BroadcastProcedure\r
+  call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this\r
+  case the Status field in the token passed into the function reflects the overall result of the\r
+  invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.\r
+  If the procedure has not yet completed on the broadcast APs, the function returns\r
+  EFI_NOT_READY.\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Token                This parameter describes the token that was passed into\r
+                                       DispatchProcedure or BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS                  Procedure has completed.\r
+  @retval EFI_NOT_READY                The Procedure has not completed.\r
+  @retval EFI_INVALID_PARAMETER        Token or Token->Completion is NULL\r
+  @retval EFI_NOT_FOUND                Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpCheckForProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL             *This,\r
+  IN       MM_COMPLETION                  Token\r
+  );\r
+\r
+/**\r
+  When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,\r
+  this function will block the caller until the remote procedure has completed on the designated AP.\r
+  The non-blocking procedure invocation is identified by the Token parameter, which must match the\r
+  token that used when DispatchProcedure was called. Upon completion the status returned by\r
+  the procedure that executed on the AP is used to update the token's Status field.\r
+\r
+  When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure\r
+  this function will block the caller until the remote procedure has completed on all of the APs that\r
+  entered MM. The non-blocking procedure invocation is identified by the Token parameter, which\r
+  must match the token that used when BroadcastProcedure was called. Upon completion the\r
+  overall status returned by the procedures that executed on the broadcast AP is used to update the\r
+  token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the\r
+  first observed failure.\r
+\r
+\r
+  @param[in]      This                 The EFI_MM_MP_PROTOCOL instance.\r
+  @param[in]      Token                This parameter describes the token that was passed into\r
+                                       DispatchProcedure or BroadcastProcedure.\r
+\r
+  @retval EFI_SUCCESS                  Procedure has completed.\r
+  @retval EFI_INVALID_PARAMETER        Token or Token->Completion is NULL\r
+  @retval EFI_NOT_FOUND                Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpWaitForProcedure (\r
+  IN CONST EFI_MM_MP_PROTOCOL            *This,\r
+  IN       MM_COMPLETION                 Token\r
+  );\r
+\r
+#endif\r