From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.88, mailfrom: ray.ni@intel.com) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by groups.io with SMTP; Mon, 08 Jul 2019 22:51:51 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Jul 2019 22:51:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,469,1557212400"; d="scan'208";a="176391602" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by orsmga002.jf.intel.com with ESMTP; 08 Jul 2019 22:51:49 -0700 Received: from fmsmsx154.amr.corp.intel.com (10.18.116.70) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 8 Jul 2019 22:51:44 -0700 Received: from shsmsx107.ccr.corp.intel.com (10.239.4.96) by FMSMSX154.amr.corp.intel.com (10.18.116.70) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 8 Jul 2019 22:51:44 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.110]) by SHSMSX107.ccr.corp.intel.com ([169.254.9.162]) with mapi id 14.03.0439.000; Tue, 9 Jul 2019 13:51:42 +0800 From: "Ni, Ray" To: "Dong, Eric" , "devel@edk2.groups.io" CC: Laszlo Ersek Subject: Re: [Patch v4 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Topic: [Patch v4 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Index: AQHVNZWsITxmp/h7C0+5+AzEIMwoS6bBnSrg Date: Tue, 9 Jul 2019 05:51:42 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C21D855@SHSMSX104.ccr.corp.intel.com> References: <20190708140130.10632-1-eric.dong@intel.com> <20190708140130.10632-3-eric.dong@intel.com> In-Reply-To: <20190708140130.10632-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 Some comments that could help to refine the code: 1. IsTokenInUse() can use linked list APIs as what the other code in your p= atch does. 2. IsTokenInUse() is called from InternalSmmStartupAllAPs() and InternalSmm= StartupThisAp(). Can we replace if (IsTokenInUse()) {return EFI_ALREADY_STARTED;} with ASSERT (!IsToke= nInUse())? Because the token is allocated every time when calling the two Internal functions. The all= ocation is done by PiSmmCpu driver not the caller. If IsTokenInUse() returns TRUE, that's PiSmmCpu driver= 's bug, which doesn't need to report to caller. 3. I think we could have one CreateToken() to replace InsertToken(). It allocates & initializes the token and inserts to the linked list. 4. FreeToken() can be FreeTokens(). It can be called in BSPHandler() inste= ad of SmiRendezvous(). 5. Many code use below check: Index !=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu && *(m= SmmMpSyncData->CpuData[Index].Present Can you please create a small function like IsPresentAp() for this chec= k? 6. Status local variable is not necessary in below code. Status =3D InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, &Wrapper= , NULL, 0, NULL); return Status; 7. Regarding mApWrapperFunc and gTokenList, can you please put them in gSmm= CpuPrivate? > -----Original Message----- > From: Dong, Eric > Sent: Monday, July 8, 2019 10:02 PM > To: devel@edk2.groups.io > Cc: Ni, Ray ; Laszlo Ersek > Subject: [Patch v4 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP > Protocol. >=20 > v4 changes: > 1. Use link list to save the token info. >=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 a= t 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 | 558 > ++++++++++++++++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 16 + > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 175 +++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 + > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 376 +++++++++++++ > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++ > 6 files changed, 1392 insertions(+), 22 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..8652ae1696 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > @@ -22,6 +22,8 @@ UINTN mSemaphoreS= ize; > SPIN_LOCK *mPFLock =3D NULL; > SMM_CPU_SYNC_MODE mCpuSmmSyncMode; > BOOLEAN mMachineCheckSupported =3D F= ALSE; > +PROCEDURE_WRAPPER *mApWrapperFunc; > +LIST_ENTRY gTokenList; >=20 > /** > Performs an atomic compare exchange operation to get semaphore. > @@ -347,6 +349,128 @@ ReplaceOSMtrrs ( > MtrrSetAllMtrrs (&gSmiMtrrs); > } >=20 > +/** > + Wheck whether task has been finished by all APs. > + > + @param BlockMode Whether did it in block mode or non-block mod= e. > + > + @retval TRUE Task has been finished by all APs. > + @retval FALSE Task not has been finished by all APs. > + > +**/ > +BOOLEAN > +WaitForAllAPsNotBusy ( > + 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; > +} > + > +/** > + 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 > +ReleaseToken ( > + IN UINTN CpuIndex > + ) > +{ > + UINTN Index; > + BOOLEAN Released; > + > + if (InStartAllApsCall ()) { > + // > + // In Start All APs mode, make sure all APs have finished task. > + // > + if (WaitForAllAPsNotBusy (FALSE)) { > + // > + // Clean the flags update in the function call. > + // > + Released =3D FALSE; > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + // > + // Only In SMM APs need to be clean up. > + // > + if (mSmmMpSyncData->CpuData[Index].Present && > mSmmMpSyncData->CpuData[Index].Token !=3D NULL) { > + if (!Released) { > + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token); > + Released =3D TRUE; > + } > + mSmmMpSyncData->CpuData[Index].Token =3D NULL; > + } > + } > + } > + } else { > + // > + // In single AP mode. > + // > + if (mSmmMpSyncData->CpuData[CpuIndex].Token !=3D NULL) { > + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token); > + mSmmMpSyncData->CpuData[CpuIndex].Token =3D NULL; > + } > + } > +} > + > /** > SMI handler for BSP. >=20 > @@ -476,12 +600,7 @@ BSPHandler ( > // > // Make sure all APs have completed their pending none-block tasks > // > - for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > - if (Index !=3D CpuIndex && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > - AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > - ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > - } > - } > + WaitForAllAPsNotBusy (TRUE); >=20 > // > // Perform the remaining tasks > @@ -604,6 +723,7 @@ APHandler ( > UINT64 Timer; > UINTN BspIndex; > MTRR_SETTINGS Mtrrs; > + EFI_STATUS ProcedureStatus; >=20 > // > // Timeout BSP > @@ -730,14 +850,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].Param= eter > + ); > + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { > + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D ProcedureStatus; > + } >=20 > // > // Release BUSY > // > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > + > + ReleaseToken (CpuIndex); > } >=20 > if (SmmCpuFeaturesNeedConfigureMtrrs()) { > @@ -906,13 +1031,136 @@ Gen4GPageTable ( > return (UINT32)(UINTN)PageTable; > } >=20 > +/** > + Checks whether the input token is the current used token. > + > + @param[in] Token This parameter describes the token that was pas= sed > 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 > +IsTokenInUse ( > + IN SPIN_LOCK *Token > + ) > +{ > + LIST_ENTRY *Link; > + PROCEDURE_TOKEN *ProcToken; > + > + if (Token =3D=3D NULL) { > + return FALSE; > + } > + > + for (Link =3D gTokenList.ForwardLink; Link !=3D &gTokenList; Link =3D = Link- > >ForwardLink) { > + ProcToken =3D PROCEDURE_TOKEN_FROM_LINK (Link); > + > + if (ProcToken->ProcedureToken =3D=3D Token) { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + Insert the token to the maintained list. > + > + @param[in] Token This parameter describes the token that = was > passed into DispatchProcedure or > + BroadcastProcedure. > + > +**/ > +VOID > +InsertToken ( > + IN SPIN_LOCK *Token > + ) > +{ > + PROCEDURE_TOKEN *ProcToken; > + > + ProcToken =3D AllocatePool (sizeof (PROCEDURE_TOKEN)); > + ASSERT (ProcToken !=3D NULL); > + > + ProcToken->Signature =3D PROCEDURE_TOKEN_SIGNATURE; > + ProcToken->ProcedureToken =3D Token; > + > + InsertTailList (&gTokenList, &ProcToken->Link); > +} > + > +/** > + Free the tokens in the maintained list. > + > +**/ > +VOID > +FreeToken ( > + VOID > + ) > +{ > + LIST_ENTRY *Link; > + PROCEDURE_TOKEN *ProcToken; > + > + while (!IsListEmpty (&gTokenList)) { > + Link =3D GetFirstNode (&gTokenList); > + ProcToken =3D PROCEDURE_TOKEN_FROM_LINK (Link); > + > + RemoveEntryList (&ProcToken->Link); > + > + FreePool ((VOID *)ProcToken->ProcedureToken); > + FreePool (ProcToken); > + } > +} > + > +/** > + 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 procedure= to run > @param[in] CpuIndex Target CPU Index > - @param[in, out] ProcArguments The parameter to pass to the > procedure > - @param[in] BlockingMode Startup AP in blocking mode = or not > + @param[in,out] ProcArguments The parameter to pass to the > procedure > + @param[in] Token This is an optional paramete= r that allows > the caller to execute the > + procedure in a blocking or n= on-blocking fashion. If it is > NULL the > + call is blocking, and the ca= ll will not return until the AP > has > + completed the procedure. If = the token is not NULL, > the call will > + return immediately. The call= er can check whether the > procedure has > + completed with CheckOnProced= ure or > WaitForProcedure. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, eith= er for blocking or non- > blocking mode. > + Zero means infinity. If the = timeout expires before all > APs return > + from Procedure, then Procedu= re on the failed APs is > terminated. If > + the timeout expires in block= ing mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in no= n-blocking mode, the > timeout determined > + can be through CheckOnProced= ure or > WaitForProcedure. > + Note that timeout support is= optional. Whether an > implementation > + supports this feature can be= determined via the > Attributes data > + member. > + @param[in,out] CpuStatus This optional pointer may be= used to > get the status code returned > + by Procedure when it complet= es execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure= fails to complete > within the optional > + timeout. The implementation = will update this variable > with > + EFI_NOT_READY prior to start= ing Procedure on the > target AP. >=20 > @retval EFI_INVALID_PARAMETER CpuNumber not valid > @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP > @@ -923,10 +1171,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 +1202,195 @@ 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 (IsTokenInUse (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)); > - return EFI_INVALID_PARAMETER; > + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData- > >CpuData[%d].Busy\n", CpuIndex)); > + ReleaseSpinLock (Token); > + return EFI_NOT_READY; > } > + > + AcquireSpinLock (Token); > + InsertToken (Token); > } >=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 A= Ps. > + > + @param[in] Procedure A pointer to the function to be= run on > + enabled APs of the system. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, e= ither 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 t= hat 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 the= token is not NULL, the > call will > + return immediately. The caller = can check whether the > procedure has > + completed with CheckOnProcedure= or > WaitForProcedure. > + @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 blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > 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 (IsTokenInUse (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; > + } > + > + // > + // Make sure all BUSY should be acquired. > + // > + // Because former code already check mSmmMpSyncData- > >CpuData[***].Busy for each AP. > + // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFa= il > for not > + // block mode. > + // > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > + AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > + } > + } > + > + if (Token !=3D NULL) { > + AcquireSpinLock (Token); > + InsertToken (Token); > + } > + > + 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 va= lue 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. > + // > + WaitForAllAPsNotBusy (TRUE); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + ISO C99 6.5.2.2 "Function calls", paragraph 9: > + If the function is defined with a type that is not compatible with > + the type (of the expression) pointed to by the expression that > + denotes the called function, the behavior is undefined. > + > + So add below wrapper function to convert between EFI_AP_PROCEDURE > + and EFI_AP_PROCEDURE2. > + > + 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 +1416,18 @@ SmmBlockingStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > TRUE); > + PROCEDURE_WRAPPER Wrapper; > + EFI_STATUS Status; > + > + 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); > + > + return Status; > } >=20 > /** > @@ -1020,7 +1452,28 @@ SmmStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)); > + SPIN_LOCK *CpuToken; > + UINTN SpinLockSize; > + > + mApWrapperFunc[CpuIndex].Procedure =3D Procedure; > + mApWrapperFunc[CpuIndex].ProcedureArgument =3D ProcArguments; > + > + if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) { > + CpuToken =3D NULL; > + } else { > + SpinLockSize =3D GetSpinLockProperties (); > + CpuToken =3D AllocatePool (SpinLockSize); > + ASSERT (CpuToken !=3D NULL); > + if (CpuToken =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + InitializeSpinLock ((SPIN_LOCK *)(CpuToken)); > + } > + > + // > + // Use wrapper function to convert EFI_AP_PROCEDURE to > EFI_AP_PROCEDURE2. > + // > + return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, > &mApWrapperFunc[CpuIndex], CpuToken, 0, NULL); > } >=20 > /** > @@ -1112,6 +1565,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 > // > @@ -1250,12 +1710,31 @@ SmiRendezvous ( > Exit: > SmmCpuFeaturesRendezvousExit (CpuIndex); >=20 > + if (CpuIndex =3D=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu) { > + FreeToken (); > + } > + > // > // Restore Cr2 > // > RestoreCr2 (Cr2); > } >=20 > +/** > + Allocate buffer for SpinLock and Wrapper function buffer. > + > +**/ > +VOID > +InitializeDataForMmMp ( > + VOID > + ) > +{ > + mApWrapperFunc =3D AllocatePool (sizeof (PROCEDURE_WRAPPER) * > gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); > + ASSERT (mApWrapperFunc !=3D NULL); > + > + InitializeListHead (&gTokenList); > +} > + > /** > Allocate buffer for all semaphores and spin locks. >=20 > @@ -1469,3 +1948,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 b= e run on > the designated target AP > + of the system. Type EFI_AP_PROCED= URE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs. > + If caller may pass a value of NUL= L 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 succes= sfully. > + @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..bb9b0822f8 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > @@ -996,6 +996,22 @@ PiCpuSmmEntry ( > ); > ASSERT_EFI_ERROR (Status); >=20 > + // > + // Initialize global buffer for MM MP. > + // > + InitializeDataForMmMp (); > + > + // > + // 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..eb7e38ea94 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,31 @@ 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; > + > +#define PROCEDURE_TOKEN_SIGNATURE SIGNATURE_32 ('P', 'R', 'T', 'S') > + > +typedef struct { > + UINTN Signature; > + LIST_ENTRY Link; > + > + SPIN_LOCK *ProcedureToken; > +} PROCEDURE_TOKEN; > + > +#define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, > Link, PROCEDURE_TOKEN_SIGNATURE) > + > 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 +384,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 +411,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 +435,7 @@ typedef struct { > SPIN_LOCK *Busy; > volatile UINT32 *Run; > volatile BOOLEAN *Present; > + SPIN_LOCK *Token; > } SMM_CPU_SEMAPHORE_CPU; >=20 > /// > @@ -1259,4 +1285,151 @@ RestoreCr2 ( > IN UINTN Cr2 > ); >=20 > +/** > + Schedule a procedure to run on the specified CPU. > + > + @param[in] Procedure The address of the procedure= to run > + @param[in] CpuIndex Target CPU Index > + @param[in,out] ProcArguments The parameter to pass to the > procedure > + @param[in,out] Token This is an optional paramete= r that allows > the caller to execute the > + procedure in a blocking or n= on-blocking fashion. If it is > NULL the > + call is blocking, and the ca= ll will not return until the AP > has > + completed the procedure. If = the token is not NULL, > the call will > + return immediately. The call= er can check whether the > procedure has > + completed with CheckOnProced= ure or > WaitForProcedure. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, eith= er for blocking or non- > blocking mode. > + Zero means infinity. If the = timeout expires before all > APs return > + from Procedure, then Procedu= re on the failed APs is > terminated. If > + the timeout expires in block= ing mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in no= n-blocking mode, the > timeout determined > + can be through CheckOnProced= ure or > WaitForProcedure. > + Note that timeout support is= optional. Whether an > implementation > + supports this feature can be= determined via the > Attributes data > + member. > + @param[in,out] CPUStatus This optional pointer may be= used to > get the status code returned > + by Procedure when it complet= es execution on the > target AP, or with > + EFI_TIMEOUT if the Procedure= fails to complete > within the optional > + timeout. The implementation = will update this variable > with > + EFI_NOT_READY prior to start= ing 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] Token This parameter describes the token that was pas= sed > 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 > +IsTokenInUse ( > + 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 A= Ps. > + > + @param[in] Procedure A pointer to the function to be= run on > + enabled APs of the system. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, e= ither 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 t= hat 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 the= token is not NULL, the > call will > + return immediately. The caller = can check whether the > procedure has > + completed with CheckOnProcedure= or > WaitForProcedure. > + @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 blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > 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 b= e run on > the designated target AP > + of the system. Type EFI_AP_PROCED= URE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs. > + If caller may pass a value of NUL= L 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 succes= sfully. > + @retval EFI_INVALID_PARAMETER The Procedure is NULL but > ProcedureArguments not NULL. > + > +**/ > +EFI_STATUS > +RegisterStartupProcedure ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArguments OPTIONAL > + ); > + > +/** > + Allocate buffer for SpinLock and Wrapper function buffer. > + > +**/ > +VOID > +InitializeDataForMmMp ( > + VOID > + ); > + > #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..ac563ce02c > --- /dev/null > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c > @@ -0,0 +1,376 @@ > +/** @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 logical > processors in the system, > + including the BSP and all APs. > + > + @retval EFI_SUCCESS The number of processors was retrieved > 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 applic= ation > 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 f= ashion > 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 be= run on > the designated target > + AP of the system. Type EFI_AP_PR= OCEDURE2 is defined > below in > + related definitions. > + @param[in] CpuNumber The zero-based index of the proc= essor > 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, e= ither for blocking or > + non-blocking mode. Zero means in= finity. If the timeout > + expires before this AP returns f= rom Procedure, then > Procedure > + on the AP is terminated. If the = timeout expires in > blocking > + mode, the call returns EFI_TIMEO= UT. If the timeout > expires > + in non-blocking mode, the timeou= t determined can be > through > + CheckOnProcedure or WaitForProce= dure. > + Note that timeout support is opt= ional. Whether an > + implementation supports this fea= ture, can be > determined via > + the Attributes data member. > + @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 sh= are information. > + @param[in,out] Token This is parameter is broken into= two > components: > + 1.Token->Completion is an option= al 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 comp= leted the procedure. If > the > + token is not NULL, the call will= return immediately. The > caller > + can check whether the procedure = has completed with > + CheckOnProcedure or WaitForProce= dure. > + 2.Token->Status The implementati= on updates the > address pointed > + at by this variable with the sta= tus code returned by > Procedure > + when it completes execution on t= he target AP, or with > EFI_TIMEOUT > + if the Procedure fails to comple= te within the optional > timeout. > + The implementation will update t= his variable with > EFI_NOT_READY > + prior to starting Procedure on t= he target AP > + @param[in,out] CPUStatus This optional pointer may be use= d to get > the status code returned > + by Procedure when it completes e= xecution on the > target AP, or with > + EFI_TIMEOUT if the Procedure fai= ls to complete within > the optional > + timeout. The implementation will= update this variable > with > + EFI_NOT_READY prior to starting = Procedure on the > target AP. > + > + @retval EFI_SUCCESS In the blocking case, this indic= ates that > Procedure has completed > + execution on the target AP. > + In the non-blocking case this in= dicates 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 P= rocedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy executi= ng another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for anot= her > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout ex= pired > 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; > + UINTN SpinLockSize; > + > + if (Token !=3D NULL) { > + SpinLockSize =3D GetSpinLockProperties (); > + CpuToken =3D AllocatePool (SpinLockSize); > + 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 eve= ry > processor on the platform. > + Processors that are powered down in such a way that they cannot respon= d > 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_PROCEDUR= E is defined > below in related > + definitions. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, either f= or blocking or non- > blocking mode. > + Zero means infinity. If the time= out expires before all > APs return > + from Procedure, then Procedure o= n the failed APs is > terminated. If > + the timeout expires in blocking = mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in non-bl= ocking mode, the > timeout determined > + can be through CheckOnProcedure = or > WaitForProcedure. > + Note that timeout support is opt= ional. Whether an > implementation > + supports this feature can be det= ermined via the > Attributes data > + member. > + @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 sh= are information. > + @param[in,out] Token This is parameter is broken into= two > components: > + 1.Token->Completion is an option= al 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 comp= leted the procedure. If > the > + token is not NULL, the call will= return immediately. The > caller > + can check whether the procedure = has completed with > + CheckOnProcedure or WaitForProce= dure. > + 2.Token->Status The implementati= on updates the > address pointed > + at by this variable with the sta= tus code returned by > Procedure > + when it completes execution on t= he target AP, or with > EFI_TIMEOUT > + if the Procedure fails to comple= te within the optional > timeout. > + The implementation will update t= his variable with > EFI_NOT_READY > + prior to starting Procedure on t= he target AP > + @param[in,out] CPUStatus This optional pointer may be use= d to get > the individual status > + returned by every AP that partic= ipated in the broadcast. > This > + parameter if used provides the b= ase 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 broadcas= t may not include > every processor > + in the system. Some implementati= ons 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 BroadcastPro= cedure call. For every > excluded > + processor, the array entry must = contain a value of > EFI_NOT_STARTED > + > + @retval EFI_SUCCESS In the blocking case, this indic= ates that > Procedure has completed > + execution on the APs. > + In the non-blocking case this in= dicates 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 executi= ng another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for anot= her > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout ex= pired > 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; > + UINTN SpinLockSize; > + > + if (Token !=3D NULL) { > + SpinLockSize =3D GetSpinLockProperties (); > + CpuToken =3D AllocatePool (SpinLockSize); > + 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 be > 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 runni= ng > in the operating system. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Procedure A pointer to the code stream to b= e run on > the designated target AP > + of the system. Type EFI_AP_PROCED= URE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs. > + If caller may pass a value of NUL= L 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 succes= sfully. > + @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 complet= ion of > the procedure on the AP. > + The function takes the token that was passed into the DispatchProcedur= e > call. If the procedure > + is complete, and therefore it is now possible to run another procedure= 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 t= he > 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 t= he > 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 funct= ion > returns > + EFI_NOT_READY. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the toke= n that was > passed into > + DispatchProcedure or BroadcastPro= cedure. > + > + @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 for= 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 (!IsTokenInUse ((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 com= pleted > 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 the > 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 com= pleted > on all of the APs that > + entered MM. The non-blocking procedure invocation is identified by the > 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 broadca= st > 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 toke= n that was > passed into > + DispatchProcedure or BroadcastPro= cedure. > + > + @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 for= 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 logical > processors in the system, > + including the BSP and all APs. > + > + @retval EFI_SUCCESS The number of processors was retrieved > 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 applic= ation > 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 f= ashion > 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 be= run on > the designated target > + AP of the system. Type EFI_AP_PR= OCEDURE2 is defined > below in > + related definitions. > + @param[in] CpuNumber The zero-based index of the proc= essor > 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, e= ither for blocking or > + non-blocking mode. Zero means in= finity. If the timeout > + expires before this AP returns f= rom Procedure, then > Procedure > + on the AP is terminated. If the = timeout expires in > blocking > + mode, the call returns EFI_TIMEO= UT. If the timeout > expires > + in non-blocking mode, the timeou= t determined can be > through > + CheckOnProcedure or WaitForProce= dure. > + Note that timeout support is opt= ional. Whether an > + implementation supports this fea= ture, can be > determined via > + the Attributes data member. > + @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 sh= are information. > + @param[in,out] Token This is parameter is broken into= two > components: > + 1.Token->Completion is an option= al 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 comp= leted the procedure. If > the > + token is not NULL, the call will= return immediately. The > caller > + can check whether the procedure = has completed with > + CheckOnProcedure or WaitForProce= dure. > + 2.Token->Status The implementati= on updates the > address pointed > + at by this variable with the sta= tus code returned by > Procedure > + when it completes execution on t= he target AP, or with > EFI_TIMEOUT > + if the Procedure fails to comple= te within the optional > timeout. > + The implementation will update t= his variable with > EFI_NOT_READY > + prior to starting Procedure on t= he target AP > + @param[in,out] CPUStatus This optional pointer may be use= d to get > the status code returned > + by Procedure when it completes e= xecution on the > target AP, or with > + EFI_TIMEOUT if the Procedure fai= ls to complete within > the optional > + timeout. The implementation will= update this variable > with > + EFI_NOT_READY prior to starting = Procedure on the > target AP. > + > + @retval EFI_SUCCESS In the blocking case, this indic= ates that > Procedure has completed > + execution on the target AP. > + In the non-blocking case this in= dicates 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 P= rocedure or Token is NULL > + @retval EFI_NOT_READY If the target AP is busy executi= ng another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for anot= her > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout ex= pired > 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 eve= ry > processor on the platform. > + Processors that are powered down in such a way that they cannot respon= d > 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_PROCEDUR= E is defined > below in related > + definitions. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for the APs to finish > + execution of Procedure, either f= or blocking or non- > blocking mode. > + Zero means infinity. If the time= out expires before all > APs return > + from Procedure, then Procedure o= n the failed APs is > terminated. If > + the timeout expires in blocking = mode, the call returns > EFI_TIMEOUT. > + If the timeout expires in non-bl= ocking mode, the > timeout determined > + can be through CheckOnProcedure = or > WaitForProcedure. > + Note that timeout support is opt= ional. Whether an > implementation > + supports this feature can be det= ermined via the > Attributes data > + member. > + @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 sh= are information. > + @param[in,out] Token This is parameter is broken into= two > components: > + 1.Token->Completion is an option= al 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 comp= leted the procedure. If > the > + token is not NULL, the call will= return immediately. The > caller > + can check whether the procedure = has completed with > + CheckOnProcedure or WaitForProce= dure. > + 2.Token->Status The implementati= on updates the > address pointed > + at by this variable with the sta= tus code returned by > Procedure > + when it completes execution on t= he target AP, or with > EFI_TIMEOUT > + if the Procedure fails to comple= te within the optional > timeout. > + The implementation will update t= his variable with > EFI_NOT_READY > + prior to starting Procedure on t= he target AP > + @param[in,out] CPUStatus This optional pointer may be use= d to get > the individual status > + returned by every AP that partic= ipated in the broadcast. > This > + parameter if used provides the b= ase 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 broadcas= t may not include > every processor > + in the system. Some implementati= ons 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 BroadcastPro= cedure call. For every > excluded > + processor, the array entry must = contain a value of > EFI_NOT_STARTED > + > + @retval EFI_SUCCESS In the blocking case, this indic= ates that > Procedure has completed > + execution on the APs. > + In the non-blocking case this in= dicates 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 executi= ng another > procedure > + @retval EFI_ALREADY_STARTED Token is already in use for anot= her > procedure > + @retval EFI_TIMEOUT In blocking mode, the timeout ex= pired > 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 be > 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 runni= ng > in the operating system. > + > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Procedure A pointer to the code stream to b= e run on > the designated target AP > + of the system. Type EFI_AP_PROCED= URE is defined > below in Volume 2 > + with the related definitions of > + EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs. > + If caller may pass a value of NUL= L 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 succes= sfully. > + @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 complet= ion of > the procedure on the AP. > + The function takes the token that was passed into the DispatchProcedur= e > call. If the procedure > + is complete, and therefore it is now possible to run another procedure= 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 t= he > 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 t= he > 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 funct= ion > returns > + EFI_NOT_READY. > + > + @param[in] This The EFI_MM_MP_PROTOCOL instance. > + @param[in] Token This parameter describes the toke= n that was > passed into > + DispatchProcedure or BroadcastPro= cedure. > + > + @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 for= 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 com= pleted > 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 the > 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 com= pleted > on all of the APs that > + entered MM. The non-blocking procedure invocation is identified by the > 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 broadca= st > 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 toke= n that was > passed into > + DispatchProcedure or BroadcastPro= cedure. > + > + @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 for= 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