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; Tue, 25 Jun 2019 22:55:10 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Jun 2019 22:55:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,418,1557212400"; d="scan'208";a="163828858" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by fmsmga007.fm.intel.com with ESMTP; 25 Jun 2019 22:55:09 -0700 Received: from fmsmsx161.amr.corp.intel.com (10.18.125.9) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 25 Jun 2019 22:55:09 -0700 Received: from shsmsx108.ccr.corp.intel.com (10.239.4.97) by FMSMSX161.amr.corp.intel.com (10.18.125.9) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 25 Jun 2019 22:55:09 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.185]) by SHSMSX108.ccr.corp.intel.com ([169.254.8.236]) with mapi id 14.03.0439.000; Wed, 26 Jun 2019 13:55:07 +0800 From: "Ni, Ray" To: "Dong, Eric" , "devel@edk2.groups.io" CC: Laszlo Ersek Subject: Re: [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Topic: [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Thread-Index: AQHVJmMMNIVFt1hkiU2B/IY00hx10qatUuwQ Date: Wed, 26 Jun 2019 05:55:06 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C1F0E85@SHSMSX104.ccr.corp.intel.com> References: <20190619055114.12744-1-eric.dong@intel.com> <20190619055114.12744-3-eric.dong@intel.com> In-Reply-To: <20190619055114.12744-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 > -----Original Message----- > From: Dong, Eric > Sent: Wednesday, June 19, 2019 1:51 PM > To: devel@edk2.groups.io > Cc: Ni, Ray ; Laszlo Ersek > Subject: [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP > Protocol. >=20 > Add MM Mp Protocol in PiSmmCpuDxeSmm driver. >=20 > Cc: Ray Ni > Cc: Laszlo Ersek > Signed-off-by: Eric Dong > --- > UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.c | 375 +++++++++++++++ > UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.h | 283 +++++++++++ > UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 468 > ++++++++++++++++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 11 + > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 172 ++++++- > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 + > 6 files changed, 1296 insertions(+), 16 deletions(-) > create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.c > create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.h >=20 > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.c > b/UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.c > new file mode 100644 > index 0000000000..8cf69428c2 > --- /dev/null > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpProtocol.c > @@ -0,0 +1,375 @@ > +/** @file > +SMM MP protocol implementation > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "PiSmmCpuDxeSmm.h" > +#include "MpProtocol.h" > + > +/// > +/// SMM MP Protocol instance > +/// > +EFI_SMM_MP_PROTOCOL mSmmMp =3D { > + EFI_SMM_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_SMM_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 > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpDispatchProcedure ( > + IN CONST EFI_SMM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN CpuNumber, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT SMM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ) > +{ 1. SPIN_LOCK *Lock; > + if (Token !=3D NULL) { > + *Token =3D AllocatePool (sizeof (SPIN_LOCK)); Lock =3D AllocatePool (...); > + ASSERT (*Token !=3D NULL);=20 If (Lock =3D=3D NULL) { Return EFI_DEVICE_ERROR; } > + InitializeSpinLock ((SPIN_LOCK *)(*Token)); InitializeSpinLock (Lock); > + *Token =3D Lock; > + return InternalSmmStartupThisAp( > + Procedure, > + CpuNumber, > + ProcedureArguments, > + SmmCpuCallInNewType, > + (SPIN_LOCK *)(*Token), (Token !=3D NULL) ? Lock : NULL The two InternalSmmStartupThisAp() can be combined to one call. > + TimeoutInMicroseconds, > + CPUStatus > + ); > + } > + > + return InternalSmmStartupThisAp( > + Procedure, > + CpuNumber, > + ProcedureArguments, > + SmmCpuCallInNewType, > + 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. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmMpBroadcastProcedure ( > + IN CONST EFI_SMM_MP_PROTOCOL *This, > + IN EFI_AP_PROCEDURE2 Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN OUT VOID *ProcedureArguments OPTIONAL, > + IN OUT SMM_COMPLETION *Token, > + IN OUT EFI_STATUS *CPUStatus > + ) > +{ > + if (Token !=3D NULL) { > + *Token =3D AllocatePool (sizeof (SPIN_LOCK)); > + ASSERT (*Token !=3D NULL); > + InitializeSpinLock ((SPIN_LOCK *) (*Token)); > + > + return InternalSmmStartupAllAPs( > + Procedure, > + TimeoutInMicroseconds, > + ProcedureArguments, > + (SPIN_LOCK *) (*Token), > + CPUStatus > + ); > + } 2. Similar comments. > + > + return InternalSmmStartupAllAPs( > + Procedure, > + TimeoutInMicroseconds, > + ProcedureArguments, > + 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_SMM_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_SMM_MP_PROTOCOL *This, > + IN SMM_COMPLETION Token > + ) > +{ > + if (Token =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!CurrentUsedToken ((SPIN_LOCK *)Token)) { 3. CurrentUsedToken --> IsCurrentToken()? > + return EFI_NOT_FOUND; > + } > + > + return CheckStatusForThisAP ((SPIN_LOCK *)Token); 4. return IsApReady(Token) ? EFI_SUCCESS : EFI_NOT_READY; > +} > + > +/** > + 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_SMM_MP_PROTOCOL *This, > + IN SMM_COMPLETION Token > + ) > +{ > + EFI_STATUS Status; > + > + do { > + Status =3D SmmMpCheckForProcedure (This, Token); > + } while (Status =3D=3D EFI_NOT_READY); 5. Use IsApReady()? > + > + return Status; > +} > + 6. The file name can be SmmMp.c/h? > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > index 64fb4d6344..6b08dc0c4e 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c > @@ -146,6 +146,56 @@ ReleaseAllAPs ( > } > } >=20 > +/** > + Wheck whether task has been finished by all APs. > + > + @retval TRUE Task has been finished by all APs. > + @retval FALSE Task not has been finished by all APs. > + > +**/ > +BOOLEAN > +TaskFinishInAllAPs ( > + VOID > + ) > +{ > + UINTN Index; > + UINTN BspIndex; > + > + BspIndex =3D mSmmMpSyncData->BspIndex; > + > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D BspIndex && *(mSmmMpSyncData->CpuData[Index].Present) > && !mSmmMpSyncData->FinishTask[Index]) { > + return FALSE; > + } > + } > + > + return TRUE; > +} > + > +/** > + Checks whenther executive procedure in sync mode. > + > + @param[in] CallInType Which call for this function= . > + @param[in] Token Token input by caller. > + > + > + @retval TRUE Executive procedure in sync mode. > + @retval FALSE Executive procedure not in sync mode. > + > +**/ > +BOOLEAN > +ExecutiveInSyncMode ( > + IN SMM_CPU_CALL_IN_TYPE CallInType, > + IN SPIN_LOCK *Token > + ) > +{ > + if (CallInType =3D=3D SmmCpuCallInOldSyncType) { > + return TRUE; > + } > + > + return Token =3D=3D NULL; > +} > + > /** > Checks if all CPUs (with certain exceptions) have checked in for this = SMI run >=20 > @@ -347,6 +397,30 @@ ReplaceOSMtrrs ( > MtrrSetAllMtrrs (&gSmiMtrrs); > } >=20 > +/** > + Clear the flags used for execute one procedure. > + > + @param BlockStyle Is this procedure block style or non-bloc= k. > + @param SingleProcessor Is this procedure only for single process= or. > + > +**/ > +VOID > +ClearProcedureFlags ( > + IN BOOLEAN BlockStyle, > + IN BOOLEAN SingleProcessor > + ) > +{ > + mSmmMpSyncData->CpuCheckMode =3D SmmCpuCheckModeMax; > + > + if (SingleProcessor) { > + mSmmMpSyncData->CpuIndex =3D (UINTN) -1; > + } > + > + if (!BlockStyle) { > + ReleaseSpinLock (mSmmMpSyncData->CurrentToken); > + } > +} > + > /** > SMI handler for BSP. >=20 > @@ -604,6 +678,7 @@ APHandler ( > UINT64 Timer; > UINTN BspIndex; > MTRR_SETTINGS Mtrrs; > + EFI_STATUS ProcedureStatus; >=20 > // > // Timeout BSP > @@ -730,14 +805,43 @@ 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->CurrentToken !=3D NULL) { > + if (mSmmMpSyncData->CpuCheckMode =3D=3D SmmCpuCheckModeSingle) > { > + if (mSmmMpSyncData->CpuStatus !=3D NULL) { > + *mSmmMpSyncData->CpuStatus =3D ProcedureStatus; > + } > + } else { > + ASSERT (mSmmMpSyncData->CpuCheckMode =3D=3D > SmmCpuCheckModeAll); > + if (mSmmMpSyncData->CpuStatus !=3D NULL) { > + mSmmMpSyncData->CpuStatus[CpuIndex] =3D ProcedureStatus; > + } > + } > + } >=20 > // > // Release BUSY > // > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > + > + // > + // In non-block mode, Update the sync flags (CpuCheckMode, CpuIndex, > FinishTask, CurrentToken) here. > + // > + if (mSmmMpSyncData->CurrentToken !=3D NULL) { > + if (mSmmMpSyncData->CpuCheckMode =3D=3D SmmCpuCheckModeSingle) > { > + if (mSmmMpSyncData->CpuIndex =3D=3D CpuIndex) { > + ClearProcedureFlags (FALSE, TRUE); > + } > + } else if (mSmmMpSyncData->CpuCheckMode =3D=3D > SmmCpuCheckModeAll) { > + mSmmMpSyncData->FinishTask[CpuIndex] =3D TRUE; 7. Can FinishTask be eliminated by just using mSmmMpSyncData->CpuData[CpuIn= dex].Busy? > + if (TaskFinishInAllAPs()) { > + ClearProcedureFlags (FALSE, FALSE); > + } > + } > + } > } >=20 > if (SmmCpuFeaturesNeedConfigureMtrrs()) { > @@ -906,13 +1010,82 @@ 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 > +CurrentUsedToken ( > + IN SPIN_LOCK *Token > + ) > +{ > + return mSmmMpSyncData->CurrentToken =3D=3D Token; > +} > + > +/** > + Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task > assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] Token This parameter describes the token that = was > passed into DispatchProcedure or > + BroadcastProcedure. > + > + @retval EFI_SUCCESS Specified AP has finished task assigned = by > StartupThisAPs(). > + @retval EFI_NOT_READY Specified AP has not finished task and > timeout has not expired. > +**/ > +EFI_STATUS > +CheckStatusForThisAP ( > + 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] CallInType Which call for this function= . > + @param[in, out] Token This is parameter is broken = into two > components: > + 1.Token->Completion is an op= tional parameter that > allows the > + caller to execute the proced= ure in a blocking or non- > blocking > + fashion. If it is NULL the c= all 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 proced= ure has completed with > + CheckOnProcedure or WaitForP= rocedure. > + 2.Token->Status The implemen= tation updates the > address pointed > + at by this variable with the= status code returned by > Procedure > + when it completes execution = on the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to co= mplete within the optional > timeout. > + The implementation will upda= te this variable with > EFI_NOT_READY > + prior to starting Procedure = on the target AP > + @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. > + >=20 > @retval EFI_INVALID_PARAMETER CpuNumber not valid > @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP > @@ -923,10 +1096,13 @@ Gen4GPageTable ( > **/ > EFI_STATUS > InternalSmmStartupThisAp ( > - IN EFI_AP_PROCEDURE Procedure, > - IN UINTN CpuIndex, > - IN OUT VOID *ProcArguments OPTIONAL, > - IN BOOLEAN BlockingMode > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN CpuIndex, > + IN OUT VOID *ProcArguments OPTIONAL, > + IN SMM_CPU_CALL_IN_TYPE CallInType, > + IN SPIN_LOCK *Token, > + IN UINTN TimeoutInMicroseconds, > + IN EFI_STATUS *CpuStatus > ) > { > if (CpuIndex >=3D gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) > { > @@ -952,27 +1128,231 @@ InternalSmmStartupThisAp ( > } > return EFI_INVALID_PARAMETER; > } > + if ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & > EFI_SMM_MP_TIMEOUT_SUPPORTED) =3D=3D 0)) { > + DEBUG((DEBUG_ERROR, "Input TimeoutInMicroseconds !=3D 0 but > EFI_SMM_MP_TIMEOUT_SUPPORTED not supported!\n")); > + return EFI_INVALID_PARAMETER; 8. Is mSmmMp.Attributes changed at runtime? If it's a constant value, can the code directly reject non-zero TimeoutInMicroseconds? > + } > + if (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (Token !=3D NULL && Token =3D=3D mSmmMpSyncData->CurrentToken) { 9. Can IsCurrentToken() be used? > + return EFI_ALREADY_STARTED; > + } > + if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) 10. In old style blocking mode, consumer expects code is waiting here. It m= ight cause backward compatibility issue here. > { > + return EFI_NOT_READY; > + } else { > + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > + } >=20 > - if (BlockingMode) { > + if (ExecutiveInSyncMode (CallInType, Token)) { 11. Can we simplify the CallInType? SmmCpuCallInOldSyncType is the same as = when Token equals to NULL, right? SmmCpuCallInOldAsyncType is assigned but I cannot find code that checks thi= s type. So please think about if this type can be eliminated or replaced with a BOO= LEAN flag. > AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > } else { > + if (Token !=3D NULL && !AcquireSpinLockOrFail (Token)) { > + DEBUG((DEBUG_ERROR, "Token->Completion can't acquire\n")); > + return EFI_INVALID_PARAMETER; > + } > if (!AcquireSpinLockOrFail (mSmmMpSyncData- > >CpuData[CpuIndex].Busy)) { > DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", > CpuIndex)); > - return EFI_INVALID_PARAMETER; > + ReleaseSpinLock (Token); > + return EFI_NOT_READY; > } > } >=20 > - mSmmMpSyncData->CpuData[CpuIndex].Procedure =3D Procedure; > + // > + // PI spec requirement in EFI_MM_MP_PROTOCOL.DispatchProcedure(): > + // The implementation will update this variable with > + // EFI_NOT_READY prior to starting Procedure on the target AP. > + // > + mSmmMpSyncData->CurrentToken =3D Token; > + mSmmMpSyncData->CpuCheckMode =3D SmmCpuCheckModeSingle; > + mSmmMpSyncData->CpuIndex =3D CpuIndex; 12. Can CpuCheckMode be eliminated since mSmmMpSyncData->CpuIndex=20 having value other (-1) indicates it's a StartupThisAp call. Above code in ApHandler() can just check mSmmMpSyncData->CpuIndex instead of checking mSmmMpSyncData->CpuCheckMode. > + mSmmMpSyncData->CpuStatus =3D CpuStatus; > + if (mSmmMpSyncData->CpuStatus !=3D NULL) { > + *mSmmMpSyncData->CpuStatus =3D EFI_NOT_READY; > + } > + > + mSmmMpSyncData->CpuData[CpuIndex].Procedure =3D > (EFI_AP_PROCEDURE2) Procedure; > mSmmMpSyncData->CpuData[CpuIndex].Parameter =3D ProcArguments; > + > ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run); >=20 > - if (BlockingMode) { > + if (ExecutiveInSyncMode (CallInType, Token)) { > AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); > + > + // > + // In block mode, update the sync flags (CpuCheckMode, CpuIndex, > FinishTask, CurrentToken) here. > + // > + if (Token =3D=3D NULL) { > + ClearProcedureFlags (TRUE, TRUE); > + } > + } > + > + 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 ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @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 (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & > EFI_SMM_MP_TIMEOUT_SUPPORTED) =3D=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + if (Token !=3D NULL && Token =3D=3D mSmmMpSyncData->CurrentToken) { > + 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, "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; > + } > + } > + } > + } > + > + // > + // PI spec requirement: > + // The implementation will update this variable with > + // EFI_NOT_READY prior to starting Procedure on the target AP. > + // > + mSmmMpSyncData->CurrentToken =3D Token; > + mSmmMpSyncData->CpuCheckMode =3D SmmCpuCheckModeAll; > + mSmmMpSyncData->CpuStatus =3D CPUStatus; 12. Similar comments as above. mSmmMpSyncData->CpuIndex can be assigned to = -1 indicating it's a StartupALLAP call. > + > + 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; > + } else { > + // > + // PI spec requirement: > + // For every excluded processor, the array entry must contain a va= lue of > EFI_NOT_STARTED. > + // > + if (mSmmMpSyncData->CpuStatus !=3D NULL) { > + mSmmMpSyncData->CpuStatus[Index] =3D EFI_NOT_STARTED; > + } > + } > + // > + // Clear all status no matter this processor is used or not. > + // May not need to clear all but add it to make the status clear. > + // > + mSmmMpSyncData->FinishTask[Index] =3D FALSE; > } > + > + ReleaseAllAPs (); > + > + if (Token =3D=3D NULL) { > + // > + // Make sure all APs have completed their tasks. > + // > + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { > + if (Index !=3D gSmmCpuPrivate- > >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData- > >CpuData[Index].Present)) { > + AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy); > + } > + } > + > + // > + // Update the sync flags (CpuCheckMode, CpuIndex, FinishTask, > CurrentToken) in block mode here. > + // > + ClearProcedureFlags (TRUE, FALSE); > + } > + > return EFI_SUCCESS; > } >=20 > + > /** > Schedule a procedure to run on the specified CPU in blocking mode. >=20 > @@ -995,7 +1375,7 @@ SmmBlockingStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > TRUE); > + return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > SmmCpuCallInOldSyncType, NULL, 0, NULL); > } >=20 > /** > @@ -1020,7 +1400,15 @@ SmmStartupThisAp ( > IN OUT VOID *ProcArguments OPTIONAL > ) > { > - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)); > + SMM_CPU_CALL_IN_TYPE CallInType; > + > + if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) { > + CallInType =3D SmmCpuCallInOldSyncType; > + } else { > + CallInType =3D SmmCpuCallInOldAsyncType; > + } > + > + return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, > CallInType, NULL, 0, NULL); > } >=20 > /** > @@ -1112,6 +1500,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 > // > @@ -1332,6 +1727,7 @@ InitializeMpSyncData ( > ZeroMem (mSmmMpSyncData, mSmmMpSyncDataSize); > mSmmMpSyncData->CpuData =3D (SMM_CPU_DATA_BLOCK *)((UINT8 > *)mSmmMpSyncData + sizeof (SMM_DISPATCHER_MP_SYNC_DATA)); > mSmmMpSyncData->CandidateBsp =3D (BOOLEAN *)(mSmmMpSyncData- > >CpuData + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); > + mSmmMpSyncData->FinishTask =3D (BOOLEAN *)(mSmmMpSyncData- > >CandidateBsp + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); > if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { > // > // Enable BSP election by setting BspIndex to -1 > @@ -1360,6 +1756,10 @@ InitializeMpSyncData ( > *(mSmmMpSyncData->CpuData[CpuIndex].Run) =3D 0; > *(mSmmMpSyncData->CpuData[CpuIndex].Present) =3D FALSE; > } > + > + mSmmMpSyncData->CpuCheckMode =3D SmmCpuCheckModeMax; > + mSmmMpSyncData->CpuIndex =3D CpuIndex; > + mSmmMpSyncData->CurrentToken =3D NULL; > } > } >=20 > @@ -1399,7 +1799,7 @@ InitializeMpServiceData ( > // Initialize mSmmMpSyncData > // > mSmmMpSyncDataSize =3D sizeof (SMM_DISPATCHER_MP_SYNC_DATA) + > - (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN)) = * > gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; > + (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN) += sizeof > (BOOLEAN)) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; > mSmmMpSyncData =3D (SMM_DISPATCHER_MP_SYNC_DATA*) > AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize)); > ASSERT (mSmmMpSyncData !=3D NULL); > mCpuSmmSyncMode =3D (SMM_CPU_SYNC_MODE)PcdGet8 > (PcdCpuSmmSyncMode); > @@ -1469,3 +1869,41 @@ 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,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 > + ) > +{ > + 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..e498f72801 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c > @@ -996,6 +996,17 @@ PiCpuSmmEntry ( > ); > ASSERT_EFI_ERROR (Status); >=20 > + // > + // Install the SMM Mp Protocol into SMM protocol database > + // > + Status =3D gSmst->SmmInstallProtocolInterface ( > + &mSmmCpuHandle, > + &gEfiSmmMpProtocolGuid, > + 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..b321ff15ee 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 > @@ -226,6 +227,7 @@ extern CPU_HOT_PLUG_DATA mCpuHotPlugData; > extern UINTN mMaxNumberOfCpus; > extern UINTN mNumberOfCpus; > extern EFI_SMM_CPU_PROTOCOL mSmmCpu; > +extern EFI_SMM_MP_PROTOCOL mSmmMp; >=20 > /// > /// The mode of the CPU at the time an SMI occurs > @@ -363,7 +365,7 @@ 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; > @@ -375,6 +377,19 @@ typedef enum { > SmmCpuSyncModeMax > } SMM_CPU_SYNC_MODE; >=20 > +typedef enum { > + SmmCpuCheckModeSingle, > + SmmCpuCheckModeAll, > + SmmCpuCheckModeMax > +} SMM_CPU_CHECK_MODE; > + > +typedef enum { > + SmmCpuCallInOldSyncType, > + SmmCpuCallInOldAsyncType, > + SmmCpuCallInNewType, > + SmmCpuCallInTypeMax > +} SMM_CPU_CALL_IN_TYPE; > + > typedef struct { > // > // Pointer to an array. The array should be located immediately after = this > structure > @@ -388,6 +403,14 @@ typedef struct { > volatile SMM_CPU_SYNC_MODE EffectiveSyncMode; > volatile BOOLEAN SwitchBsp; > volatile BOOLEAN *CandidateBsp; > + SPIN_LOCK *CurrentToken; > + SMM_CPU_CHECK_MODE CpuCheckMode; > + UINTN CpuIndex; > + EFI_STATUS *CpuStatus; > + volatile BOOLEAN *FinishTask; > + > + EFI_AP_PROCEDURE StartupProcedure; > + VOID *StartupProcArgs; > } SMM_DISPATCHER_MP_SYNC_DATA; >=20 > #define SMM_PSD_OFFSET 0xfb00 > @@ -1259,4 +1282,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] CallInType Which call for this function= . > + @param[in, out] Token This is parameter is broken = into two > components: > + 1.Token->Completion is an op= tional parameter that > allows the > + caller to execute the proced= ure in a blocking or non- > blocking > + fashion. If it is NULL the c= all 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 proced= ure has completed with > + CheckOnProcedure or WaitForP= rocedure. > + 2.Token->Status The implemen= tation updates the > address pointed > + at by this variable with the= status code returned by > Procedure > + when it completes execution = on the target AP, or with > EFI_TIMEOUT > + if the Procedure fails to co= mplete within the optional > timeout. > + The implementation will upda= te this variable with > EFI_NOT_READY > + prior to starting Procedure = on the target AP > + @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. > + > + > + @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_PROCEDURE Procedure, > + IN UINTN CpuIndex, > + IN OUT VOID *ProcArguments OPTIONAL, > + IN SMM_CPU_CALL_IN_TYPE CallInType, > + IN SPIN_LOCK *Token, > + IN UINTN TimeoutInMicroseconds, > + IN 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 > +CurrentUsedToken ( > + 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 > +CheckStatusForThisAP ( > + 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 ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @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 > + ); > + > #endif > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > index 466c568d49..f478ae62a7 100644 > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf > @@ -40,6 +40,8 @@ > SmmProfileInternal.h > SmramSaveState.c > SmmCpuMemoryManagement.c > + MpProtocol.h > + MpProtocol.c >=20 > [Sources.Ia32] > Ia32/Semaphore.c > @@ -105,6 +107,7 @@ > gEfiSmmReadyToLockProtocolGuid ## NOTIFY > gEfiSmmCpuServiceProtocolGuid ## PRODUCES > gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES > + gEfiSmmMpProtocolGuid ## PRODUCES >=20 > [Guids] > gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB = # it is > used for S3 boot. > -- > 2.21.0.windows.1