From: "Ni, Ray" <ray.ni@intel.com>
To: "Dong, Eric" <eric.dong@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Laszlo Ersek <lersek@redhat.com>
Subject: Re: [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol.
Date: Wed, 26 Jun 2019 05:55:06 +0000 [thread overview]
Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C1F0E85@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <20190619055114.12744-3-eric.dong@intel.com>
> -----Original Message-----
> From: Dong, Eric <eric.dong@intel.com>
> Sent: Wednesday, June 19, 2019 1:51 PM
> To: devel@edk2.groups.io
> Cc: Ni, Ray <ray.ni@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP
> Protocol.
>
> Add MM Mp Protocol in PiSmmCpuDxeSmm driver.
>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Eric Dong <eric.dong@intel.com>
> ---
> 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
>
> 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.<BR>
> +
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PiSmmCpuDxeSmm.h"
> +#include "MpProtocol.h"
> +
> +///
> +/// SMM MP Protocol instance
> +///
> +EFI_SMM_MP_PROTOCOL mSmmMp = {
> + 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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + *NumberOfProcessors = gSmmCpuPrivate-
> >SmmCoreEntryContext.NumberOfCpus;
> +
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + This service allows the caller to invoke a procedure one of the application
> processors (AP). This
> + function uses an optional token parameter to support blocking and non-
> blocking modes. If the token
> + is passed into the call, the function will operate in a non-blocking fashion
> and the caller can
> + check for completion with CheckOnProcedure or WaitForProcedure.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the procedure to 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 processor
> number of the target
> + AP, on which the code stream is supposed to run. If the
> number
> + points to the calling processor then it will not run the
> + supplied code.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for this AP to
> + finish execution of Procedure, either for blocking or
> + non-blocking mode. Zero means infinity. If the timeout
> + expires before this AP returns from Procedure, then
> Procedure
> + on the AP is terminated. If the timeout expires in
> blocking
> + mode, the call returns EFI_TIMEOUT. If the timeout
> expires
> + in non-blocking mode, the timeout determined can be
> through
> + CheckOnProcedure 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 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.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation 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 complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the status code returned
> + by Procedure when it completes 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 starting Procedure on the
> target AP.
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the target AP.
> + In the non-blocking case this indicates that the
> procedure has
> + been successfully scheduled for execution on the target
> AP.
> + @retval EFI_INVALID_PARAMETER The input arguments are out of
> range. Either the target AP is the
> + caller of the function, or the Procedure or Token is NULL
> + @retval EFI_NOT_READY If the target AP is busy executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> 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 != NULL) {
> + *Token = AllocatePool (sizeof (SPIN_LOCK));
Lock = AllocatePool (...);
> + ASSERT (*Token != NULL);
If (Lock == NULL) {
Return EFI_DEVICE_ERROR;
}
> + InitializeSpinLock ((SPIN_LOCK *)(*Token));
InitializeSpinLock (Lock);
> +
*Token = Lock;
> + return InternalSmmStartupThisAp(
> + Procedure,
> + CpuNumber,
> + ProcedureArguments,
> + SmmCpuCallInNewType,
> + (SPIN_LOCK *)(*Token),
(Token != 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 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 instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the APs that have
> + entered MM. Type EFI_AP_PROCEDURE is defined
> below in related
> + definitions.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for the APs to finish
> + execution of Procedure, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure 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 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.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation 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 complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the individual status
> + returned by every AP that participated in the broadcast.
> This
> + parameter if used provides the base address of an array
> to hold
> + the EFI_STATUS value of each AP in the system. The size
> of the
> + array can be ascertained by the
> GetNumberOfProcessors function.
> + As mentioned above, the broadcast may not include
> every processor
> + in the system. Some implementations 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 BroadcastProcedure call. For every
> excluded
> + processor, the array entry must contain a value of
> EFI_NOT_STARTED
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the APs.
> + In the non-blocking case this indicates 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 executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> 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 != NULL) {
> + *Token = AllocatePool (sizeof (SPIN_LOCK));
> + ASSERT (*Token != 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 running
> in the operating system.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL 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 successfully.
> + @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 completion 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 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 the
> procedure on all the
> + broadcast APs. The function takes the token that was passed into the
> BroadcastProcedure
> + call. If the procedure is complete on all broadcast APs this function returns
> EFI_SUCESS. In this
> + case the Status field in the token passed into the function reflects the
> overall result of the
> + invocation, which may be EFI_SUCCESS, if all executions succeeded, or the
> first observed failure.
> + If the procedure has not yet completed on the broadcast APs, the function
> returns
> + EFI_NOT_READY.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @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 == 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 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 via
> 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 instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @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 = SmmMpCheckForProcedure (This, Token);
> + } while (Status == 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 (
> }
> }
>
> +/**
> + 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 = mSmmMpSyncData->BspIndex;
> +
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (Index != 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 == SmmCpuCallInOldSyncType) {
> + return TRUE;
> + }
> +
> + return Token == NULL;
> +}
> +
> /**
> Checks if all CPUs (with certain exceptions) have checked in for this SMI run
>
> @@ -347,6 +397,30 @@ ReplaceOSMtrrs (
> MtrrSetAllMtrrs (&gSmiMtrrs);
> }
>
> +/**
> + Clear the flags used for execute one procedure.
> +
> + @param BlockStyle Is this procedure block style or non-block.
> + @param SingleProcessor Is this procedure only for single processor.
> +
> +**/
> +VOID
> +ClearProcedureFlags (
> + IN BOOLEAN BlockStyle,
> + IN BOOLEAN SingleProcessor
> + )
> +{
> + mSmmMpSyncData->CpuCheckMode = SmmCpuCheckModeMax;
> +
> + if (SingleProcessor) {
> + mSmmMpSyncData->CpuIndex = (UINTN) -1;
> + }
> +
> + if (!BlockStyle) {
> + ReleaseSpinLock (mSmmMpSyncData->CurrentToken);
> + }
> +}
> +
> /**
> SMI handler for BSP.
>
> @@ -604,6 +678,7 @@ APHandler (
> UINT64 Timer;
> UINTN BspIndex;
> MTRR_SETTINGS Mtrrs;
> + EFI_STATUS ProcedureStatus;
>
> //
> // Timeout BSP
> @@ -730,14 +805,43 @@ APHandler (
> //
> // Invoke the scheduled procedure
> //
> - (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
> - (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
> - );
> + ProcedureStatus = (*mSmmMpSyncData-
> >CpuData[CpuIndex].Procedure) (
> + (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
> + );
> +
> + if (mSmmMpSyncData->CurrentToken != NULL) {
> + if (mSmmMpSyncData->CpuCheckMode == SmmCpuCheckModeSingle)
> {
> + if (mSmmMpSyncData->CpuStatus != NULL) {
> + *mSmmMpSyncData->CpuStatus = ProcedureStatus;
> + }
> + } else {
> + ASSERT (mSmmMpSyncData->CpuCheckMode ==
> SmmCpuCheckModeAll);
> + if (mSmmMpSyncData->CpuStatus != NULL) {
> + mSmmMpSyncData->CpuStatus[CpuIndex] = ProcedureStatus;
> + }
> + }
> + }
>
> //
> // Release BUSY
> //
> ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> +
> + //
> + // In non-block mode, Update the sync flags (CpuCheckMode, CpuIndex,
> FinishTask, CurrentToken) here.
> + //
> + if (mSmmMpSyncData->CurrentToken != NULL) {
> + if (mSmmMpSyncData->CpuCheckMode == SmmCpuCheckModeSingle)
> {
> + if (mSmmMpSyncData->CpuIndex == CpuIndex) {
> + ClearProcedureFlags (FALSE, TRUE);
> + }
> + } else if (mSmmMpSyncData->CpuCheckMode ==
> SmmCpuCheckModeAll) {
> + mSmmMpSyncData->FinishTask[CpuIndex] = TRUE;
7. Can FinishTask be eliminated by just using mSmmMpSyncData->CpuData[CpuIndex].Busy?
> + if (TaskFinishInAllAPs()) {
> + ClearProcedureFlags (FALSE, FALSE);
> + }
> + }
> + }
> }
>
> if (SmmCpuFeaturesNeedConfigureMtrrs()) {
> @@ -906,13 +1010,82 @@ Gen4GPageTable (
> return (UINT32)(UINTN)PageTable;
> }
>
> +/**
> + Checks whether the input token is the current used token.
> +
> +
> + @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 token.
> +**/
> +BOOLEAN
> +CurrentUsedToken (
> + IN SPIN_LOCK *Token
> + )
> +{
> + return mSmmMpSyncData->CurrentToken == 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.
>
> @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 optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure.
> If the
> + token is not NULL, the call will return immediately.
> The caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation 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 complete within the optional
> timeout.
> + The implementation will update 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, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure 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
> @@ -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 >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)
> {
> @@ -952,27 +1128,231 @@ InternalSmmStartupThisAp (
> }
> return EFI_INVALID_PARAMETER;
> }
> + if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes &
> EFI_SMM_MP_TIMEOUT_SUPPORTED) == 0)) {
> + DEBUG((DEBUG_ERROR, "Input TimeoutInMicroseconds != 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 == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (Token != NULL && Token == 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 might cause backward compatibility issue here.
> {
> + return EFI_NOT_READY;
> + } else {
> + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> + }
>
> - 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 this type.
So please think about if this type can be eliminated or replaced with a BOOLEAN flag.
> AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> } else {
> + if (Token != 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;
> }
> }
>
> - mSmmMpSyncData->CpuData[CpuIndex].Procedure = 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 = Token;
> + mSmmMpSyncData->CpuCheckMode = SmmCpuCheckModeSingle;
> + mSmmMpSyncData->CpuIndex = CpuIndex;
12. Can CpuCheckMode be eliminated since mSmmMpSyncData->CpuIndex
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 = CpuStatus;
> + if (mSmmMpSyncData->CpuStatus != NULL) {
> + *mSmmMpSyncData->CpuStatus = EFI_NOT_READY;
> + }
> +
> + mSmmMpSyncData->CpuData[CpuIndex].Procedure =
> (EFI_AP_PROCEDURE2) Procedure;
> mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
> +
> ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
>
> - 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 == NULL) {
> + ClearProcedureFlags (TRUE, TRUE);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Worker function to execute a caller provided function on all enabled APs.
> +
> + @param[in] Procedure A pointer to the function to be run on
> + enabled APs of the system.
> + @param[in] SingleThread If TRUE, then all the enabled APs execute
> + the function specified by Procedure one by
> + one, in ascending order of processor handle
> + number. If FALSE, then all the enabled APs
> + execute the function specified by Procedure
> + simultaneously.
> + @param[in] WaitEvent The event created by the caller with
> CreateEvent()
> + service.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for
> + APs to return from Procedure, either 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, then its
> + content is set to NULL. If not all APs
> + finish before timeout expires, then its
> + content is set to address of the buffer
> + holding handle numbers of the failed APs.
> +
> + @retval EFI_SUCCESS In blocking mode, all APs have finished 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 (Procedure == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes &
> EFI_SMM_MP_TIMEOUT_SUPPORTED) == 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (Token != NULL && Token == mSmmMpSyncData->CurrentToken) {
> + return EFI_ALREADY_STARTED;
> + }
> +
> + CpuCount = 0;
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (*mSmmMpSyncData->CpuData[Index].Present && (Index !=
> gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu)) {
> + CpuCount ++;
> +
> + if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) {
> + return EFI_NOT_READY;
> + }
> + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
> + }
> + }
> + if (CpuCount == 0) {
> + return EFI_NOT_STARTED;
> + }
> +
> + if (Token == NULL) {
> + //
> + // Make sure all BUSY should be acquired.
> + //
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (Index != 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 = mMaxNumberOfCpus; Index-- > 0;) {
> + if (Index != 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 = mMaxNumberOfCpus; CpuCount -- > Index;) {
> + if (CpuCount != 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 = Token;
> + mSmmMpSyncData->CpuCheckMode = SmmCpuCheckModeAll;
> + mSmmMpSyncData->CpuStatus = CPUStatus;
12. Similar comments as above. mSmmMpSyncData->CpuIndex can be assigned to -1 indicating
it's a StartupALLAP call.
> +
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (Index != gSmmCpuPrivate-
> >SmmCoreEntryContext.CurrentlyExecutingCpu && *(mSmmMpSyncData-
> >CpuData[Index].Present)) {
> + mSmmMpSyncData->CpuData[Index].Procedure =
> (EFI_AP_PROCEDURE2) Procedure;
> + mSmmMpSyncData->CpuData[Index].Parameter =
> ProcedureArguments;
> + } else {
> + //
> + // PI spec requirement:
> + // For every excluded processor, the array entry must contain a value of
> EFI_NOT_STARTED.
> + //
> + if (mSmmMpSyncData->CpuStatus != NULL) {
> + mSmmMpSyncData->CpuStatus[Index] = 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] = FALSE;
> }
> +
> + ReleaseAllAPs ();
> +
> + if (Token == NULL) {
> + //
> + // Make sure all APs have completed their tasks.
> + //
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (Index != 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;
> }
>
> +
> /**
> Schedule a procedure to run on the specified CPU in blocking mode.
>
> @@ -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);
> }
>
> /**
> @@ -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 = SmmCpuCallInOldSyncType;
> + } else {
> + CallInType = SmmCpuCallInOldAsyncType;
> + }
> +
> + return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments,
> CallInType, NULL, 0, NULL);
> }
>
> /**
> @@ -1112,6 +1500,13 @@ SmiRendezvous (
> Cr2 = 0;
> SaveCr2 (&Cr2);
>
> + //
> + // Call the user register Startup function first.
> + //
> + if (mSmmMpSyncData->StartupProcedure != NULL) {
> + mSmmMpSyncData->StartupProcedure (mSmmMpSyncData-
> >StartupProcArgs);
> + }
> +
> //
> // Perform CPU specific entry hooks
> //
> @@ -1332,6 +1727,7 @@ InitializeMpSyncData (
> ZeroMem (mSmmMpSyncData, mSmmMpSyncDataSize);
> mSmmMpSyncData->CpuData = (SMM_CPU_DATA_BLOCK *)((UINT8
> *)mSmmMpSyncData + sizeof (SMM_DISPATCHER_MP_SYNC_DATA));
> mSmmMpSyncData->CandidateBsp = (BOOLEAN *)(mSmmMpSyncData-
> >CpuData + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
> + mSmmMpSyncData->FinishTask = (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) = 0;
> *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;
> }
> +
> + mSmmMpSyncData->CpuCheckMode = SmmCpuCheckModeMax;
> + mSmmMpSyncData->CpuIndex = CpuIndex;
> + mSmmMpSyncData->CurrentToken = NULL;
> }
> }
>
> @@ -1399,7 +1799,7 @@ InitializeMpServiceData (
> // Initialize mSmmMpSyncData
> //
> mSmmMpSyncDataSize = 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 = (SMM_DISPATCHER_MP_SYNC_DATA*)
> AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize));
> ASSERT (mSmmMpSyncData != NULL);
> mCpuSmmSyncMode = (SMM_CPU_SYNC_MODE)PcdGet8
> (PcdCpuSmmSyncMode);
> @@ -1469,3 +1869,41 @@ RegisterSmmEntry (
> gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
> return EFI_SUCCESS;
> }
> +
> +/**
> +
> + Register the SMM Foundation entry point.
> +
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL 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 successfully.
> + @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 == NULL && ProcedureArguments != NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (mSmmMpSyncData == NULL) {
> + return EFI_NOT_READY;
> + }
> +
> + mSmmMpSyncData->StartupProcedure = Procedure;
> + mSmmMpSyncData->StartupProcArgs = 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);
>
> + //
> + // Install the SMM Mp Protocol into SMM protocol database
> + //
> + Status = 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 <Protocol/SmmReadyToLock.h>
> #include <Protocol/SmmCpuService.h>
> #include <Protocol/SmmMemoryAttribute.h>
> +#include <Protocol/SmmMp.h>
>
> #include <Guid/AcpiS3Context.h>
> #include <Guid/MemoryAttributesTable.h>
> @@ -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;
>
> ///
> /// 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;
>
> +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;
>
> #define SMM_PSD_OFFSET 0xfb00
> @@ -1259,4 +1282,151 @@ RestoreCr2 (
> IN UINTN Cr2
> );
>
> +/**
> + 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 optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure.
> If the
> + token is not NULL, the call will return immediately.
> The caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation 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 complete within the optional
> timeout.
> + The implementation will update 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, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure 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 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 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 APs.
> +
> + @param[in] Procedure A pointer to the function to be run on
> + enabled APs of the system.
> + @param[in] SingleThread If TRUE, then all the enabled APs execute
> + the function specified by Procedure one by
> + one, in ascending order of processor handle
> + number. If FALSE, then all the enabled APs
> + execute the function specified by Procedure
> + simultaneously.
> + @param[in] WaitEvent The event created by the caller with
> CreateEvent()
> + service.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for
> + APs to return from Procedure, either 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, then its
> + content is set to NULL. If not all APs
> + finish before timeout expires, then its
> + content is set to address of the buffer
> + holding handle numbers of the failed APs.
> +
> + @retval EFI_SUCCESS In blocking mode, all APs have finished 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 to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL 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 successfully.
> + @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
>
> [Sources.Ia32]
> Ia32/Semaphore.c
> @@ -105,6 +107,7 @@
> gEfiSmmReadyToLockProtocolGuid ## NOTIFY
> gEfiSmmCpuServiceProtocolGuid ## PRODUCES
> gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
> + gEfiSmmMpProtocolGuid ## PRODUCES
>
> [Guids]
> gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is
> used for S3 boot.
> --
> 2.21.0.windows.1
next prev parent reply other threads:[~2019-06-26 5:55 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-19 5:51 [Patch 0/2] Enable new MM MP protocol Dong, Eric
2019-06-19 5:51 ` [Patch 1/2] MdePkg: Add new MM MP Protocol definition Dong, Eric
2019-06-20 16:17 ` [edk2-devel] " Laszlo Ersek
2019-06-26 3:14 ` Ni, Ray
2019-06-19 5:51 ` [Patch 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol Dong, Eric
2019-06-20 16:45 ` [edk2-devel] " Laszlo Ersek
2019-06-25 2:15 ` Dong, Eric
2019-06-25 10:24 ` Laszlo Ersek
2019-06-25 10:27 ` Laszlo Ersek
2019-06-26 5:55 ` Ni, Ray [this message]
2019-06-20 16:25 ` [edk2-devel] [Patch 0/2] Enable new MM MP protocol Laszlo Ersek
2019-06-26 3:30 ` Liming Gao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=734D49CCEBEEF84792F5B80ED585239D5C1F0E85@SHSMSX104.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox