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.151, mailfrom: eric.dong@intel.com) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by groups.io with SMTP; Mon, 08 Jul 2019 02:18:38 -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 fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Jul 2019 02:18:37 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,466,1557212400"; d="scan'208";a="176110416" Received: from fmsmsx104.amr.corp.intel.com ([10.18.124.202]) by orsmga002.jf.intel.com with ESMTP; 08 Jul 2019 02:18:36 -0700 Received: from fmsmsx603.amr.corp.intel.com (10.18.126.83) by fmsmsx104.amr.corp.intel.com (10.18.124.202) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 8 Jul 2019 02:18:36 -0700 Received: from fmsmsx603.amr.corp.intel.com (10.18.126.83) by fmsmsx603.amr.corp.intel.com (10.18.126.83) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Mon, 8 Jul 2019 02:18:35 -0700 Received: from shsmsx107.ccr.corp.intel.com (10.239.4.96) by fmsmsx603.amr.corp.intel.com (10.18.126.83) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.1713.5 via Frontend Transport; Mon, 8 Jul 2019 02:18:34 -0700 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.3]) by SHSMSX107.ccr.corp.intel.com ([169.254.9.162]) with mapi id 14.03.0439.000; Mon, 8 Jul 2019 17:18:33 +0800 From: "Dong, Eric" To: "Ni, Ray" , "devel@edk2.groups.io" 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: AQHVMUkHfnTcXC+2B0emmKQ2TbC/7Ka58X4wgAAPMiA= Date: Mon, 8 Jul 2019 09:18:32 +0000 Message-ID: References: <20190703024242.33572-1-eric.dong@intel.com> <20190703024242.33572-3-eric.dong@intel.com> <734D49CCEBEEF84792F5B80ED585239D5C215538@SHSMSX104.ccr.corp.intel.com> In-Reply-To: <734D49CCEBEEF84792F5B80ED585239D5C215538@SHSMSX104.ccr.corp.intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: eric.dong@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Ray, > -----Original Message----- > From: Ni, Ray > Sent: Thursday, July 4, 2019 2:18 PM > To: devel@edk2.groups.io; Dong, Eric > Cc: Laszlo Ersek > Subject: RE: [edk2-devel] [Patch v3 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: > Enable MM MP Protocol. >=20 > 1. mMaxNumberOfCpus and gSmmCpuPrivate- > >SmmCoreEntryContext.NumberOfCpus are both used. Can you please > refine the code to use only one? [Eric] will do it in other patch. =20 > 2. I do think that MM_MP code needs to maintain a internal linked list > containing all created tokens. Because it's possible that caller is writ= ten 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, CheckOnProcedur= e > (&TokenA) may return NotFound. > The linked list can be freed upon exiting SMM [Eric] will enable it in my next version change.=20 =20 > 3. IsCurrentToken() can be changed to look up the token in the linked li= st and > the name can be changed to IsTokenInUse(). > The function name reflects the spec wording "EFI_ALREADY_STARTED - > Token is already in use for another procedure."=09 [Eric] will enable it in my next version change. > 4. In InternalSmmStartup[AllAPs|ThisAp], Token can be acquired after Bus= y is > acquired. Token is associated with the procedure. > Busy is associated with the individual processor. [Eric] will enable it in my next version change. > 5. *(CPUStatus + Index) can be changed to CPUStatus[Index]. Use [] inste= ad > of address operation. [Eric] will enable it in my next version change. > 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.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)= ) { > DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData- > >CpuData[%d].Busy\n", Index)); >=20 > // > // 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); > } > } >=20 > ReleaseSpinLock (Token); > return EFI_INVALID_PARAMETER; > } > } > } [Eric] will enable it in my next version change. > 7. IsTaskFinishInAllAPs() can be used by BSPHandler() as well. The funct= ion > name can be WaitForAllAPsNotBusy() or some other name because the > function > has side affect, not just check. [Eric] will enable it in my next version change. > 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 possibl= e to be > freed > as long as it's inserted to the linked list. [Eric] will enable it in my next version change. Thanks, Eric >=20 > Thanks, > Ray >=20 > > -----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. > > > > v3 changes: > > 1. Fix Token clean up too early caused CheckProcedure return error. > > > > v2 changes: > > 1. Remove some duplicated global variables. > > 2. Enhance token design to support multiple task trig for different AP= s at > the > > same time. > > > > V1 changes: > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1937 > > > > Add MM Mp Protocol in PiSmmCpuDxeSmm driver. > > > > 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 > > > > 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 mSemapho= reSize; > > SPIN_LOCK *mPFLock =3D NULL; > > SMM_CPU_SYNC_MODE mCpuSmmSyncMode; > > BOOLEAN mMachineCheckSupported = =3D FALSE; > > +SPIN_LOCK **mApTokenLock; > > > > /** > > Performs an atomic compare exchange operation to get semaphore. > > @@ -146,6 +147,45 @@ ReleaseAllAPs ( > > } > > } > > > > +/** > > + Wheck whether task has been finished by all APs. > > + > > + @param BlockMode Whether did it in block mode or non-block > mode. > > + > > + @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 th= is SMI > run > > > > @@ -347,6 +387,92 @@ ReplaceOSMtrrs ( > > MtrrSetAllMtrrs (&gSmiMtrrs); > > } > > > > +/** > > + 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. > > > > @@ -604,6 +730,7 @@ APHandler ( > > UINT64 Timer; > > UINTN BspIndex; > > MTRR_SETTINGS Mtrrs; > > + EFI_STATUS ProcedureStatus; > > > > // > > // 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].Pa= rameter > > + ); > > + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { > > + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D ProcedureStatus; > > + } > > > > // > > // Release BUSY > > // > > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > > + > > + CleanUpStatusFlags (CpuIndex); > > } > > > > if (SmmCpuFeaturesNeedConfigureMtrrs()) { > > @@ -906,13 +1038,95 @@ Gen4GPageTable ( > > return (UINT32)(UINTN)PageTable; > > } > > > > +/** > > + 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 > passed > > into DispatchProcedure or > > + BroadcastProcedure. > > + > > + @retval TRUE The input token is the current used token. > > + @retval FALSE The input token is not the current used toke= n. > > +**/ > > +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 th= at was > > passed into DispatchProcedure or > > + BroadcastProcedure. > > + > > + @retval EFI_SUCCESS Specified AP has finished task assign= ed by > > StartupThisAPs(). > > + @retval EFI_NOT_READY Specified AP has not finished task an= d > > 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. > > > > @param[in] Procedure The address of the proced= ure 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 mo= de or not > > + @param[in,out] ProcArguments The parameter to pass to = the > > procedure > > + @param[in] Token This is an optional param= eter that allows > > the caller to execute the > > + procedure in a blocking o= r 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 c= aller can check whether > the > > procedure has > > + completed with CheckOnPro= cedure or > > WaitForProcedure. > > + @param[in] TimeoutInMicroseconds Indicates the time limit = in > > microseconds for the APs to finish > > + execution of Procedure, e= ither for blocking or non- > > blocking mode. > > + Zero means infinity. If t= he timeout expires before all > > APs return > > + from Procedure, then Proc= edure on the failed APs is > > terminated. If > > + the timeout expires in bl= ocking mode, the call > returns > > EFI_TIMEOUT. > > + If the timeout expires in= non-blocking mode, the > > timeout determined > > + can be through CheckOnPro= cedure 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 comp= letes execution on the > > target AP, or with > > + EFI_TIMEOUT if the Proced= ure fails to complete > > within the optional > > + timeout. The implementati= on will update this > variable > > with > > + EFI_NOT_READY prior to st= arting Procedure on the > > target AP. > > > > @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; > > + } > > > > - 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; > > + } > > } > > > > 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); > > > > - 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 enable= d APs. > > + > > + @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= , either for > > + blocking or non-blocking mod= e. > > + @param[in,out] ProcedureArguments The parameter passed into > > Procedure for > > + all APs. > > + @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,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_SUCCESS In blocking mode, all APs have fini= shed > before > > + the timeout expired. > > + @retval EFI_SUCCESS In non-blocking mode, function has = been > > 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 + Inde= x; > > + 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= value > 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; > > } > > > > @@ -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; > > } > > > > /** > > @@ -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; > > } > > > > /** > > @@ -1112,6 +1559,13 @@ SmiRendezvous ( > > Cr2 =3D 0; > > SaveCr2 (&Cr2); > > > > + // > > + // 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; > > > > 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 + ApTokenSiz= e; > > 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; > > > > mPFLock =3D mSmmCpuSemaphores.SemaphoreGlobal= .PFLock; > > mConfigSmmCodeAccessCheckLock =3D > > mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock; > > > > + mApTokenLock =3D AllocatePool (sizeof (SPIN_LOCK *) * gSmmCpuPrivat= e- > > >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; > > } > > > > @@ -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 t= o be run on > > the designated target AP > > + of the system. Type EFI_AP_PRO= CEDURE is defined > > below in Volume 2 > > + with the related definitions o= f > > + EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs. > > + If caller may pass a value of = NULL to deregister any > > existing > > + startup procedure. > > + @param[in] ProcedureArguments Allows the caller to pass a li= st of > > parameters to the code that is > > + run by the AP. It is an option= al common mailbox > > between APs and > > + the caller to share informatio= n > > + > > + @retval EFI_SUCCESS The Procedure has been set suc= cessfully. > > + @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); > > > > + // > > + // 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 > > > > #include > > #include > > @@ -221,11 +222,20 @@ typedef struct { > > EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration; > > } SMM_CPU_PRIVATE_DATA; > > > > +// > > +// 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; > > > > /// > > /// 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; > > > > 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; > > > > #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; > > > > /// > > @@ -439,6 +454,7 @@ extern SPIN_LOCK > > *mConfigSmmCodeAccessCheckLock; > > extern EFI_SMRAM_DESCRIPTOR *mSmmCpuSmramRanges; > > extern UINTN mSmmCpuSmramRangeCount; > > extern UINT8 mPhysicalAddressBits; > > +extern SPIN_LOCK **mApTokenLock; > > > > // > > // Copy of the PcdPteMemoryEncryptionAddressOrMask > > @@ -1259,4 +1275,146 @@ RestoreCr2 ( > > IN UINTN Cr2 > > ); > > > > +/** > > + Schedule a procedure to run on the specified CPU. > > + > > + @param[in] Procedure The address of the proced= ure 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 param= eter that > allows > > the caller to execute the > > + procedure in a blocking o= r 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 c= aller can check whether > the > > procedure has > > + completed with CheckOnPro= cedure or > > WaitForProcedure. > > + @param[in] TimeoutInMicroseconds Indicates the time limit = in > > microseconds for the APs to finish > > + execution of Procedure, e= ither for blocking or non- > > blocking mode. > > + Zero means infinity. If t= he timeout expires before all > > APs return > > + from Procedure, then Proc= edure on the failed APs is > > terminated. If > > + the timeout expires in bl= ocking mode, the call > returns > > EFI_TIMEOUT. > > + If the timeout expires in= non-blocking mode, the > > timeout determined > > + can be through CheckOnPro= cedure 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 comp= letes execution on the > > target AP, or with > > + EFI_TIMEOUT if the Proced= ure fails to complete > > within the optional > > + timeout. The implementati= on will update this > variable > > with > > + EFI_NOT_READY prior to st= arting 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 successfull= y > > 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 > passed > > into DispatchProcedure or > > + BroadcastProcedure. > > + > > + @retval TRUE The input token is the current used token. > > + @retval FALSE The input token is not the current used toke= n. > > +**/ > > +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 th= at was > > passed into DispatchProcedure or > > + BroadcastProcedure. > > + > > + @retval EFI_SUCCESS Specified AP has finished task assign= ed by > > StartupThisAPs(). > > + @retval EFI_NOT_READY Specified AP has not finished task an= d > > timeout has not expired. > > +**/ > > +EFI_STATUS > > +IsApReady ( > > + IN SPIN_LOCK *Token > > + ); > > + > > +/** > > + Worker function to execute a caller provided function on all enable= d APs. > > + > > + @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= , either for > > + blocking or non-blocking mod= e. > > + @param[in,out] ProcedureArgument The parameter passed into > > Procedure for > > + all APs. > > + @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,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_SUCCESS In blocking mode, all APs have fini= shed > before > > + the timeout expired. > > + @retval EFI_SUCCESS In non-blocking mode, function has = been > > 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 t= o be run on > > the designated target AP > > + of the system. Type EFI_AP_PRO= CEDURE is defined > > below in Volume 2 > > + with the related definitions o= f > > + EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs. > > + If caller may pass a value of = NULL to deregister any > > existing > > + startup procedure. > > + @param[in,out] ProcedureArguments Allows the caller to pass a li= st of > > parameters to the code that is > > + run by the AP. It is an option= al common mailbox > > between APs and > > + the caller to share informatio= n > > + > > + @retval EFI_SUCCESS The Procedure has been set suc= cessfully. > > + @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 > > > > [Sources.Ia32] > > Ia32/Semaphore.c > > @@ -105,6 +107,7 @@ > > gEfiSmmReadyToLockProtocolGuid ## NOTIFY > > gEfiSmmCpuServiceProtocolGuid ## PRODUCES > > gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES > > + gEfiMmMpProtocolGuid ## PRODUCES > > > > [Guids] > > gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## H= OB # 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 platfor= m. > > + > > + @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 retrie= ved > > 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 app= lication > > processors (AP). This > > + function uses an optional token parameter to support blocking and n= on- > > blocking modes. If the token > > + is passed into the call, the function will operate in a non-blockin= g fashion > > and the caller can > > + check for completion with CheckOnProcedure or WaitForProcedure. > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instan= ce. > > + @param[in] Procedure A pointer to the procedure to= be run on > > the designated target > > + AP of the system. Type EFI_AP= _PROCEDURE2 is > defined > > below in > > + related definitions. > > + @param[in] CpuNumber The zero-based index of the p= rocessor > > number of the target > > + AP, on which the code stream = is supposed to run. If > the > > number > > + points to the calling process= or 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= infinity. If the > timeout > > + expires before this AP return= s from Procedure, then > > Procedure > > + on the AP is terminated. If t= he timeout expires in > > blocking > > + mode, the call returns EFI_TI= MEOUT. If the timeout > > expires > > + in non-blocking mode, the tim= eout determined can be > > through > > + CheckOnProcedure or WaitForPr= ocedure. > > + Note that timeout support is = optional. Whether an > > + implementation supports this = feature, can be > > determined via > > + the Attributes data member. > > + @param[in,out] ProcedureArguments Allows the caller to pass a l= ist 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. > > + @param[in,out] Token This is parameter is broken i= nto two > > components: > > + 1.Token->Completion is an opt= ional parameter that > > allows the > > + caller to execute the procedu= re in a blocking or non- > > blocking > > + fashion. If it is NULL the ca= ll is blocking, and the call will > > + not return until the AP has c= ompleted the procedure. > If > > the > > + token is not NULL, the call w= ill return immediately. The > > caller > > + can check whether the procedu= re has completed with > > + CheckOnProcedure or WaitForPr= ocedure. > > + 2.Token->Status The implement= ation updates the > > address pointed > > + at by this variable with the = status code returned by > > Procedure > > + when it completes execution o= n the target AP, or with > > EFI_TIMEOUT > > + if the Procedure fails to com= plete within the optional > > timeout. > > + The implementation will updat= e this variable with > > EFI_NOT_READY > > + prior to starting Procedure o= n the target AP > > + @param[in,out] CPUStatus This optional pointer may be = used to > get > > the status code returned > > + by Procedure when it complete= s execution on the > > target AP, or with > > + EFI_TIMEOUT if the Procedure = fails to complete within > > the optional > > + timeout. The implementation w= ill update this variable > > with > > + EFI_NOT_READY prior to starti= ng Procedure on the > > target AP. > > + > > + @retval EFI_SUCCESS In the blocking case, this in= dicates that > > Procedure has completed > > + execution on the target AP. > > + In the non-blocking case this= indicates that the > > procedure has > > + been successfully scheduled f= or execution on the > target > > AP. > > + @retval EFI_INVALID_PARAMETER The input arguments are out o= f > > range. Either the target AP is the > > + caller of the function, or th= e Procedure or Token is > NULL > > + @retval EFI_NOT_READY If the target AP is busy exec= uting > another > > procedure > > + @retval EFI_ALREADY_STARTED Token is already in use for a= nother > > procedure > > + @retval EFI_TIMEOUT In blocking mode, the timeout= expired > > 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 t= o > > support blocking and > > + nonblocking modes. If the token is passed into the call, the functi= on will > > operate in a non-blocking > > + fashion and the caller can check for completion with CheckOnProcedu= re > or > > WaitForProcedure. > > + > > + It is not necessary for the implementation to run the procedure on = every > > processor on the platform. > > + Processors that are powered down in such a way that they cannot > respond > > to interrupts, may be > > + excluded from the broadcast. > > + > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instan= ce. > > + @param[in] Procedure A pointer to the code stream = to be run > on > > the APs that have > > + entered MM. Type EFI_AP_PROCE= DURE is defined > > below in related > > + definitions. > > + @param[in] TimeoutInMicroseconds Indicates the time limit in > > microseconds for the APs to finish > > + execution of Procedure, eithe= r for blocking or non- > > blocking mode. > > + Zero means infinity. If the t= imeout expires before all > > APs return > > + from Procedure, then Procedur= e on the failed APs is > > terminated. If > > + the timeout expires in blocki= ng mode, the call returns > > EFI_TIMEOUT. > > + If the timeout expires in non= -blocking mode, the > > timeout determined > > + can be through CheckOnProcedu= re 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] ProcedureArguments Allows the caller to pass a l= ist 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. > > + @param[in,out] Token This is parameter is broken i= nto two > > components: > > + 1.Token->Completion is an opt= ional parameter that > > allows the > > + caller to execute the procedu= re in a blocking or non- > > blocking > > + fashion. If it is NULL the ca= ll is blocking, and the call will > > + not return until the AP has c= ompleted the procedure. > If > > the > > + token is not NULL, the call w= ill return immediately. The > > caller > > + can check whether the procedu= re has completed with > > + CheckOnProcedure or WaitForPr= ocedure. > > + 2.Token->Status The implement= ation updates the > > address pointed > > + at by this variable with the = status code returned by > > Procedure > > + when it completes execution o= n the target AP, or with > > EFI_TIMEOUT > > + if the Procedure fails to com= plete within the optional > > timeout. > > + The implementation will updat= e this variable with > > EFI_NOT_READY > > + prior to starting Procedure o= n the target AP > > + @param[in,out] CPUStatus This optional pointer may be = used to > get > > the individual status > > + returned by every AP that par= ticipated in the > broadcast. > > This > > + parameter if used provides th= e 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 t= he > > GetNumberOfProcessors function. > > + As mentioned above, the broad= cast may not include > > every processor > > + in the system. Some implement= ations may exclude > > processors that > > + have been powered down in suc= h a way that they are > > not responsive > > + to interrupts. Additionally t= he broadcast excludes the > > processor > > + which is making the Broadcast= Procedure call. For > every > > excluded > > + processor, the array entry mu= st contain a value of > > EFI_NOT_STARTED > > + > > + @retval EFI_SUCCESS In the blocking case, this in= dicates that > > Procedure has completed > > + execution on the APs. > > + In the non-blocking case this= indicates that the > > procedure has > > + been successfully scheduled f= or execution on the APs. > > + @retval EFI_INVALID_PARAMETER The Procedure or Token is NUL= L > > + @retval EFI_NOT_READY If the target AP is busy exec= uting > another > > procedure > > + @retval EFI_ALREADY_STARTED Token is already in use for a= nother > > procedure > > + @retval EFI_TIMEOUT In blocking mode, the timeout= expired > > 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= 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 th= e > > 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 > running > > in the operating system. > > + > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instanc= e. > > + @param[in] Procedure A pointer to the code stream t= o be run on > > the designated target AP > > + of the system. Type EFI_AP_PRO= CEDURE is defined > > below in Volume 2 > > + with the related definitions o= f > > + EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs. > > + If caller may pass a value of = NULL to deregister any > > existing > > + startup procedure. > > + @param[in,out] ProcedureArguments Allows the caller to pass a li= st of > > parameters to the code that is > > + run by the AP. It is an option= al common mailbox > > between APs and > > + the caller to share informatio= n > > + > > + @retval EFI_SUCCESS The Procedure has been set suc= cessfully. > > + @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 comp= letion > of > > the procedure on the AP. > > + The function takes the token that was passed into the > DispatchProcedure > > call. If the procedure > > + is complete, and therefore it is now possible to run another proced= ure > on > > the same AP, this function > > + returns EFI_SUCESS. In this case the status returned by the procedu= re > 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 o= f the > > procedure on all the > > + broadcast APs. The function takes the token that was passed into th= e > > BroadcastProcedure > > + call. If the procedure is complete on all broadcast APs this functi= on > returns > > EFI_SUCESS. In this > > + case the Status field in the token passed into the function reflect= s 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 > function > > returns > > + EFI_NOT_READY. > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instanc= e. > > + @param[in] Token This parameter describes the t= oken that > was > > passed into > > + DispatchProcedure or Broadcast= Procedure. > > + > > + @retval EFI_SUCCESS Procedure has completed. > > + @retval EFI_NOT_READY The Procedure has not complete= d. > > + @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 (!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 vi= a > > DispatchProcedure, > > + this function will block the caller until the remote procedure has > completed > > 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 vi= a > > BroadcastProcedure > > + this function will block the caller until the remote procedure has > completed > > 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 > broadcast > > 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 instanc= e. > > + @param[in] Token This parameter describes the t= oken that > was > > passed into > > + DispatchProcedure or Broadcast= Procedure. > > + > > + @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 platfor= m. > > + > > + @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 retrie= ved > > 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 app= lication > > processors (AP). This > > + function uses an optional token parameter to support blocking and n= on- > > blocking modes. If the token > > + is passed into the call, the function will operate in a non-blockin= g fashion > > and the caller can > > + check for completion with CheckOnProcedure or WaitForProcedure. > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instan= ce. > > + @param[in] Procedure A pointer to the procedure to= be run on > > the designated target > > + AP of the system. Type EFI_AP= _PROCEDURE2 is > defined > > below in > > + related definitions. > > + @param[in] CpuNumber The zero-based index of the p= rocessor > > number of the target > > + AP, on which the code stream = is supposed to run. If > the > > number > > + points to the calling process= or 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= infinity. If the > timeout > > + expires before this AP return= s from Procedure, then > > Procedure > > + on the AP is terminated. If t= he timeout expires in > > blocking > > + mode, the call returns EFI_TI= MEOUT. If the timeout > > expires > > + in non-blocking mode, the tim= eout determined can be > > through > > + CheckOnProcedure or WaitForPr= ocedure. > > + Note that timeout support is = optional. Whether an > > + implementation supports this = feature, can be > > determined via > > + the Attributes data member. > > + @param[in,out] ProcedureArguments Allows the caller to pass a l= ist 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. > > + @param[in,out] Token This is parameter is broken i= nto two > > components: > > + 1.Token->Completion is an opt= ional parameter that > > allows the > > + caller to execute the procedu= re in a blocking or non- > > blocking > > + fashion. If it is NULL the ca= ll is blocking, and the call will > > + not return until the AP has c= ompleted the procedure. > If > > the > > + token is not NULL, the call w= ill return immediately. The > > caller > > + can check whether the procedu= re has completed with > > + CheckOnProcedure or WaitForPr= ocedure. > > + 2.Token->Status The implement= ation updates the > > address pointed > > + at by this variable with the = status code returned by > > Procedure > > + when it completes execution o= n the target AP, or with > > EFI_TIMEOUT > > + if the Procedure fails to com= plete within the optional > > timeout. > > + The implementation will updat= e this variable with > > EFI_NOT_READY > > + prior to starting Procedure o= n the target AP > > + @param[in,out] CPUStatus This optional pointer may be = used to > get > > the status code returned > > + by Procedure when it complete= s execution on the > > target AP, or with > > + EFI_TIMEOUT if the Procedure = fails to complete within > > the optional > > + timeout. The implementation w= ill update this variable > > with > > + EFI_NOT_READY prior to starti= ng Procedure on the > > target AP. > > + > > + @retval EFI_SUCCESS In the blocking case, this in= dicates that > > Procedure has completed > > + execution on the target AP. > > + In the non-blocking case this= indicates that the > > procedure has > > + been successfully scheduled f= or execution on the > target > > AP. > > + @retval EFI_INVALID_PARAMETER The input arguments are out o= f > > range. Either the target AP is the > > + caller of the function, or th= e Procedure or Token is > NULL > > + @retval EFI_NOT_READY If the target AP is busy exec= uting > another > > procedure > > + @retval EFI_ALREADY_STARTED Token is already in use for a= nother > > procedure > > + @retval EFI_TIMEOUT In blocking mode, the timeout= expired > > 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 OPTIONA= L, > > + 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 t= o > > support blocking and > > + nonblocking modes. If the token is passed into the call, the functi= on will > > operate in a non-blocking > > + fashion and the caller can check for completion with CheckOnProcedu= re > or > > WaitForProcedure. > > + > > + It is not necessary for the implementation to run the procedure on = every > > processor on the platform. > > + Processors that are powered down in such a way that they cannot > respond > > to interrupts, may be > > + excluded from the broadcast. > > + > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instan= ce. > > + @param[in] Procedure A pointer to the code stream = to be run > on > > the APs that have > > + entered MM. Type EFI_AP_PROCE= DURE is defined > > below in related > > + definitions. > > + @param[in] TimeoutInMicroseconds Indicates the time limit in > > microseconds for the APs to finish > > + execution of Procedure, eithe= r for blocking or non- > > blocking mode. > > + Zero means infinity. If the t= imeout expires before all > > APs return > > + from Procedure, then Procedur= e on the failed APs is > > terminated. If > > + the timeout expires in blocki= ng mode, the call returns > > EFI_TIMEOUT. > > + If the timeout expires in non= -blocking mode, the > > timeout determined > > + can be through CheckOnProcedu= re 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] ProcedureArguments Allows the caller to pass a l= ist 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. > > + @param[in,out] Token This is parameter is broken i= nto two > > components: > > + 1.Token->Completion is an opt= ional parameter that > > allows the > > + caller to execute the procedu= re in a blocking or non- > > blocking > > + fashion. If it is NULL the ca= ll is blocking, and the call will > > + not return until the AP has c= ompleted the procedure. > If > > the > > + token is not NULL, the call w= ill return immediately. The > > caller > > + can check whether the procedu= re has completed with > > + CheckOnProcedure or WaitForPr= ocedure. > > + 2.Token->Status The implement= ation updates the > > address pointed > > + at by this variable with the = status code returned by > > Procedure > > + when it completes execution o= n the target AP, or with > > EFI_TIMEOUT > > + if the Procedure fails to com= plete within the optional > > timeout. > > + The implementation will updat= e this variable with > > EFI_NOT_READY > > + prior to starting Procedure o= n the target AP > > + @param[in,out] CPUStatus This optional pointer may be = used to > get > > the individual status > > + returned by every AP that par= ticipated in the > broadcast. > > This > > + parameter if used provides th= e 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 t= he > > GetNumberOfProcessors function. > > + As mentioned above, the broad= cast may not include > > every processor > > + in the system. Some implement= ations may exclude > > processors that > > + have been powered down in suc= h a way that they are > > not responsive > > + to interrupts. Additionally t= he broadcast excludes the > > processor > > + which is making the Broadcast= Procedure call. For > every > > excluded > > + processor, the array entry mu= st contain a value of > > EFI_NOT_STARTED > > + > > + @retval EFI_SUCCESS In the blocking case, this in= dicates that > > Procedure has completed > > + execution on the APs. > > + In the non-blocking case this= indicates that the > > procedure has > > + been successfully scheduled f= or execution on the APs. > > + @retval EFI_INVALID_PARAMETER The Procedure or Token is NUL= L > > + @retval EFI_NOT_READY If the target AP is busy exec= uting > another > > procedure > > + @retval EFI_ALREADY_STARTED Token is already in use for a= nother > > procedure > > + @retval EFI_TIMEOUT In blocking mode, the timeout= expired > > 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 OPTIONA= L, > > + 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 th= e > > 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 > running > > in the operating system. > > + > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instanc= e. > > + @param[in] Procedure A pointer to the code stream t= o be run on > > the designated target AP > > + of the system. Type EFI_AP_PRO= CEDURE is defined > > below in Volume 2 > > + with the related definitions o= f > > + EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs. > > + If caller may pass a value of = NULL to deregister any > > existing > > + startup procedure. > > + @param[in,out] ProcedureArguments Allows the caller to pass a li= st of > > parameters to the code that is > > + run by the AP. It is an option= al common mailbox > > between APs and > > + the caller to share informatio= n > > + > > + @retval EFI_SUCCESS The Procedure has been set suc= cessfully. > > + @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 comp= letion > of > > the procedure on the AP. > > + The function takes the token that was passed into the > DispatchProcedure > > call. If the procedure > > + is complete, and therefore it is now possible to run another proced= ure > on > > the same AP, this function > > + returns EFI_SUCESS. In this case the status returned by the procedu= re > 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 o= f the > > procedure on all the > > + broadcast APs. The function takes the token that was passed into th= e > > BroadcastProcedure > > + call. If the procedure is complete on all broadcast APs this functi= on > returns > > EFI_SUCESS. In this > > + case the Status field in the token passed into the function reflect= s 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 > function > > returns > > + EFI_NOT_READY. > > + > > + @param[in] This The EFI_MM_MP_PROTOCOL instanc= e. > > + @param[in] Token This parameter describes the t= oken that > was > > passed into > > + DispatchProcedure or Broadcast= Procedure. > > + > > + @retval EFI_SUCCESS Procedure has completed. > > + @retval EFI_NOT_READY The Procedure has not complete= d. > > + @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 vi= a > > DispatchProcedure, > > + this function will block the caller until the remote procedure has > completed > > 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 vi= a > > BroadcastProcedure > > + this function will block the caller until the remote procedure has > completed > > 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 > broadcast > > 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 instanc= e. > > + @param[in] Token This parameter describes the t= oken that > was > > passed into > > + DispatchProcedure or Broadcast= Procedure. > > + > > + @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 > > > > > >=20