From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.20, mailfrom: ray.ni@intel.com) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by groups.io with SMTP; Wed, 03 Jul 2019 23:18:17 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Jul 2019 23:18:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,449,1557212400"; d="scan'208";a="158200218" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by orsmga008.jf.intel.com with ESMTP; 03 Jul 2019 23:18:16 -0700 Received: from shsmsx153.ccr.corp.intel.com (10.239.6.53) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.439.0; Wed, 3 Jul 2019 23:18:15 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.110]) by SHSMSX153.ccr.corp.intel.com ([169.254.12.60]) with mapi id 14.03.0439.000; Thu, 4 Jul 2019 14:18:13 +0800 From: "Ni, Ray" To: "devel@edk2.groups.io" , "Dong, Eric" CC: Laszlo Ersek Subject: Re: [edk2-devel] [Patch v3 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Topic: [edk2-devel] [Patch v3 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Index: AQHVMUkHjxY/YZvhDEqjmF7JRBLOtKa58X4w Date: Thu, 4 Jul 2019 06:18:12 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C215538@SHSMSX104.ccr.corp.intel.com> References: <20190703024242.33572-1-eric.dong@intel.com> <20190703024242.33572-3-eric.dong@intel.com> In-Reply-To: <20190703024242.33572-3-eric.dong@intel.com> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: ray.ni@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable 1. mMaxNumberOfCpus and gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ar= e both used. Can you please refine the code to use only one? 2. I do think that MM_MP code needs to maintain a internal linked list con= taining all created tokens. Because it's possible that caller is written in= below way: DispatchProcedure (AP#1, &TokenA); DispatchProcedure (AP#1, &TokenB); DispatchProcedure (AP#1, &TokenC); CheckOnProcedure (&TokenA); Without having a list to contain all created tokens, CheckOnProcedure = (&TokenA) may return NotFound. The linked list can be freed upon exiting SMM 3. IsCurrentToken() can be changed to look up the token in the linked list= and the name can be changed to IsTokenInUse(). The function name reflects the spec wording "EFI_ALREADY_STARTED - Tok= en is already in use for another procedure." 4. In InternalSmmStartup[AllAPs|ThisAp], Token can be acquired after Busy = is acquired. Token is associated with the procedure. Busy is associated with the individual processor. 5. *(CPUStatus + Index) can be changed to CPUStatus[Index]. Use [] instead= of address operation. 6. Below error handling in InternalSmmStartupAllAPs may not be necessary. = Just AcquireSpinLock (...Busy) should be ok. // // Make sure all BUSY should be acquired. // for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { if (Index !=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutin= gCpu && *(mSmmMpSyncData->CpuData[Index].Present)) { if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) = { DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].B= usy\n", Index)); // // Release BUSY accquired before. // for (CpuCount =3D mMaxNumberOfCpus; CpuCount -- > Index;) { if (CpuCount !=3D gSmmCpuPrivate->SmmCoreEntryContext.Currentl= yExecutingCpu && *(mSmmMpSyncData->CpuData[CpuCount].Present)) { ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuCount].Busy); } } ReleaseSpinLock (Token); return EFI_INVALID_PARAMETER; } } } 7. IsTaskFinishInAllAPs() can be used by BSPHandler() as well. The functio= n name can be WaitForAllAPsNotBusy() or some other name because the functio= n has side affect, not just check. 8. Maybe you don't need to have a mApTokenLock[]. For old style async SMM = MP call, the token is not returned to caller. But it's still possible to be= freed as long as it's inserted to the linked list. Thanks, Ray > -----Original Message----- > From: devel@edk2.groups.io On Behalf Of Dong, > Eric > Sent: Wednesday, July 3, 2019 10:43 AM > To: devel@edk2.groups.io > Cc: Ni, Ray ; Laszlo Ersek > Subject: [edk2-devel] [Patch v3 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable > MM MP Protocol. >=20 > v3 changes: > 1. Fix Token clean up too early caused CheckProcedure return error. >=20 > v2 changes: > 1. Remove some duplicated global variables. > 2. Enhance token design to support multiple task trig for different APs = at the > same time. >=20 > V1 changes: > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1937 >=20 > Add MM Mp Protocol in PiSmmCpuDxeSmm driver. >=20 > Cc: Ray Ni > Cc: Laszlo Ersek > Signed-off-by: Eric Dong > --- > UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 536 > ++++++++++++++++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 11 + > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 160 +++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 + > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 372 +++++++++++++ > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++ > 6 files changed, 1351 insertions(+), 17 deletions(-) > create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c > create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h >=20 > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > index 64fb4d6344..13858f5d2d 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > @@ -22,6 +22,7 @@ UINTN mSemaphore= Size; > SPIN_LOCK *mPFLock =3D NULL; > SMM_CPU_SYNC_MODE mCpuSmmSyncMode; > BOOLEAN mMachineCheckSupported =3D = FALSE; > +SPIN_LOCK **mApTokenLock; >=20 > /** > Performs an atomic compare exchange operation to get semaphore. > @@ -146,6 +147,45 @@ ReleaseAllAPs ( > } > } >=20 > +/** > + Wheck whether task has been finished by all APs. > + > + @param BlockMode Whether did it in block mode or non-block mo= de. > + > + @retval TRUE Task has been finished by all APs. > + @retval FALSE Task not has been finished by all APs. > + > +**/ > +BOOLEAN > +IsTaskFinishInAllAPs ( > + IN BOOLEAN BlockMode > + ) > +{ > + UINTN Index; > + > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + // > + // Ignore BSP and APs which not call in SMM. > + // > + if ((Index =3D=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu) || (!*(mSmmMpSyncData- > >CpuData[Index].Present))) { > + continue; > + } > + > + if (BlockMode) { > + AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy); > + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy); > + } else { > + if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) = { > + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy); > + } else { > + return FALSE; > + } > + } > + } > + > + return TRUE; > +} > + > /** > Checks if all CPUs (with certain exceptions) have checked in for this= SMI run >=20 > @@ -347,6 +387,92 @@ ReplaceOSMtrrs ( > MtrrSetAllMtrrs (&gSmiMtrrs); > } >=20 > +/** > + Check whether execute in single AP or all APs. > + > + Compare two Tokens used by different APs to know whether in > StartAllAps call. > + > + Whether is an valid AP base on AP's Present flag. > + > + @retval TRUE IN StartAllAps call. > + @retval FALSE Not in StartAllAps call. > + > +**/ > +BOOLEAN > +InStartAllApsCall ( > + VOID > + ) > +{ > + UINTN ApIndex; > + UINTN ApIndex2; > + > + for (ApIndex =3D mMaxNumberOfCpus; ApIndex-- > 0;) { > + if ((ApIndex !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu) && > + *(mSmmMpSyncData->CpuData[ApIndex].Present) && > + (mSmmMpSyncData->CpuData[ApIndex].Token !=3D NULL)) { > + for (ApIndex2 =3D ApIndex; ApIndex2-- > 0;) { > + if ((ApIndex2 !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu) && > + *(mSmmMpSyncData->CpuData[ApIndex2].Present) && > + (mSmmMpSyncData->CpuData[ApIndex2].Token !=3D NULL)) { > + return mSmmMpSyncData->CpuData[ApIndex2].Token =3D=3D > mSmmMpSyncData->CpuData[ApIndex].Token; > + } > + } > + } > + } > + > + return FALSE; > +} > + > +/** > + Clean up the status flags used during executing the procedure. > + > + @param CpuIndex The AP index which calls this function. > + > +**/ > +VOID > +CleanUpStatusFlags ( > + IN UINTN CpuIndex > + ) > +{ > + UINTN Index; > + > + if (InStartAllApsCall ()) { > + // > + // In Start All APs mode, make sure all APs have finished task. > + // > + if (IsTaskFinishInAllAPs (FALSE)) { > + // > + // Clean the flags update in the function call. > + // > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + // > + // Only In SMM APs need to be clean up. > + // > + if (mSmmMpSyncData->CpuData[Index].Present) { > + if (mSmmMpSyncData->CpuData[Index].Token !=3D NULL) { > + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token); > + break; > + } > + } > + } > + } > + } else { > + // > + // In single AP mode. > + // > + if (mSmmMpSyncData->CpuData[CpuIndex].Token !=3D NULL) { > + // > + // Free the wrapper buffer in non-block mode used by > SmmMpDispatchProcedure function. > + // > + if (mApTokenLock[CpuIndex] =3D=3D mSmmMpSyncData- > >CpuData[CpuIndex].Token) { > + FreePool ((VOID *)mSmmMpSyncData- > >CpuData[CpuIndex].Parameter); > + } > + > + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token); > + } > + } > +} > + > /** > SMI handler for BSP. >=20 > @@ -604,6 +730,7 @@ APHandler ( > UINT64 Timer; > UINTN BspIndex; > MTRR_SETTINGS Mtrrs; > + EFI_STATUS ProcedureStatus; >=20 > // > // Timeout BSP > @@ -730,14 +857,19 @@ APHandler ( > // > // Invoke the scheduled procedure > // > - (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) ( > - (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter > - ); > + ProcedureStatus =3D (*mSmmMpSyncData- > >CpuData[CpuIndex].Procedure) ( > + (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Para= meter > + ); > + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { > + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D ProcedureStatus; > + } >=20 > // > // Release BUSY > // > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > + > + CleanUpStatusFlags (CpuIndex); > } >=20 > if (SmmCpuFeaturesNeedConfigureMtrrs()) { > @@ -906,13 +1038,95 @@ Gen4GPageTable ( > return (UINT32)(UINTN)PageTable; > } >=20 > +/** > + Checks whether the input token is the current used token. > + > + @param[in] CpuIndex Cpu Index. > + @param[in] Token This parameter describes the token that was pa= ssed > into DispatchProcedure or > + BroadcastProcedure. > + > + @retval TRUE The input token is the current used token. > + @retval FALSE The input token is not the current used token. > +**/ > +BOOLEAN > +IsCurrentToken ( > + IN UINTN CpuIndex, > + IN SPIN_LOCK *Token > + ) > +{ > + UINTN Index; > + > + if (Token =3D=3D NULL) { > + return FALSE; > + } > + > + if (CpuIndex =3D=3D (UINTN) -1) { > + for (Index =3D 0; Index < gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus; Index ++) { > + if (mSmmMpSyncData->CpuData[Index].Present && > + (mSmmMpSyncData->CpuData[Index].Token !=3D NULL) && > + (mSmmMpSyncData->CpuData[Index].Token =3D=3D Token)) { > + return TRUE; > + } > + } > + > + return FALSE; > + } > + > + return mSmmMpSyncData->CpuData[CpuIndex].Token =3D=3D Token; > +} > + > +/** > + Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task > assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] Token This parameter describes the token that= was > passed into DispatchProcedure or > + BroadcastProcedure. > + > + @retval EFI_SUCCESS Specified AP has finished task assigned= by > StartupThisAPs(). > + @retval EFI_NOT_READY Specified AP has not finished task and > timeout has not expired. > +**/ > +EFI_STATUS > +IsApReady ( > + IN SPIN_LOCK *Token > + ) > +{ > + if (AcquireSpinLockOrFail (Token)) { > + ReleaseSpinLock (Token); > + return EFI_SUCCESS; > + } > + > + return EFI_NOT_READY; > +} > + > /** > Schedule a procedure to run on the specified CPU. >=20 > @param[in] Procedure The address of the procedur= e to run > @param[in] CpuIndex Target CPU Index > - @param[in, out] ProcArguments The parameter to pass to th= e > procedure > - @param[in] BlockingMode Startup AP in blocking mode= or not > + @param[in,out] ProcArguments The parameter to pass to th= e > procedure > + @param[in] Token This is an optional paramet= er that allows > the caller to execute the > + procedure in a blocking or = non-blocking fashion. If it is > NULL the > + call is blocking, and the c= all will not return until the AP > has > + completed the procedure. If= the token is not NULL, > the call will > + return immediately. The cal= ler can check whether the > procedure has > + completed with CheckOnProce= dure or > WaitForProcedure. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, eit= her for blocking or non- > blocking mode. > + Zero means infinity. If the= timeout expires before all > APs return > + from Procedure, then Proced= ure on the failed APs is > terminated. If > + the timeout expires in bloc= king mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in n= on-blocking mode, the > timeout determined > + can be through CheckOnProce= dure or > WaitForProcedure. > + Note that timeout support i= s optional. Whether an > implementation > + supports this feature can b= e determined via the > Attributes data > + member. > + @param[in,out] CpuStatus This optional pointer may b= e used to > get the status code returned > + by Procedure when it comple= tes execution on the > target AP, or with > + EFI_TIMEOUT if the Procedur= e fails to complete > within the optional > + timeout. The implementation= will update this variable > with > + EFI_NOT_READY prior to star= ting Procedure on the > target AP. >=20 > @retval EFI_INVALID_PARAMETER CpuNumber not valid > @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP > @@ -923,10 +1137,12 @@ Gen4GPageTable ( > **/ > EFI_STATUS > InternalSmmStartupThisAp ( > - IN EFI_AP_PROCEDURE Procedure, > - IN UINTN CpuIndex, > - IN OUT VOID *ProcArguments OPTIONAL, > - IN BOOLEAN BlockingMode > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN CpuIndex, > + IN OUT VOID *ProcArguments OPTIONAL, > + IN SPIN_LOCK *Token, > + IN UINTN TimeoutInMicroseconds, > + IN OUT EFI_STATUS *CpuStatus > ) > { > if (CpuIndex >=3D gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) > { > @@ -952,24 +1168,208 @@ InternalSmmStartupThisAp ( > } > return EFI_INVALID_PARAMETER; > } > + if ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & > EFI_MM_MP_TIMEOUT_SUPPORTED) =3D=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + if (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (IsCurrentToken (CpuIndex, Token)) { > + return EFI_ALREADY_STARTED; > + } >=20 > - if (BlockingMode) { > + if (Token =3D=3D NULL) { > AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > } else { > - if (!AcquireSpinLockOrFail (mSmmMpSyncData- > >CpuData[CpuIndex].Busy)) { > - DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", > CpuIndex)); > + if (!AcquireSpinLockOrFail (Token)) { > + DEBUG((DEBUG_ERROR, "Token can't acquire\n")); > return EFI_INVALID_PARAMETER; > } > + if (!AcquireSpinLockOrFail (mSmmMpSyncData- > >CpuData[CpuIndex].Busy)) { > + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData- > >CpuData[%d].Busy\n", CpuIndex)); > + ReleaseSpinLock (Token); > + return EFI_NOT_READY; > + } > } >=20 > mSmmMpSyncData->CpuData[CpuIndex].Procedure =3D Procedure; > mSmmMpSyncData->CpuData[CpuIndex].Parameter =3D ProcArguments; > + mSmmMpSyncData->CpuData[CpuIndex].Token =3D Token; > + mSmmMpSyncData->CpuData[CpuIndex].Status =3D CpuStatus; > + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { > + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D EFI_NOT_READY; > + } > + > ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run); >=20 > - if (BlockingMode) { > + if (Token =3D=3D NULL) { > AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > } > + > + return EFI_SUCCESS; > +} > + > +/** > + Worker function to execute a caller provided function on all enabled = APs. > + > + @param[in] Procedure A pointer to the function to b= e run on > + enabled APs of the system. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, = either for > + blocking or non-blocking mode. > + @param[in,out] ProcedureArguments The parameter passed into > Procedure for > + all APs. > + @param[in,out] Token This is an optional parameter = that allows > the caller to execute the > + procedure in a blocking or non= -blocking fashion. If it is > NULL the > + call is blocking, and the call= will not return until the AP > has > + completed the procedure. If th= e token is not NULL, the > call will > + return immediately. The caller= can check whether the > procedure has > + completed with CheckOnProcedur= e or > WaitForProcedure. > + @param[in,out] CPUStatus This optional pointer may be u= sed to get > the status code returned > + by Procedure when it completes= execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure f= ails to complete within > the optional > + timeout. The implementation wi= ll update this variable > with > + EFI_NOT_READY prior to startin= g Procedure on the > target AP. > + > + > + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has be= en > dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +InternalSmmStartupAllAPs ( > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT SPIN_LOCK *Token, > + IN OUT EFI_STATUS *CPUStatus > + ) > +{ > + UINTN Index; > + UINTN CpuCount; > + > + if ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & > EFI_MM_MP_TIMEOUT_SUPPORTED) =3D=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + if (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (IsCurrentToken ((UINTN)-1, Token)) { > + return EFI_ALREADY_STARTED; > + } > + > + CpuCount =3D 0; > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (*mSmmMpSyncData->CpuData[Index].Present && (Index !=3D > gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu)) { > + CpuCount ++; > + > + if (gSmmCpuPrivate->Operation[Index] =3D=3D SmmCpuRemove) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) = { > + return EFI_NOT_READY; > + } > + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > + } > + } > + if (CpuCount =3D=3D 0) { > + return EFI_NOT_STARTED; > + } > + > + if (Token =3D=3D NULL) { > + // > + // Make sure all BUSY should be acquired. > + // > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > + AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > + } > + } > + } else { > + if (!AcquireSpinLockOrFail (Token)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Make sure all BUSY should be acquired. > + // > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > + if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy= )) > { > + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData- > >CpuData[%d].Busy\n", Index)); > + > + // > + // Release BUSY accquired before. > + // > + for (CpuCount =3D mMaxNumberOfCpus; CpuCount -- > Index;) { > + if (CpuCount !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[CpuCount].Present)) { > + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuCount].Busy); > + } > + } > + > + ReleaseSpinLock (Token); > + return EFI_INVALID_PARAMETER; > + } > + } > + } > + } > + > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > + mSmmMpSyncData->CpuData[Index].Procedure =3D > (EFI_AP_PROCEDURE2) Procedure; > + mSmmMpSyncData->CpuData[Index].Parameter =3D > ProcedureArguments; > + mSmmMpSyncData->CpuData[Index].Token =3D Token; > + if (CPUStatus !=3D NULL) { > + mSmmMpSyncData->CpuData[Index].Status =3D CPUStatus + Index; > + if (mSmmMpSyncData->CpuData[Index].Status !=3D NULL) { > + *mSmmMpSyncData->CpuData[Index].Status =3D EFI_NOT_READY; > + } > + } > + } else { > + // > + // PI spec requirement: > + // For every excluded processor, the array entry must contain a v= alue of > EFI_NOT_STARTED. > + // > + if (CPUStatus !=3D NULL) { > + *(CPUStatus + Index) =3D EFI_NOT_STARTED; > + } > + } > + } > + > + ReleaseAllAPs (); > + > + if (Token =3D=3D NULL) { > + // > + // Make sure all APs have completed their tasks. > + // > + IsTaskFinishInAllAPs (TRUE); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Wrapper for Procedures. > + > + @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProcedureWrapper ( > + IN OUT VOID *Buffer > + ) > +{ > + PROCEDURE_WRAPPER *Wrapper; > + > + Wrapper =3D Buffer; > + Wrapper->Procedure (Wrapper->ProcedureArgument); > + > return EFI_SUCCESS; > } >=20 > @@ -995,7 +1395,24 @@ SmmBlockingStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > TRUE); > + PROCEDURE_WRAPPER *Wrapper; > + EFI_STATUS Status; > + > + Wrapper =3D AllocatePool (sizeof(PROCEDURE_WRAPPER)); > + if (Wrapper =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + Wrapper->Procedure =3D Procedure; > + Wrapper->ProcedureArgument =3D ProcArguments; > + > + // > + // Use wrapper function to convert EFI_AP_PROCEDURE to > EFI_AP_PROCEDURE2. > + // > + Status =3D InternalSmmStartupThisAp(ProcedureWrapper, CpuIndex, > Wrapper, NULL, 0, NULL); > + > + FreePool (Wrapper); > + > + return Status; > } >=20 > /** > @@ -1020,7 +1437,37 @@ SmmStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)); > + SPIN_LOCK *CpuToken; > + PROCEDURE_WRAPPER *Wrapper; > + EFI_STATUS Status; > + > + Wrapper =3D AllocatePool (sizeof(PROCEDURE_WRAPPER)); > + if (Wrapper =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + Wrapper->Procedure =3D Procedure; > + Wrapper->ProcedureArgument =3D ProcArguments; > + > + if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) { > + CpuToken =3D NULL; > + } else { > + CpuToken =3D mApTokenLock[CpuIndex]; > + } > + > + // > + // Use wrapper function to convert EFI_AP_PROCEDURE to > EFI_AP_PROCEDURE2. > + // > + Status =3D InternalSmmStartupThisAp(ProcedureWrapper, CpuIndex, > Wrapper, CpuToken, 0, NULL); > + > + // > + // Free wrapper buffer for block mode. > + // Non-block mode frees buffer in ApHandler function. > + // > + if (CpuToken =3D=3D NULL) { > + FreePool (Wrapper); > + } > + > + return Status; > } >=20 > /** > @@ -1112,6 +1559,13 @@ SmiRendezvous ( > Cr2 =3D 0; > SaveCr2 (&Cr2); >=20 > + // > + // Call the user register Startup function first. > + // > + if (mSmmMpSyncData->StartupProcedure !=3D NULL) { > + mSmmMpSyncData->StartupProcedure (mSmmMpSyncData- > >StartupProcArgs); > + } > + > // > // Perform CPU specific entry hooks > // > @@ -1273,13 +1727,17 @@ InitializeSmmCpuSemaphores ( > UINTN Pages; > UINTN *SemaphoreBlock; > UINTN SemaphoreAddr; > + UINTN ApTokenSize; > + UINTN CpuIndex; >=20 > SemaphoreSize =3D GetSpinLockProperties (); > ProcessorCount =3D gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus; > GlobalSemaphoresSize =3D (sizeof (SMM_CPU_SEMAPHORE_GLOBAL) / > sizeof (VOID *)) * SemaphoreSize; > CpuSemaphoresSize =3D (sizeof (SMM_CPU_SEMAPHORE_CPU) / sizeof > (VOID *)) * ProcessorCount * SemaphoreSize; > - TotalSize =3D GlobalSemaphoresSize + CpuSemaphoresSize; > + ApTokenSize =3D SemaphoreSize * ProcessorCount; > + TotalSize =3D GlobalSemaphoresSize + CpuSemaphoresSize + ApTokenSize; > DEBUG((EFI_D_INFO, "One Semaphore Size =3D 0x%x\n", SemaphoreSize)= ); > + DEBUG((EFI_D_INFO, "Token Spin Lock Size =3D 0x%x\n", ApTokenSize)); > DEBUG((EFI_D_INFO, "Total Semaphores Size =3D 0x%x\n", TotalSize)); > Pages =3D EFI_SIZE_TO_PAGES (TotalSize); > SemaphoreBlock =3D AllocatePages (Pages); > @@ -1305,10 +1763,19 @@ InitializeSmmCpuSemaphores ( > mSmmCpuSemaphores.SemaphoreCpu.Run =3D (UINT32 > *)SemaphoreAddr; > SemaphoreAddr +=3D ProcessorCount * SemaphoreSize; > mSmmCpuSemaphores.SemaphoreCpu.Present =3D (BOOLEAN > *)SemaphoreAddr; > + SemaphoreAddr +=3D ProcessorCount * SemaphoreSize; > + mSmmCpuSemaphores.SemaphoreCpu.Token =3D (SPIN_LOCK > *)SemaphoreAddr; >=20 > mPFLock =3D mSmmCpuSemaphores.SemaphoreGlobal.P= FLock; > mConfigSmmCodeAccessCheckLock =3D > mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock; >=20 > + mApTokenLock =3D AllocatePool (sizeof (SPIN_LOCK *) * gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus); > + ASSERT (mApTokenLock !=3D NULL); > + for (CpuIndex =3D 0; CpuIndex < gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus; CpuIndex ++) { > + mApTokenLock[CpuIndex] =3D (SPIN_LOCK > *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Token + SemaphoreSize > * CpuIndex); > + InitializeSpinLock (mApTokenLock[CpuIndex]); > + } > + > mSemaphoreSize =3D SemaphoreSize; > } >=20 > @@ -1469,3 +1936,40 @@ RegisterSmmEntry ( > gSmmCpuPrivate->SmmCoreEntry =3D SmmEntryPoint; > return EFI_SUCCESS; > } > + > +/** > + > + Register the SMM Foundation entry point. > + > + @param[in] Procedure A pointer to the code stream to = be run on > the designated target AP > + of the system. Type EFI_AP_PROCE= DURE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.Startup= AllAPs. > + If caller may pass a value of NU= LL to deregister any > existing > + startup procedure. > + @param[in] ProcedureArguments Allows the caller to pass a list= of > parameters to the code that is > + run by the AP. It is an optional= common mailbox > between APs and > + the caller to share information > + > + @retval EFI_SUCCESS The Procedure has been set succe= ssfully. > + @retval EFI_INVALID_PARAMETER The Procedure is NULL but > ProcedureArguments not NULL. > + > +**/ > +EFI_STATUS > +RegisterStartupProcedure ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArguments OPTIONAL > + ) > +{ > + if (Procedure =3D=3D NULL && ProcedureArguments !=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (mSmmMpSyncData =3D=3D NULL) { > + return EFI_NOT_READY; > + } > + > + mSmmMpSyncData->StartupProcedure =3D Procedure; > + mSmmMpSyncData->StartupProcArgs =3D ProcedureArguments; > + > + return EFI_SUCCESS; > +} > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > index 2f7d777ee7..dd1b3be0f5 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > @@ -996,6 +996,17 @@ PiCpuSmmEntry ( > ); > ASSERT_EFI_ERROR (Status); >=20 > + // > + // Install the SMM Mp Protocol into SMM protocol database > + // > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mSmmCpuHandle, > + &gEfiMmMpProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mSmmMp > + ); > + ASSERT_EFI_ERROR (Status); > + > // > // Expose address of CPU Hot Plug Data structure if CPU hot plug is > supported. > // > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h > b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h > index 2bb35a424d..5df09687e1 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h > @@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > #include > #include > #include > +#include >=20 > #include > #include > @@ -221,11 +222,20 @@ typedef struct { > EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration; > } SMM_CPU_PRIVATE_DATA; >=20 > +// > +// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE. > +// > +typedef struct { > + EFI_AP_PROCEDURE Procedure; > + VOID *ProcedureArgument; > +} PROCEDURE_WRAPPER; > + > extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate; > extern CPU_HOT_PLUG_DATA mCpuHotPlugData; > extern UINTN mMaxNumberOfCpus; > extern UINTN mNumberOfCpus; > extern EFI_SMM_CPU_PROTOCOL mSmmCpu; > +extern EFI_MM_MP_PROTOCOL mSmmMp; >=20 > /// > /// The mode of the CPU at the time an SMI occurs > @@ -363,10 +373,12 @@ SmmRelocationSemaphoreComplete ( > /// > typedef struct { > SPIN_LOCK *Busy; > - volatile EFI_AP_PROCEDURE Procedure; > + volatile EFI_AP_PROCEDURE2 Procedure; > volatile VOID *Parameter; > volatile UINT32 *Run; > volatile BOOLEAN *Present; > + SPIN_LOCK *Token; > + EFI_STATUS *Status; > } SMM_CPU_DATA_BLOCK; >=20 > typedef enum { > @@ -388,6 +400,8 @@ typedef struct { > volatile SMM_CPU_SYNC_MODE EffectiveSyncMode; > volatile BOOLEAN SwitchBsp; > volatile BOOLEAN *CandidateBsp; > + EFI_AP_PROCEDURE StartupProcedure; > + VOID *StartupProcArgs; > } SMM_DISPATCHER_MP_SYNC_DATA; >=20 > #define SMM_PSD_OFFSET 0xfb00 > @@ -410,6 +424,7 @@ typedef struct { > SPIN_LOCK *Busy; > volatile UINT32 *Run; > volatile BOOLEAN *Present; > + SPIN_LOCK *Token; > } SMM_CPU_SEMAPHORE_CPU; >=20 > /// > @@ -439,6 +454,7 @@ extern SPIN_LOCK > *mConfigSmmCodeAccessCheckLock; > extern EFI_SMRAM_DESCRIPTOR *mSmmCpuSmramRanges; > extern UINTN mSmmCpuSmramRangeCount; > extern UINT8 mPhysicalAddressBits; > +extern SPIN_LOCK **mApTokenLock; >=20 > // > // Copy of the PcdPteMemoryEncryptionAddressOrMask > @@ -1259,4 +1275,146 @@ RestoreCr2 ( > IN UINTN Cr2 > ); >=20 > +/** > + Schedule a procedure to run on the specified CPU. > + > + @param[in] Procedure The address of the procedur= e to run > + @param[in] CpuIndex Target CPU Index > + @param[in,out] ProcArguments The parameter to pass to th= e > procedure > + @param[in,out] Token This is an optional paramet= er that allows > the caller to execute the > + procedure in a blocking or = non-blocking fashion. If it is > NULL the > + call is blocking, and the c= all will not return until the AP > has > + completed the procedure. If= the token is not NULL, > the call will > + return immediately. The cal= ler can check whether the > procedure has > + completed with CheckOnProce= dure or > WaitForProcedure. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, eit= her for blocking or non- > blocking mode. > + Zero means infinity. If the= timeout expires before all > APs return > + from Procedure, then Proced= ure on the failed APs is > terminated. If > + the timeout expires in bloc= king mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in n= on-blocking mode, the > timeout determined > + can be through CheckOnProce= dure or > WaitForProcedure. > + Note that timeout support i= s optional. Whether an > implementation > + supports this feature can b= e determined via the > Attributes data > + member. > + @param[in,out] CPUStatus This optional pointer may b= e used to > get the status code returned > + by Procedure when it comple= tes execution on the > target AP, or with > + EFI_TIMEOUT if the Procedur= e fails to complete > within the optional > + timeout. The implementation= will update this variable > with > + EFI_NOT_READY prior to star= ting Procedure on the > target AP. > + > + > + @retval EFI_INVALID_PARAMETER CpuNumber not valid > + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP > + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did > not enter SMM > + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is > busy > + @retval EFI_SUCCESS The procedure has been successfully > scheduled > + > +**/ > +EFI_STATUS > +InternalSmmStartupThisAp ( > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN CpuIndex, > + IN OUT VOID *ProcArguments OPTIONAL, > + IN SPIN_LOCK *Token, > + IN UINTN TimeoutInMicroseconds, > + IN OUT EFI_STATUS *CpuStatus > + ); > + > +/** > + Checks whether the input token is the current used token. > + > + @param[in] CpuIndex Cpu Index. > + @param[in] Token This parameter describes the token that was pa= ssed > into DispatchProcedure or > + BroadcastProcedure. > + > + @retval TRUE The input token is the current used token. > + @retval FALSE The input token is not the current used token. > +**/ > +BOOLEAN > +IsCurrentToken ( > + IN UINTN CpuIndex, > + IN SPIN_LOCK *Token > + ); > + > +/** > + Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task > assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] Token This parameter describes the token that= was > passed into DispatchProcedure or > + BroadcastProcedure. > + > + @retval EFI_SUCCESS Specified AP has finished task assigned= by > StartupThisAPs(). > + @retval EFI_NOT_READY Specified AP has not finished task and > timeout has not expired. > +**/ > +EFI_STATUS > +IsApReady ( > + IN SPIN_LOCK *Token > + ); > + > +/** > + Worker function to execute a caller provided function on all enabled = APs. > + > + @param[in] Procedure A pointer to the function to b= e run on > + enabled APs of the system. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, = either for > + blocking or non-blocking mode. > + @param[in,out] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[in,out] Token This is an optional parameter = that allows > the caller to execute the > + procedure in a blocking or non= -blocking fashion. If it is > NULL the > + call is blocking, and the call= will not return until the AP > has > + completed the procedure. If th= e token is not NULL, the > call will > + return immediately. The caller= can check whether the > procedure has > + completed with CheckOnProcedur= e or > WaitForProcedure. > + @param[in,out] CPUStatus This optional pointer may be u= sed to get > the status code returned > + by Procedure when it completes= execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure f= ails to complete within > the optional > + timeout. The implementation wi= ll update this variable > with > + EFI_NOT_READY prior to startin= g Procedure on the > target AP. > + > + > + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has be= en > dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +InternalSmmStartupAllAPs ( > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT SPIN_LOCK *Token, > + IN OUT EFI_STATUS *CPUStatus > + ); > + > +/** > + > + Register the SMM Foundation entry point. > + > + @param[in] Procedure A pointer to the code stream to = be run on > the designated target AP > + of the system. Type EFI_AP_PROCE= DURE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.Startup= AllAPs. > + If caller may pass a value of NU= LL to deregister any > existing > + startup procedure. > + @param[in,out] ProcedureArguments Allows the caller to pass a list= of > parameters to the code that is > + run by the AP. It is an optional= common mailbox > between APs and > + the caller to share information > + > + @retval EFI_SUCCESS The Procedure has been set succe= ssfully. > + @retval EFI_INVALID_PARAMETER The Procedure is NULL but > ProcedureArguments not NULL. > + > +**/ > +EFI_STATUS > +RegisterStartupProcedure ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArguments OPTIONAL > + ); > + > #endif > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > index 466c568d49..da0308c47f 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > @@ -40,6 +40,8 @@ > SmmProfileInternal.h > SmramSaveState.c > SmmCpuMemoryManagement.c > + SmmMp.h > + SmmMp.c >=20 > [Sources.Ia32] > Ia32/Semaphore.c > @@ -105,6 +107,7 @@ > gEfiSmmReadyToLockProtocolGuid ## NOTIFY > gEfiSmmCpuServiceProtocolGuid ## PRODUCES > gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES > + gEfiMmMpProtocolGuid ## PRODUCES >=20 > [Guids] > gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB= # it is > used for S3 boot. > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c > b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c > new file mode 100644 > index 0000000000..bfbc78691f > --- /dev/null > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c > @@ -0,0 +1,372 @@ > +/** @file > +SMM MP protocol implementation > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "PiSmmCpuDxeSmm.h" > +#include "SmmMp.h" > + > +/// > +/// SMM MP Protocol instance > +/// > +EFI_MM_MP_PROTOCOL mSmmMp =3D { > + EFI_MM_MP_PROTOCOL_REVISION, > + 0, > + SmmMpGetNumberOfProcessors, > + SmmMpDispatchProcedure, > + SmmMpBroadcastProcedure, > + SmmMpSetStartupProcedure, > + SmmMpCheckForProcedure, > + SmmMpWaitForProcedure > +}; > + > +/** > + Service to retrieves the number of logical processor in the platform. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[out] NumberOfProcessors Pointer to the total number of logica= l > processors in the system, > + including the BSP and all APs. > + > + @retval EFI_SUCCESS The number of processors was retrieve= d > successfully > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpGetNumberOfProcessors ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + OUT UINTN *NumberOfProcessors > + ) > +{ > + if (NumberOfProcessors =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + *NumberOfProcessors =3D gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus; > + > + return EFI_SUCCESS; > +} > + > + > +/** > + This service allows the caller to invoke a procedure one of the appli= cation > processors (AP). This > + function uses an optional token parameter to support blocking and non= - > blocking modes. If the token > + is passed into the call, the function will operate in a non-blocking = fashion > and the caller can > + check for completion with CheckOnProcedure or WaitForProcedure. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance= . > + @param[in] Procedure A pointer to the procedure to b= e run on > the designated target > + AP of the system. Type EFI_AP_P= ROCEDURE2 is defined > below in > + related definitions. > + @param[in] CpuNumber The zero-based index of the pro= cessor > number of the target > + AP, on which the code stream is= supposed to run. If the > number > + points to the calling processor= then it will not run the > + supplied code. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for this AP to > + finish execution of Procedure, = either for blocking or > + non-blocking mode. Zero means i= nfinity. If the timeout > + expires before this AP returns = from Procedure, then > Procedure > + on the AP is terminated. If the= timeout expires in > blocking > + mode, the call returns EFI_TIME= OUT. If the timeout > expires > + in non-blocking mode, the timeo= ut determined can be > through > + CheckOnProcedure or WaitForProc= edure. > + Note that timeout support is op= tional. Whether an > + implementation supports this fe= ature, can be > determined via > + the Attributes data member. > + @param[in,out] ProcedureArguments Allows the caller to pass a lis= t of > parameters to the code > + that is run by the AP. It is an= optional common mailbox > + between APs and the caller to s= hare information. > + @param[in,out] Token This is parameter is broken int= o two > components: > + 1.Token->Completion is an optio= nal parameter that > allows the > + caller to execute the procedure= in a blocking or non- > blocking > + fashion. If it is NULL the call= is blocking, and the call will > + not return until the AP has com= pleted the procedure. If > the > + token is not NULL, the call wil= l return immediately. The > caller > + can check whether the procedure= has completed with > + CheckOnProcedure or WaitForProc= edure. > + 2.Token->Status The implementat= ion updates the > address pointed > + at by this variable with the st= atus code returned by > Procedure > + when it completes execution on = the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to compl= ete within the optional > timeout. > + The implementation will update = this variable with > EFI_NOT_READY > + prior to starting Procedure on = the target AP > + @param[in,out] CPUStatus This optional pointer may be us= ed to get > the status code returned > + by Procedure when it completes = execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure fa= ils to complete within > the optional > + timeout. The implementation wil= l update this variable > with > + EFI_NOT_READY prior to starting= Procedure on the > target AP. > + > + @retval EFI_SUCCESS In the blocking case, this indi= cates that > Procedure has completed > + execution on the target AP. > + In the non-blocking case this i= ndicates that the > procedure has > + been successfully scheduled for= execution on the target > AP. > + @retval EFI_INVALID_PARAMETER The input arguments are out of > range. Either the target AP is the > + caller of the function, or the = Procedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy execut= ing another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for ano= ther > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout e= xpired > before the specified AP > + has finished > + @retval EFI_OUT_OF_RESOURCES Could not allocate a required > resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpDispatchProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN CpuNumber, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT MM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ) > +{ > + SPIN_LOCK *CpuToken; > + > + if (Token !=3D NULL) { > + CpuToken =3D AllocatePool (sizeof (SPIN_LOCK)); > + ASSERT (CpuToken !=3D NULL); > + if (CpuToken =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + InitializeSpinLock ((SPIN_LOCK *)(CpuToken)); > + > + *Token =3D (MM_COMPLETION)CpuToken; > + } > + > + return InternalSmmStartupThisAp ( > + Procedure, > + CpuNumber, > + ProcedureArguments, > + Token !=3D NULL ? CpuToken : NULL, > + TimeoutInMicroseconds, > + CPUStatus > + ); > +} > + > +/** > + This service allows the caller to invoke a procedure on all running > application processors (AP) > + except the caller. This function uses an optional token parameter to > support blocking and > + nonblocking modes. If the token is passed into the call, the function= will > operate in a non-blocking > + fashion and the caller can check for completion with CheckOnProcedure= or > WaitForProcedure. > + > + It is not necessary for the implementation to run the procedure on ev= ery > processor on the platform. > + Processors that are powered down in such a way that they cannot respo= nd > to interrupts, may be > + excluded from the broadcast. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance= . > + @param[in] Procedure A pointer to the code stream to= be run on > the APs that have > + entered MM. Type EFI_AP_PROCEDU= RE is defined > below in related > + definitions. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, either = for blocking or non- > blocking mode. > + Zero means infinity. If the tim= eout expires before all > APs return > + from Procedure, then Procedure = on the failed APs is > terminated. If > + the timeout expires in blocking= mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in non-b= locking mode, the > timeout determined > + can be through CheckOnProcedure= or > WaitForProcedure. > + Note that timeout support is op= tional. Whether an > implementation > + supports this feature can be de= termined via the > Attributes data > + member. > + @param[in,out] ProcedureArguments Allows the caller to pass a lis= t of > parameters to the code > + that is run by the AP. It is an= optional common mailbox > + between APs and the caller to s= hare information. > + @param[in,out] Token This is parameter is broken int= o two > components: > + 1.Token->Completion is an optio= nal parameter that > allows the > + caller to execute the procedure= in a blocking or non- > blocking > + fashion. If it is NULL the call= is blocking, and the call will > + not return until the AP has com= pleted the procedure. If > the > + token is not NULL, the call wil= l return immediately. The > caller > + can check whether the procedure= has completed with > + CheckOnProcedure or WaitForProc= edure. > + 2.Token->Status The implementat= ion updates the > address pointed > + at by this variable with the st= atus code returned by > Procedure > + when it completes execution on = the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to compl= ete within the optional > timeout. > + The implementation will update = this variable with > EFI_NOT_READY > + prior to starting Procedure on = the target AP > + @param[in,out] CPUStatus This optional pointer may be us= ed to get > the individual status > + returned by every AP that parti= cipated in the broadcast. > This > + parameter if used provides the = base address of an array > to hold > + the EFI_STATUS value of each AP= in the system. The size > of the > + array can be ascertained by the > GetNumberOfProcessors function. > + As mentioned above, the broadca= st may not include > every processor > + in the system. Some implementat= ions may exclude > processors that > + have been powered down in such = a way that they are > not responsive > + to interrupts. Additionally the= broadcast excludes the > processor > + which is making the BroadcastPr= ocedure call. For every > excluded > + processor, the array entry must= contain a value of > EFI_NOT_STARTED > + > + @retval EFI_SUCCESS In the blocking case, this indi= cates that > Procedure has completed > + execution on the APs. > + In the non-blocking case this i= ndicates that the > procedure has > + been successfully scheduled for= execution on the APs. > + @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy execut= ing another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for ano= ther > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout e= xpired > before the specified AP > + has finished. > + @retval EFI_OUT_OF_RESOURCES Could not allocate a required > resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpBroadcastProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT MM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ) > +{ > + SPIN_LOCK *CpuToken; > + > + if (Token !=3D NULL) { > + CpuToken =3D AllocatePool (sizeof (SPIN_LOCK)); > + ASSERT (CpuToken !=3D NULL); > + if (CpuToken =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + InitializeSpinLock ((SPIN_LOCK *)(CpuToken)); > + > + *Token =3D (MM_COMPLETION)CpuToken; > + } > + > + return InternalSmmStartupAllAPs( > + Procedure, > + TimeoutInMicroseconds, > + ProcedureArguments, > + Token !=3D NULL ? CpuToken : NULL, > + CPUStatus > + ); > +} > + > + > +/** > + This service allows the caller to set a startup procedure that will b= e > executed when an AP powers > + up from a state where core configuration and context is lost. The > procedure is execution has the > + following properties: > + 1. The procedure executes before the processor is handed over to the > operating system. > + 2. All processors execute the same startup procedure. > + 3. The procedure may run in parallel with other procedures invoked > through the functions in this > + protocol, or with processors that are executing an MM handler or runn= ing > in the operating system. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Procedure A pointer to the code stream to = be run on > the designated target AP > + of the system. Type EFI_AP_PROCE= DURE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.Startup= AllAPs. > + If caller may pass a value of NU= LL to deregister any > existing > + startup procedure. > + @param[in,out] ProcedureArguments Allows the caller to pass a list= of > parameters to the code that is > + run by the AP. It is an optional= common mailbox > between APs and > + the caller to share information > + > + @retval EFI_SUCCESS The Procedure has been set succe= ssfully. > + @retval EFI_INVALID_PARAMETER The Procedure is NULL but > ProcedureArguments not NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpSetStartupProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN OUT VOID *ProcedureArguments OPTIONAL > + ) > +{ > + return RegisterStartupProcedure (Procedure, ProcedureArguments); > +} > + > +/** > + When non-blocking execution of a procedure on an AP is invoked with > DispatchProcedure, > + via the use of a token, this function can be used to check for comple= tion of > the procedure on the AP. > + The function takes the token that was passed into the DispatchProcedu= re > call. If the procedure > + is complete, and therefore it is now possible to run another procedur= e on > the same AP, this function > + returns EFI_SUCESS. In this case the status returned by the procedure= that > executed on the AP is > + returned in the token's Status field. If the procedure has not yet > completed, then this function > + returns EFI_NOT_READY. > + > + When a non-blocking execution of a procedure is invoked with > BroadcastProcedure, via the > + use of a token, this function can be used to check for completion of = the > procedure on all the > + broadcast APs. The function takes the token that was passed into the > BroadcastProcedure > + call. If the procedure is complete on all broadcast APs this function= returns > EFI_SUCESS. In this > + case the Status field in the token passed into the function reflects = the > overall result of the > + invocation, which may be EFI_SUCCESS, if all executions succeeded, or= the > first observed failure. > + If the procedure has not yet completed on the broadcast APs, the func= tion > returns > + EFI_NOT_READY. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the tok= en that was > passed into > + DispatchProcedure or BroadcastPr= ocedure. > + > + @retval EFI_SUCCESS Procedure has completed. > + @retval EFI_NOT_READY The Procedure has not completed. > + @retval EFI_INVALID_PARAMETER Token or Token->Completion is > NULL > + @retval EFI_NOT_FOUND Token is not currently in use fo= r a non- > blocking call > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpCheckForProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN MM_COMPLETION Token > + ) > +{ > + if (Token =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!IsCurrentToken ((UINTN)-1, (SPIN_LOCK *)Token)) { > + return EFI_NOT_FOUND; > + } > + > + return IsApReady ((SPIN_LOCK *)Token); > +} > + > +/** > + When a non-blocking execution of a procedure on an AP is invoked via > DispatchProcedure, > + this function will block the caller until the remote procedure has co= mpleted > on the designated AP. > + The non-blocking procedure invocation is identified by the Token > parameter, which must match the > + token that used when DispatchProcedure was called. Upon completion th= e > status returned by > + the procedure that executed on the AP is used to update the token's > Status field. > + > + When a non-blocking execution of a procedure on an AP is invoked via > BroadcastProcedure > + this function will block the caller until the remote procedure has co= mpleted > on all of the APs that > + entered MM. The non-blocking procedure invocation is identified by th= e > Token parameter, which > + must match the token that used when BroadcastProcedure was called. > Upon completion the > + overall status returned by the procedures that executed on the broadc= ast > AP is used to update the > + token's Status field. The overall status may be EFI_SUCCESS, if all > executions succeeded, or the > + first observed failure. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the tok= en that was > passed into > + DispatchProcedure or BroadcastPr= ocedure. > + > + @retval EFI_SUCCESS Procedure has completed. > + @retval EFI_INVALID_PARAMETER Token or Token->Completion is > NULL > + @retval EFI_NOT_FOUND Token is not currently in use fo= r a non- > blocking call > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpWaitForProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN MM_COMPLETION Token > + ) > +{ > + EFI_STATUS Status; > + > + do { > + Status =3D SmmMpCheckForProcedure (This, Token); > + } while (Status =3D=3D EFI_NOT_READY); > + > + return Status; > +} > + > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h > b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h > new file mode 100644 > index 0000000000..e0d823a4b1 > --- /dev/null > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h > @@ -0,0 +1,286 @@ > +/** @file > +Include file for SMM MP protocol implementation. > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _SMM_MP_PROTOCOL_H_ > +#define _SMM_MP_PROTOCOL_H_ > + > +// > +// SMM MP Protocol function prototypes. > +// > + > +/** > + Service to retrieves the number of logical processor in the platform. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[out] NumberOfProcessors Pointer to the total number of logica= l > processors in the system, > + including the BSP and all APs. > + > + @retval EFI_SUCCESS The number of processors was retrieve= d > successfully > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL > +**/ > + > +EFI_STATUS > +EFIAPI > +SmmMpGetNumberOfProcessors ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + OUT UINTN *NumberOfProcessors > + ); > + > + > +/** > + This service allows the caller to invoke a procedure one of the appli= cation > processors (AP). This > + function uses an optional token parameter to support blocking and non= - > blocking modes. If the token > + is passed into the call, the function will operate in a non-blocking = fashion > and the caller can > + check for completion with CheckOnProcedure or WaitForProcedure. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance= . > + @param[in] Procedure A pointer to the procedure to b= e run on > the designated target > + AP of the system. Type EFI_AP_P= ROCEDURE2 is defined > below in > + related definitions. > + @param[in] CpuNumber The zero-based index of the pro= cessor > number of the target > + AP, on which the code stream is= supposed to run. If the > number > + points to the calling processor= then it will not run the > + supplied code. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for this AP to > + finish execution of Procedure, = either for blocking or > + non-blocking mode. Zero means i= nfinity. If the timeout > + expires before this AP returns = from Procedure, then > Procedure > + on the AP is terminated. If the= timeout expires in > blocking > + mode, the call returns EFI_TIME= OUT. If the timeout > expires > + in non-blocking mode, the timeo= ut determined can be > through > + CheckOnProcedure or WaitForProc= edure. > + Note that timeout support is op= tional. Whether an > + implementation supports this fe= ature, can be > determined via > + the Attributes data member. > + @param[in,out] ProcedureArguments Allows the caller to pass a lis= t of > parameters to the code > + that is run by the AP. It is an= optional common mailbox > + between APs and the caller to s= hare information. > + @param[in,out] Token This is parameter is broken int= o two > components: > + 1.Token->Completion is an optio= nal parameter that > allows the > + caller to execute the procedure= in a blocking or non- > blocking > + fashion. If it is NULL the call= is blocking, and the call will > + not return until the AP has com= pleted the procedure. If > the > + token is not NULL, the call wil= l return immediately. The > caller > + can check whether the procedure= has completed with > + CheckOnProcedure or WaitForProc= edure. > + 2.Token->Status The implementat= ion updates the > address pointed > + at by this variable with the st= atus code returned by > Procedure > + when it completes execution on = the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to compl= ete within the optional > timeout. > + The implementation will update = this variable with > EFI_NOT_READY > + prior to starting Procedure on = the target AP > + @param[in,out] CPUStatus This optional pointer may be us= ed to get > the status code returned > + by Procedure when it completes = execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure fa= ils to complete within > the optional > + timeout. The implementation wil= l update this variable > with > + EFI_NOT_READY prior to starting= Procedure on the > target AP. > + > + @retval EFI_SUCCESS In the blocking case, this indi= cates that > Procedure has completed > + execution on the target AP. > + In the non-blocking case this i= ndicates that the > procedure has > + been successfully scheduled for= execution on the target > AP. > + @retval EFI_INVALID_PARAMETER The input arguments are out of > range. Either the target AP is the > + caller of the function, or the = Procedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy execut= ing another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for ano= ther > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout e= xpired > before the specified AP > + has finished > + @retval EFI_OUT_OF_RESOURCES Could not allocate a required > resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpDispatchProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN CpuNumber, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT MM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ); > + > +/** > + This service allows the caller to invoke a procedure on all running > application processors (AP) > + except the caller. This function uses an optional token parameter to > support blocking and > + nonblocking modes. If the token is passed into the call, the function= will > operate in a non-blocking > + fashion and the caller can check for completion with CheckOnProcedure= or > WaitForProcedure. > + > + It is not necessary for the implementation to run the procedure on ev= ery > processor on the platform. > + Processors that are powered down in such a way that they cannot respo= nd > to interrupts, may be > + excluded from the broadcast. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance= . > + @param[in] Procedure A pointer to the code stream to= be run on > the APs that have > + entered MM. Type EFI_AP_PROCEDU= RE is defined > below in related > + definitions. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, either = for blocking or non- > blocking mode. > + Zero means infinity. If the tim= eout expires before all > APs return > + from Procedure, then Procedure = on the failed APs is > terminated. If > + the timeout expires in blocking= mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in non-b= locking mode, the > timeout determined > + can be through CheckOnProcedure= or > WaitForProcedure. > + Note that timeout support is op= tional. Whether an > implementation > + supports this feature can be de= termined via the > Attributes data > + member. > + @param[in,out] ProcedureArguments Allows the caller to pass a lis= t of > parameters to the code > + that is run by the AP. It is an= optional common mailbox > + between APs and the caller to s= hare information. > + @param[in,out] Token This is parameter is broken int= o two > components: > + 1.Token->Completion is an optio= nal parameter that > allows the > + caller to execute the procedure= in a blocking or non- > blocking > + fashion. If it is NULL the call= is blocking, and the call will > + not return until the AP has com= pleted the procedure. If > the > + token is not NULL, the call wil= l return immediately. The > caller > + can check whether the procedure= has completed with > + CheckOnProcedure or WaitForProc= edure. > + 2.Token->Status The implementat= ion updates the > address pointed > + at by this variable with the st= atus code returned by > Procedure > + when it completes execution on = the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to compl= ete within the optional > timeout. > + The implementation will update = this variable with > EFI_NOT_READY > + prior to starting Procedure on = the target AP > + @param[in,out] CPUStatus This optional pointer may be us= ed to get > the individual status > + returned by every AP that parti= cipated in the broadcast. > This > + parameter if used provides the = base address of an array > to hold > + the EFI_STATUS value of each AP= in the system. The size > of the > + array can be ascertained by the > GetNumberOfProcessors function. > + As mentioned above, the broadca= st may not include > every processor > + in the system. Some implementat= ions may exclude > processors that > + have been powered down in such = a way that they are > not responsive > + to interrupts. Additionally the= broadcast excludes the > processor > + which is making the BroadcastPr= ocedure call. For every > excluded > + processor, the array entry must= contain a value of > EFI_NOT_STARTED > + > + @retval EFI_SUCCESS In the blocking case, this indi= cates that > Procedure has completed > + execution on the APs. > + In the non-blocking case this i= ndicates that the > procedure has > + been successfully scheduled for= execution on the APs. > + @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy execut= ing another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for ano= ther > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout e= xpired > before the specified AP > + has finished > + @retval EFI_OUT_OF_RESOURCES Could not allocate a required > resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpBroadcastProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT MM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ); > + > + > +/** > + This service allows the caller to set a startup procedure that will b= e > executed when an AP powers > + up from a state where core configuration and context is lost. The > procedure is execution has the > + following properties: > + 1. The procedure executes before the processor is handed over to the > operating system. > + 2. All processors execute the same startup procedure. > + 3. The procedure may run in parallel with other procedures invoked > through the functions in this > + protocol, or with processors that are executing an MM handler or runn= ing > in the operating system. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Procedure A pointer to the code stream to = be run on > the designated target AP > + of the system. Type EFI_AP_PROCE= DURE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.Startup= AllAPs. > + If caller may pass a value of NU= LL to deregister any > existing > + startup procedure. > + @param[in,out] ProcedureArguments Allows the caller to pass a list= of > parameters to the code that is > + run by the AP. It is an optional= common mailbox > between APs and > + the caller to share information > + > + @retval EFI_SUCCESS The Procedure has been set succe= ssfully. > + @retval EFI_INVALID_PARAMETER The Procedure is NULL but > ProcedureArguments not NULL. > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpSetStartupProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN OUT VOID *ProcedureArguments OPTIONAL > + ); > + > +/** > + When non-blocking execution of a procedure on an AP is invoked with > DispatchProcedure, > + via the use of a token, this function can be used to check for comple= tion of > the procedure on the AP. > + The function takes the token that was passed into the DispatchProcedu= re > call. If the procedure > + is complete, and therefore it is now possible to run another procedur= e on > the same AP, this function > + returns EFI_SUCESS. In this case the status returned by the procedure= that > executed on the AP is > + returned in the token's Status field. If the procedure has not yet > completed, then this function > + returns EFI_NOT_READY. > + > + When a non-blocking execution of a procedure is invoked with > BroadcastProcedure, via the > + use of a token, this function can be used to check for completion of = the > procedure on all the > + broadcast APs. The function takes the token that was passed into the > BroadcastProcedure > + call. If the procedure is complete on all broadcast APs this function= returns > EFI_SUCESS. In this > + case the Status field in the token passed into the function reflects = the > overall result of the > + invocation, which may be EFI_SUCCESS, if all executions succeeded, or= the > first observed failure. > + If the procedure has not yet completed on the broadcast APs, the func= tion > returns > + EFI_NOT_READY. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the tok= en that was > passed into > + DispatchProcedure or BroadcastPr= ocedure. > + > + @retval EFI_SUCCESS Procedure has completed. > + @retval EFI_NOT_READY The Procedure has not completed. > + @retval EFI_INVALID_PARAMETER Token or Token->Completion is > NULL > + @retval EFI_NOT_FOUND Token is not currently in use fo= r a non- > blocking call > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpCheckForProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN MM_COMPLETION Token > + ); > + > +/** > + When a non-blocking execution of a procedure on an AP is invoked via > DispatchProcedure, > + this function will block the caller until the remote procedure has co= mpleted > on the designated AP. > + The non-blocking procedure invocation is identified by the Token > parameter, which must match the > + token that used when DispatchProcedure was called. Upon completion th= e > status returned by > + the procedure that executed on the AP is used to update the token's > Status field. > + > + When a non-blocking execution of a procedure on an AP is invoked via > BroadcastProcedure > + this function will block the caller until the remote procedure has co= mpleted > on all of the APs that > + entered MM. The non-blocking procedure invocation is identified by th= e > Token parameter, which > + must match the token that used when BroadcastProcedure was called. > Upon completion the > + overall status returned by the procedures that executed on the broadc= ast > AP is used to update the > + token's Status field. The overall status may be EFI_SUCCESS, if all > executions succeeded, or the > + first observed failure. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the tok= en that was > passed into > + DispatchProcedure or BroadcastPr= ocedure. > + > + @retval EFI_SUCCESS Procedure has completed. > + @retval EFI_INVALID_PARAMETER Token or Token->Completion is > NULL > + @retval EFI_NOT_FOUND Token is not currently in use fo= r a non- > blocking call > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpWaitForProcedure ( > + IN CONST EFI_MM_MP_PROTOCOL *This, > + IN MM_COMPLETION Token > + ); > + > +#endif > -- > 2.21.0.windows.1 >=20 >=20 >=20