From nobody Wed Apr 24 22:56:12 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+43188+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+43188+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1562121768; cv=none; d=zoho.com; s=zohoarc; b=Be17HF7DtGZ/hRdGE8KtVP5un15GMdNwpJfH8pPV9JguyyenkbReQLrGNq2YE9yFYlLmlPct6wXcpxtFdbdQvcBBQWRJmR1N2oG+H4AmvXrD5zeGS/PHq7WHI2Znw0iFN+EtKKgq3QIaUlmVdG4qUI6QhpRNtdfZdoTVLXcEdxU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562121768; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To:ARC-Authentication-Results; bh=oRNrtH1PSbXcJO7pHBhyjAT7UWTpv0L6/DYiuOKx3aU=; b=Mu0SxjJz5jQB/UwA2gQlF+AKnSDNGA/6WkcRYea3K8dH4gYo/qzjSAU9xZHgYI2UK9Hy0PzNmHudLYO+B+skNg97DJWfzfyVX1vN4V9j2VF+wTrP7WkI/L/NMzfdimTcTiQd496DaionMuAHwtg2/BpH/M+c5hxBaa3R7UyOFp4= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+43188+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1562121768005825.079141936208; Tue, 2 Jul 2019 19:42:48 -0700 (PDT) Return-Path: X-Received: from mga02.intel.com (mga02.intel.com []) by groups.io with SMTP; Tue, 02 Jul 2019 19:42:46 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 02 Jul 2019 19:42:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,445,1557212400"; d="scan'208";a="315434610" X-Received: from ydong10-win10.ccr.corp.intel.com ([10.239.158.133]) by orsmga004.jf.intel.com with ESMTP; 02 Jul 2019 19:42:45 -0700 From: "Dong, Eric" To: devel@edk2.groups.io Cc: Ray Ni , Laszlo Ersek Subject: [edk2-devel] [Patch v3 1/2] MdePkg: Add new MM MP Protocol definition. Date: Wed, 3 Jul 2019 10:42:41 +0800 Message-Id: <20190703024242.33572-2-eric.dong@intel.com> In-Reply-To: <20190703024242.33572-1-eric.dong@intel.com> References: <20190703024242.33572-1-eric.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,eric.dong@intel.com Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1562121767; bh=enpYNmczgprXv9bu+J9K2IXLuoOMD1yAdFLYIZmPB3E=; h=Cc:Date:From:Reply-To:Subject:To; b=Y+vAojmNH66Wo/7GFODANEXMkMhVhRgY1197dX4tDCpSREXLWQJWSySrsf/U+qXCQ25 H+db6Vo0fSp/gukvhDN3G2M0Mr3s/83St71E4Pm6bCFAZBnOGmQcOKHYpoIoVL3I7smy8 O+LcF0DqblGxuAqlDgyJaYpt7u4A7dG1Ft8= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" V2 change: 1. Remove SMM prefix definition which not required by spec. V1 changes: REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1937 EFI MM MP Protocol is defined in the PI 1.5 specification. The MM MP protocol provides a set of functions to allow execution of procedures on processors that have entered MM. This protocol has the following properties: 1. The caller can invoke execution of a procedure on a processor, other than the caller, that has also entered MM. Supports blocking and non-blocking modes of operation. 2. The caller can invoke a procedure on multiple processors. Supports blocking and non-blocking modes of operation. Cc: Ray Ni Cc: Laszlo Ersek Signed-off-by: Eric Dong Reviewed-by: Ray Ni --- MdePkg/Include/Pi/PiMultiPhase.h | 16 ++ MdePkg/Include/Protocol/MmMp.h | 333 +++++++++++++++++++++++++++++++ MdePkg/MdePkg.dec | 3 + 3 files changed, 352 insertions(+) create mode 100644 MdePkg/Include/Protocol/MmMp.h diff --git a/MdePkg/Include/Pi/PiMultiPhase.h b/MdePkg/Include/Pi/PiMultiPh= ase.h index eb12527767..a5056799e1 100644 --- a/MdePkg/Include/Pi/PiMultiPhase.h +++ b/MdePkg/Include/Pi/PiMultiPhase.h @@ -176,4 +176,20 @@ VOID IN OUT VOID *Buffer ); =20 +/** + The function prototype for invoking a function on an Application Process= or. + + This definition is used by the UEFI MM MP Serices Protocol. + + @param[in] ProcedureArgument The pointer to private data buffer. + + @retval EFI_SUCCESS Excutive the procedure successfully + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_AP_PROCEDURE2)( + IN VOID *ProcedureArgument +); + #endif diff --git a/MdePkg/Include/Protocol/MmMp.h b/MdePkg/Include/Protocol/MmMp.h new file mode 100644 index 0000000000..beace1386c --- /dev/null +++ b/MdePkg/Include/Protocol/MmMp.h @@ -0,0 +1,333 @@ +/** @file + EFI MM MP Protocol is defined in the PI 1.5 specification. + + The MM MP protocol provides a set of functions to allow execution of pro= cedures on processors that + have entered MM. This protocol has the following properties: + 1. The caller can only invoke execution of a procedure on a processor, o= ther than the caller, that + has also entered MM. + 2. It is possible to invoke a procedure on multiple processors. Supports= blocking and non-blocking + modes of operation. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MM_MP_H_ +#define _MM_MP_H_ + +#include + +#define EFI_MM_MP_PROTOCOL_GUID \ + { \ + 0x5d5450d7, 0x990c, 0x4180, {0xa8, 0x3, 0x8e, 0x63, 0xf0, 0x60, 0x83, = 0x7 } \ + } + +// +// Revision definition. +// +#define EFI_MM_MP_PROTOCOL_REVISION 0x00 + +// +// Attribute flags +// +#define EFI_MM_MP_TIMEOUT_SUPPORTED 0x01 + +// +// Completion token +// +typedef VOID* MM_COMPLETION; + +typedef struct { + MM_COMPLETION Completion; + EFI_STATUS Status; +} MM_DISPATCH_COMPLETION_TOKEN; + +typedef struct _EFI_MM_MP_PROTOCOL EFI_MM_MP_PROTOCOL; + +/** + 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 p= rocessors in the system, + including the BSP and all APs. + + @retval EFI_SUCCESS The number of processors was retrieved s= uccessfully + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MM_GET_NUMBER_OF_PROCESSORS) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + OUT UINTN *NumberOfProcessors +); + + +/** + This service allows the caller to invoke a procedure one of the applicat= ion processors (AP). This + function uses an optional token parameter to support blocking and non-bl= ocking modes. If the token + is passed into the call, the function will operate in a non-blocking fas= hion 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 r= un on the designated target + AP of the system. Type EFI_AP_PROC= EDURE2 is defined below in + related definitions. + @param[in] CpuNumber The zero-based index of the proces= sor number of the target + AP, on which the code stream is su= pposed to run. If the number + points to the calling processor th= en it will not run the + supplied code. + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for this AP to + finish execution of Procedure, eit= her for blocking or + non-blocking mode. Zero means infi= nity. If the timeout + expires before this AP returns fro= m Procedure, then Procedure + on the AP is terminated. If the ti= meout 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 WaitForProcedu= re. + Note that timeout support is optio= nal. Whether an + implementation supports this featu= re, can be determined via + the Attributes data member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 exe= cution on the target AP, or with + EFI_TIMEOUT if the Procedure fails= to complete within the optional + timeout. The implementation will u= pdate this variable with + EFI_NOT_READY prior to starting Pr= ocedure on the target AP. + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the target AP. + In the non-blocking case this indi= cates that the procedure has + been successfully scheduled for ex= ecution on the target AP. + @retval EFI_INVALID_PARAMETER The input arguments are out of ran= ge. Either the target AP is the + caller of the function, or the Pro= cedure 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 anothe= r procedure + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before the specified AP + has finished +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MM_DISPATCH_PROCEDURE) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN CpuNumber, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus +); + +/** + This service allows the caller to invoke a procedure on all running appl= ication processors (AP) + except the caller. This function uses an optional token parameter to sup= port blocking and + nonblocking modes. If the token is passed into the call, the function wi= ll 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 micros= econds for the APs to finish + execution of Procedure, either for= blocking or non-blocking mode. + Zero means infinity. If the timeou= t expires before all APs return + from Procedure, then Procedure on = the failed APs is terminated. If + the timeout expires in blocking mo= de, the call returns EFI_TIMEOUT. + If the timeout expires in non-bloc= king mode, the timeout determined + can be through CheckOnProcedure or= WaitForProcedure. + Note that timeout support is optio= nal. Whether an implementation + supports this feature can be deter= mined via the Attributes data + member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 particip= ated in the broadcast. This + parameter if used provides the bas= e 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 Ge= tNumberOfProcessors function. + As mentioned above, the broadcast = may not include every processor + in the system. Some implementation= s may exclude processors that + have been powered down in such a w= ay that they are not responsive + to interrupts. Additionally the br= oadcast excludes the processor + which is making the BroadcastProce= dure call. For every excluded + processor, the array entry must co= ntain a value of EFI_NOT_STARTED + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the APs. In the non-b= locking case this indicates that + the procedure has been successfull= y scheduled for execution on the + APs. + @retval EFI_INVALID_PARAMETER Procedure or Token is NULL. + @retval EFI_NOT_READY If a target AP is busy executing a= nother procedure. + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before all enabled APs have + finished. + @retval EFI_ALREADY_STARTED Before the AP procedure associated= with the Token is finished, the + same Token cannot be used to dispa= tch or broadcast another procedure. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MM_BROADCAST_PROCEDURE) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus +); + + +/** + This service allows the caller to set a startup procedure that will be e= xecuted when an AP powers + up from a state where core configuration and context is lost. The proced= ure is execution has the + following properties: + 1. The procedure executes before the processor is handed over to the ope= rating system. + 2. All processors execute the same startup procedure. + 3. The procedure may run in parallel with other procedures invoked throu= gh 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_PROCEDUR= E is defined below in Volume 2 + with the related definitions of + EFI_MP_SERVICES_PROTOCOL.StartupAll= APs. + 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 co= mmon mailbox between APs and + the caller to share information + + @retval EFI_SUCCESS The Procedure has been set successf= ully. + @retval EFI_INVALID_PARAMETER The Procedure is NULL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MM_SET_STARTUP_PROCEDURE) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN OUT VOID *ProcedureArguments OPTIONAL +); + +/** + When non-blocking execution of a procedure on an AP is invoked with Disp= atchProcedure, + via the use of a token, this function can be used to check for completio= n 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 o= n the same AP, this function + returns EFI_SUCESS. In this case the status returned by the procedure th= at executed on the AP is + returned in the token's Status field. If the procedure has not yet compl= eted, then this function + returns EFI_NOT_READY. + + When a non-blocking execution of a procedure is invoked with BroadcastPr= ocedure, 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 Bro= adcastProcedure + call. If the procedure is complete on all broadcast APs this function re= turns 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 th= e first observed failure. + If the procedure has not yet completed on the broadcast APs, the functio= n 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 BroadcastProce= dure. + + @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 + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CHECK_FOR_PROCEDURE) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token +); + +/** + When a non-blocking execution of a procedure on an AP is invoked via Dis= patchProcedure, + this function will block the caller until the remote procedure has compl= eted on the designated AP. + The non-blocking procedure invocation is identified by the Token paramet= er, which must match the + token that used when DispatchProcedure was called. Upon completion the s= tatus returned by + the procedure that executed on the AP is used to update the token's Stat= us field. + + When a non-blocking execution of a procedure on an AP is invoked via Bro= adcastProcedure + this function will block the caller until the remote procedure has compl= eted on all of the APs that + entered MM. The non-blocking procedure invocation is identified by the T= oken 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 exec= utions 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 BroadcastProce= dure. + + @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 + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_WAIT_FOR_PROCEDURE) ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token +); + + + +/// +/// The MM MP protocol provides a set of functions to allow execution of p= rocedures on processors that +/// have entered MM. +/// +struct _EFI_MM_MP_PROTOCOL { + UINT32 Revision; + UINT32 Attributes; + EFI_MM_GET_NUMBER_OF_PROCESSORS GetNumberOfProcessors; + EFI_MM_DISPATCH_PROCEDURE DispatchProcedure; + EFI_MM_BROADCAST_PROCEDURE BroadcastProcedure; + EFI_MM_SET_STARTUP_PROCEDURE SetStartupProcedure; + EFI_CHECK_FOR_PROCEDURE CheckForProcedure; + EFI_WAIT_FOR_PROCEDURE WaitForProcedure; +}; + +extern EFI_GUID gEfiMmMpProtocolGuid; + +#endif diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 6c563375ee..b382efd578 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -1167,6 +1167,9 @@ # Protocols defined in PI 1.5. # =20 + ## Include/Protocol/MmMp.h + gEfiMmMpProtocolGuid =3D { 0x5d5450d7, 0x990c, 0x4180, { 0xa8, 0x3, 0x8e= , 0x63, 0xf0, 0x60, 0x83, 0x7 }} + ## Include/Protocol/MmEndOfDxe.h gEfiMmEndOfDxeProtocolGuid =3D { 0x24e70042, 0xd5c5, 0x4260, { 0x8c, 0x3= 9, 0xa, 0xd3, 0xaa, 0x32, 0xe9, 0x3d }} =20 --=20 2.21.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#43188): https://edk2.groups.io/g/devel/message/43188 Mute This Topic: https://groups.io/mt/32293745/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed Apr 24 22:56:12 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+43189+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+43189+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1562121770; cv=none; d=zoho.com; s=zohoarc; b=HFMDityH/i21s692EX8KAElQXtbETHsHCMsoHoqXEfkjpT0Y0zXfdsPZTDUbOBukBejsfyRvyVYOaTVF9z97NvQgAxPTVTrB3RHjkWNPbwD6lbfCpNfiV7wZXiCcbMaJ5aBuDNP+G92NaNNldwqRzX7mAmAN/dlcKEpTNdPd618= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562121770; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To:ARC-Authentication-Results; bh=KKeMmjZ916P6iJxr8o9E3boDlnY5hIcJ+1J1Jgy0CaU=; b=dpV8db7ff+W0fDLj/0qMbUCSqKBMwLXcwiPKWJZR/2rfAwQs74zLAzpaC1JA+O+KykFLe1G4qhypRo9+eitmymRhTx6CGS/rDvZGkcWjNgC0jTqJcgsH/cdUWuyvMPrS9vcA9CfFR8aLD/LN4XLdb9nHSaucKB15BDzvFDnh1Bs= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+43189+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1562121770258449.968666314026; Tue, 2 Jul 2019 19:42:50 -0700 (PDT) Return-Path: X-Received: from mga02.intel.com (mga02.intel.com []) by groups.io with SMTP; Tue, 02 Jul 2019 19:42:49 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 02 Jul 2019 19:42:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,445,1557212400"; d="scan'208";a="315434617" X-Received: from ydong10-win10.ccr.corp.intel.com ([10.239.158.133]) by orsmga004.jf.intel.com with ESMTP; 02 Jul 2019 19:42:46 -0700 From: "Dong, Eric" To: devel@edk2.groups.io Cc: Ray Ni , Laszlo Ersek Subject: [edk2-devel] [Patch v3 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol. Date: Wed, 3 Jul 2019 10:42:42 +0800 Message-Id: <20190703024242.33572-3-eric.dong@intel.com> In-Reply-To: <20190703024242.33572-1-eric.dong@intel.com> References: <20190703024242.33572-1-eric.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,eric.dong@intel.com Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1562121769; bh=MbK4/wDcQPxU+cLNrOS1scIqK2smPQBfRpumBliwxOk=; h=Cc:Date:From:Reply-To:Subject:To; b=QjK2S+mpclamWFzhbOEDxO2lwlzMNrpAafcWaHvCzCSTKHKJxjdlAQH74cvY16XRdj6 jlULAZ4wScTn7Z1h5kXqXJM7QAvTvUYmLXma3kPfM/NE/maC8jvBPi2qG4maPKOMYIm3G Yn9ulq3FC+6KV17ZLoiHieH+HzjmYNr49Lw= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" v3 changes: 1. Fix Token clean up too early caused CheckProcedure return error. v2 changes: 1. Remove some duplicated global variables. 2. Enhance token design to support multiple task trig for different APs at = the same time. V1 changes: REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1937 Add MM Mp Protocol in PiSmmCpuDxeSmm driver. Cc: Ray Ni Cc: Laszlo Ersek Signed-off-by: Eric Dong --- UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 536 ++++++++++++++++++- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 11 + UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 160 +++++- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 + UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 372 +++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++ 6 files changed, 1351 insertions(+), 17 deletions(-) create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxe= Smm/MpService.c index 64fb4d6344..13858f5d2d 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c @@ -22,6 +22,7 @@ UINTN mSemaphoreSiz= e; SPIN_LOCK *mPFLock =3D NULL; SMM_CPU_SYNC_MODE mCpuSmmSyncMode; BOOLEAN mMachineCheckSupported =3D FAL= SE; +SPIN_LOCK **mApTokenLock; =20 /** Performs an atomic compare exchange operation to get semaphore. @@ -146,6 +147,45 @@ ReleaseAllAPs ( } } =20 +/** + Wheck whether task has been finished by all APs. + + @param BlockMode Whether did it in block mode or non-block mode. + + @retval TRUE Task has been finished by all APs. + @retval FALSE Task not has been finished by all APs. + +**/ +BOOLEAN +IsTaskFinishInAllAPs ( + IN BOOLEAN BlockMode + ) +{ + UINTN Index; + + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { + // + // Ignore BSP and APs which not call in SMM. + // + if ((Index =3D=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecuti= ngCpu) || (!*(mSmmMpSyncData->CpuData[Index].Present))) { + continue; + } + + if (BlockMode) { + AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy); + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy); + } else { + if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) { + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy); + } else { + return FALSE; + } + } + } + + return TRUE; +} + /** Checks if all CPUs (with certain exceptions) have checked in for this SM= I run =20 @@ -347,6 +387,92 @@ ReplaceOSMtrrs ( MtrrSetAllMtrrs (&gSmiMtrrs); } =20 +/** + Check whether execute in single AP or all APs. + + Compare two Tokens used by different APs to know whether in StartAllAps = call. + + Whether is an valid AP base on AP's Present flag. + + @retval TRUE IN StartAllAps call. + @retval FALSE Not in StartAllAps call. + +**/ +BOOLEAN +InStartAllApsCall ( + VOID + ) +{ + UINTN ApIndex; + UINTN ApIndex2; + + for (ApIndex =3D mMaxNumberOfCpus; ApIndex-- > 0;) { + if ((ApIndex !=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecuti= ngCpu) &&=20 + *(mSmmMpSyncData->CpuData[ApIndex].Present) && + (mSmmMpSyncData->CpuData[ApIndex].Token !=3D NULL)) { + for (ApIndex2 =3D ApIndex; ApIndex2-- > 0;) { + if ((ApIndex2 !=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyEx= ecutingCpu) &&=20 + *(mSmmMpSyncData->CpuData[ApIndex2].Present) && + (mSmmMpSyncData->CpuData[ApIndex2].Token !=3D NULL)) { + return mSmmMpSyncData->CpuData[ApIndex2].Token =3D=3D mSmmMpSync= Data->CpuData[ApIndex].Token; + } + } + } + } + + return FALSE; +} + +/** + Clean up the status flags used during executing the procedure. + + @param CpuIndex The AP index which calls this function. + +**/ +VOID +CleanUpStatusFlags ( + IN UINTN CpuIndex + ) +{ + UINTN Index; + + if (InStartAllApsCall ()) { + // + // In Start All APs mode, make sure all APs have finished task. + // + if (IsTaskFinishInAllAPs (FALSE)) { + // + // Clean the flags update in the function call. + // + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { + // + // Only In SMM APs need to be clean up. + // + if (mSmmMpSyncData->CpuData[Index].Present) { + if (mSmmMpSyncData->CpuData[Index].Token !=3D NULL) { + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token); + break; + } + } + } + } + } else { + // + // In single AP mode. + // + if (mSmmMpSyncData->CpuData[CpuIndex].Token !=3D NULL) { + // + // Free the wrapper buffer in non-block mode used by SmmMpDispatchPr= ocedure function. + // + if (mApTokenLock[CpuIndex] =3D=3D mSmmMpSyncData->CpuData[CpuIndex].= Token) { + FreePool ((VOID *)mSmmMpSyncData->CpuData[CpuIndex].Parameter); + } + + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token); + } + } +} + /** SMI handler for BSP. =20 @@ -604,6 +730,7 @@ APHandler ( UINT64 Timer; UINTN BspIndex; MTRR_SETTINGS Mtrrs; + EFI_STATUS ProcedureStatus; =20 // // Timeout BSP @@ -730,14 +857,19 @@ APHandler ( // // Invoke the scheduled procedure // - (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) ( - (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter - ); + ProcedureStatus =3D (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) ( + (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Paramet= er + ); + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D ProcedureStatus; + } =20 // // Release BUSY // ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); + + CleanUpStatusFlags (CpuIndex); } =20 if (SmmCpuFeaturesNeedConfigureMtrrs()) { @@ -906,13 +1038,95 @@ Gen4GPageTable ( return (UINT32)(UINTN)PageTable; } =20 +/** + Checks whether the input token is the current used token. + + @param[in] CpuIndex Cpu Index. + @param[in] Token This parameter describes the token that was passe= d into DispatchProcedure or + BroadcastProcedure. + + @retval TRUE The input token is the current used token. + @retval FALSE The input token is not the current used token. +**/ +BOOLEAN +IsCurrentToken ( + IN UINTN CpuIndex, + IN SPIN_LOCK *Token + ) +{ + UINTN Index; + + if (Token =3D=3D NULL) { + return FALSE; + } + + if (CpuIndex =3D=3D (UINTN) -1) { + for (Index =3D 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOf= Cpus; Index ++) { + if (mSmmMpSyncData->CpuData[Index].Present &&=20 + (mSmmMpSyncData->CpuData[Index].Token !=3D NULL) && + (mSmmMpSyncData->CpuData[Index].Token =3D=3D Token)) { + return TRUE; + } + } + + return FALSE; + } + + return mSmmMpSyncData->CpuData[CpuIndex].Token =3D=3D Token; +} + +/** + Checks status of specified AP. + + This function checks whether the specified AP has finished the task assi= gned + by StartupThisAP(), and whether timeout expires. + + @param[in] Token This parameter describes the token that wa= s 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 tim= eout has not expired. +**/ +EFI_STATUS +IsApReady ( + IN SPIN_LOCK *Token + ) +{ + if (AcquireSpinLockOrFail (Token)) { + ReleaseSpinLock (Token); + return EFI_SUCCESS; + } + + return EFI_NOT_READY; +} + /** Schedule a procedure to run on the specified CPU. =20 @param[in] Procedure The address of the procedure t= o run @param[in] CpuIndex Target CPU Index - @param[in, out] ProcArguments The parameter to pass to the p= rocedure - @param[in] BlockingMode Startup AP in blocking mode or= not + @param[in,out] ProcArguments The parameter to pass to the p= rocedure + @param[in] Token This is an optional parameter = that allows the caller to execute the + procedure in a blocking or non= -blocking fashion. If it is NULL the + call is blocking, and the call= will not return until the AP has + completed the procedure. If th= e token is not NULL, the call will + return immediately. The caller= can check whether the procedure has + completed with CheckOnProcedur= e or WaitForProcedure. + @param[in] TimeoutInMicroseconds Indicates the time limit in mi= croseconds for the APs to finish + execution of Procedure, either= for blocking or non-blocking mode. + Zero means infinity. If the ti= meout expires before all APs return + from Procedure, then Procedure= on the failed APs is terminated. If + the timeout expires in blockin= g mode, the call returns EFI_TIMEOUT. + If the timeout expires in non-= blocking mode, the timeout determined + can be through CheckOnProcedur= e or WaitForProcedure. + Note that timeout support is o= ptional. Whether an implementation + supports this feature can be d= etermined via the Attributes data + member. + @param[in,out] CpuStatus This optional pointer may be u= sed to get the status code returned + by Procedure when it completes= execution on the target AP, or with + EFI_TIMEOUT if the Procedure f= ails to complete within the optional + timeout. The implementation wi= ll update this variable with + EFI_NOT_READY prior to startin= g Procedure on the target AP. =20 @retval EFI_INVALID_PARAMETER CpuNumber not valid @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP @@ -923,10 +1137,12 @@ Gen4GPageTable ( **/ EFI_STATUS InternalSmmStartupThisAp ( - IN EFI_AP_PROCEDURE Procedure, - IN UINTN CpuIndex, - IN OUT VOID *ProcArguments OPTIONAL, - IN BOOLEAN BlockingMode + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN CpuIndex, + IN OUT VOID *ProcArguments OPTIONAL, + IN SPIN_LOCK *Token, + IN UINTN TimeoutInMicroseconds, + IN OUT EFI_STATUS *CpuStatus ) { if (CpuIndex >=3D gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) { @@ -952,24 +1168,208 @@ InternalSmmStartupThisAp ( } return EFI_INVALID_PARAMETER; } + if ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & EFI_MM_MP_TI= MEOUT_SUPPORTED) =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + if (Procedure =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + if (IsCurrentToken (CpuIndex, Token)) { + return EFI_ALREADY_STARTED; + } =20 - if (BlockingMode) { + if (Token =3D=3D NULL) { AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); } else { - if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) { - DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex)); + if (!AcquireSpinLockOrFail (Token)) { + DEBUG((DEBUG_ERROR, "Token can't acquire\n")); return EFI_INVALID_PARAMETER; } + if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) { + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].Busy\= n", CpuIndex)); + ReleaseSpinLock (Token); + return EFI_NOT_READY; + } } =20 mSmmMpSyncData->CpuData[CpuIndex].Procedure =3D Procedure; mSmmMpSyncData->CpuData[CpuIndex].Parameter =3D ProcArguments; + mSmmMpSyncData->CpuData[CpuIndex].Token =3D Token; + mSmmMpSyncData->CpuData[CpuIndex].Status =3D CpuStatus; + if (mSmmMpSyncData->CpuData[CpuIndex].Status !=3D NULL) { + *mSmmMpSyncData->CpuData[CpuIndex].Status =3D EFI_NOT_READY; + } + ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run); =20 - if (BlockingMode) { + if (Token =3D=3D NULL) { AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); } + + return EFI_SUCCESS; +} + +/** + Worker function to execute a caller provided function on all enabled APs. + + @param[in] Procedure A pointer to the function to be r= un on + enabled APs of the system. + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for + APs to return from Procedure, eit= her for + blocking or non-blocking mode. + @param[in,out] ProcedureArguments The parameter passed into Procedu= re for + all APs. + @param[in,out] Token This is an optional parameter tha= t allows the caller to execute the + procedure in a blocking or non-bl= ocking fashion. If it is NULL the + call is blocking, and the call wi= ll not return until the AP has + completed the procedure. If the t= oken is not NULL, the call will + return immediately. The caller ca= n check whether the procedure has + completed with CheckOnProcedure o= r WaitForProcedure. + @param[in,out] CPUStatus This optional pointer may be used= to get the status code returned + by Procedure when it completes ex= ecution on the target AP, or with + EFI_TIMEOUT if the Procedure fail= s to complete within the optional + timeout. The implementation will = update this variable with + EFI_NOT_READY prior to starting P= rocedure on the target AP. + + + @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 ((TimeoutInMicroseconds !=3D 0) && ((mSmmMp.Attributes & EFI_MM_MP_TI= MEOUT_SUPPORTED) =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + if (Procedure =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + if (IsCurrentToken ((UINTN)-1, Token)) { + return EFI_ALREADY_STARTED; + } + + CpuCount =3D 0; + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { + if (*mSmmMpSyncData->CpuData[Index].Present && (Index !=3D gSmmCpuPriv= ate->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.CurrentlyExecutin= gCpu && *(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.CurrentlyExecutin= gCpu && *(mSmmMpSyncData->CpuData[Index].Present)) { + if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) { + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].B= usy\n", Index)); + + // + // Release BUSY accquired before. + // + for (CpuCount =3D mMaxNumberOfCpus; CpuCount -- > Index;) { + if (CpuCount !=3D gSmmCpuPrivate->SmmCoreEntryContext.Currentl= yExecutingCpu && *(mSmmMpSyncData->CpuData[CpuCount].Present)) { + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuCount].Busy); + } + } + + ReleaseSpinLock (Token); + return EFI_INVALID_PARAMETER; + } + } + } + } + + for (Index =3D mMaxNumberOfCpus; Index-- > 0;) { + if (Index !=3D gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingC= pu && *(mSmmMpSyncData->CpuData[Index].Present)) { + mSmmMpSyncData->CpuData[Index].Procedure =3D (EFI_AP_PROCEDURE2) Pro= cedure; + mSmmMpSyncData->CpuData[Index].Parameter =3D ProcedureArguments; + mSmmMpSyncData->CpuData[Index].Token =3D Token; + if (CPUStatus !=3D NULL) { + mSmmMpSyncData->CpuData[Index].Status =3D CPUStatus + Index; + if (mSmmMpSyncData->CpuData[Index].Status !=3D NULL) { + *mSmmMpSyncData->CpuData[Index].Status =3D EFI_NOT_READY; + } + } + } else { + // + // PI spec requirement: + // For every excluded processor, the array entry must contain a valu= e of EFI_NOT_STARTED. + // + if (CPUStatus !=3D NULL) { + *(CPUStatus + Index) =3D EFI_NOT_STARTED; + } + } + } + + ReleaseAllAPs (); + + if (Token =3D=3D NULL) { + // + // Make sure all APs have completed their tasks. + // + IsTaskFinishInAllAPs (TRUE); + } + + return EFI_SUCCESS; +} + +/** + Wrapper for Procedures. + + @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer. + +**/ +EFI_STATUS +EFIAPI +ProcedureWrapper ( + IN OUT VOID *Buffer + ) +{ + PROCEDURE_WRAPPER *Wrapper; + + Wrapper =3D Buffer; + Wrapper->Procedure (Wrapper->ProcedureArgument); + return EFI_SUCCESS; } =20 @@ -995,7 +1395,24 @@ SmmBlockingStartupThisAp ( IN OUT VOID *ProcArguments OPTIONAL ) { - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE= ); + PROCEDURE_WRAPPER *Wrapper; + EFI_STATUS Status; + + Wrapper =3D AllocatePool (sizeof(PROCEDURE_WRAPPER)); + if (Wrapper =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + Wrapper->Procedure =3D Procedure; + Wrapper->ProcedureArgument =3D ProcArguments; + + // + // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2. + // + Status =3D InternalSmmStartupThisAp(ProcedureWrapper, CpuIndex, Wrapper,= NULL, 0, NULL); + + FreePool (Wrapper); + + return Status; } =20 /** @@ -1020,7 +1437,37 @@ SmmStartupThisAp ( IN OUT VOID *ProcArguments OPTIONAL ) { - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, Feat= urePcdGet (PcdCpuSmmBlockStartupThisAp)); + SPIN_LOCK *CpuToken; + PROCEDURE_WRAPPER *Wrapper; + EFI_STATUS Status; + + Wrapper =3D AllocatePool (sizeof(PROCEDURE_WRAPPER)); + if (Wrapper =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + Wrapper->Procedure =3D Procedure; + Wrapper->ProcedureArgument =3D ProcArguments; + + if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) { + CpuToken =3D NULL; + } else { + CpuToken =3D mApTokenLock[CpuIndex]; + } + + // + // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2. + // + Status =3D InternalSmmStartupThisAp(ProcedureWrapper, CpuIndex, Wrapper,= CpuToken, 0, NULL); + + // + // Free wrapper buffer for block mode. + // Non-block mode frees buffer in ApHandler function. + // + if (CpuToken =3D=3D NULL) { + FreePool (Wrapper); + } + + return Status; } =20 /** @@ -1112,6 +1559,13 @@ SmiRendezvous ( Cr2 =3D 0; SaveCr2 (&Cr2); =20 + // + // Call the user register Startup function first. + // + if (mSmmMpSyncData->StartupProcedure !=3D NULL) { + mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs); + } + // // Perform CPU specific entry hooks // @@ -1273,13 +1727,17 @@ InitializeSmmCpuSemaphores ( UINTN Pages; UINTN *SemaphoreBlock; UINTN SemaphoreAddr; + UINTN ApTokenSize; + UINTN CpuIndex;=20 =20 SemaphoreSize =3D GetSpinLockProperties (); ProcessorCount =3D gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; GlobalSemaphoresSize =3D (sizeof (SMM_CPU_SEMAPHORE_GLOBAL) / sizeof (VO= ID *)) * SemaphoreSize; CpuSemaphoresSize =3D (sizeof (SMM_CPU_SEMAPHORE_CPU) / sizeof (VOID = *)) * ProcessorCount * SemaphoreSize; - TotalSize =3D GlobalSemaphoresSize + CpuSemaphoresSize; + ApTokenSize =3D SemaphoreSize * ProcessorCount; + TotalSize =3D GlobalSemaphoresSize + CpuSemaphoresSize + ApTokenSize; DEBUG((EFI_D_INFO, "One Semaphore Size =3D 0x%x\n", SemaphoreSize)); + DEBUG((EFI_D_INFO, "Token Spin Lock Size =3D 0x%x\n", ApTokenSize)); DEBUG((EFI_D_INFO, "Total Semaphores Size =3D 0x%x\n", TotalSize)); Pages =3D EFI_SIZE_TO_PAGES (TotalSize); SemaphoreBlock =3D AllocatePages (Pages); @@ -1305,10 +1763,19 @@ InitializeSmmCpuSemaphores ( mSmmCpuSemaphores.SemaphoreCpu.Run =3D (UINT32 *)SemaphoreAddr; SemaphoreAddr +=3D ProcessorCount * SemaphoreSize; mSmmCpuSemaphores.SemaphoreCpu.Present =3D (BOOLEAN *)SemaphoreAddr; + SemaphoreAddr +=3D ProcessorCount * SemaphoreSize; + mSmmCpuSemaphores.SemaphoreCpu.Token =3D (SPIN_LOCK *)SemaphoreAddr; =20 mPFLock =3D mSmmCpuSemaphores.SemaphoreGlobal.PFLo= ck; mConfigSmmCodeAccessCheckLock =3D mSmmCpuSemaphores.SemaphoreGlobal.Code= AccessCheckLock; =20 + mApTokenLock =3D AllocatePool (sizeof (SPIN_LOCK *) * gSmmCpuPrivate->Sm= mCoreEntryContext.NumberOfCpus); + ASSERT (mApTokenLock !=3D NULL); + for (CpuIndex =3D 0; CpuIndex < gSmmCpuPrivate->SmmCoreEntryContext.Numb= erOfCpus; CpuIndex ++) { + mApTokenLock[CpuIndex] =3D (SPIN_LOCK *)((UINTN)mSmmCpuSemaphores.Sema= phoreCpu.Token + SemaphoreSize * CpuIndex); + InitializeSpinLock (mApTokenLock[CpuIndex]); + } + mSemaphoreSize =3D SemaphoreSize; } =20 @@ -1469,3 +1936,40 @@ RegisterSmmEntry ( gSmmCpuPrivate->SmmCoreEntry =3D SmmEntryPoint; return EFI_SUCCESS; } + +/** + + Register the SMM Foundation entry point. + + @param[in] Procedure A pointer to the code stream to be = run on the designated target AP + of the system. Type EFI_AP_PROCEDUR= E is defined below in Volume 2 + with the related definitions of + EFI_MP_SERVICES_PROTOCOL.StartupAll= APs. + If caller may pass a value of NULL = to deregister any existing + startup procedure. + @param[in] ProcedureArguments Allows the caller to pass a list of= parameters to the code that is + run by the AP. It is an optional co= mmon mailbox between APs and + the caller to share information + + @retval EFI_SUCCESS The Procedure has been set successf= ully. + @retval EFI_INVALID_PARAMETER The Procedure is NULL but Procedure= Arguments 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/PiSmmC= puDxeSmm/PiSmmCpuDxeSmm.c index 2f7d777ee7..dd1b3be0f5 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -996,6 +996,17 @@ PiCpuSmmEntry ( ); ASSERT_EFI_ERROR (Status); =20 + // + // Install the SMM Mp Protocol into SMM protocol database + // + Status =3D gSmst->SmmInstallProtocolInterface ( + &mSmmCpuHandle, + &gEfiMmMpProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmMp + ); + ASSERT_EFI_ERROR (Status); + // // Expose address of CPU Hot Plug Data structure if CPU hot plug is supp= orted. // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmC= puDxeSmm/PiSmmCpuDxeSmm.h index 2bb35a424d..5df09687e1 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include =20 #include #include @@ -221,11 +222,20 @@ typedef struct { EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration; } SMM_CPU_PRIVATE_DATA; =20 +// +// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE. +// +typedef struct { + EFI_AP_PROCEDURE Procedure; + VOID *ProcedureArgument; +} PROCEDURE_WRAPPER; + extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate; extern CPU_HOT_PLUG_DATA mCpuHotPlugData; extern UINTN mMaxNumberOfCpus; extern UINTN mNumberOfCpus; extern EFI_SMM_CPU_PROTOCOL mSmmCpu; +extern EFI_MM_MP_PROTOCOL mSmmMp; =20 /// /// The mode of the CPU at the time an SMI occurs @@ -363,10 +373,12 @@ SmmRelocationSemaphoreComplete ( /// typedef struct { SPIN_LOCK *Busy; - volatile EFI_AP_PROCEDURE Procedure; + volatile EFI_AP_PROCEDURE2 Procedure; volatile VOID *Parameter; volatile UINT32 *Run; volatile BOOLEAN *Present; + SPIN_LOCK *Token; + EFI_STATUS *Status; } SMM_CPU_DATA_BLOCK; =20 typedef enum { @@ -388,6 +400,8 @@ typedef struct { volatile SMM_CPU_SYNC_MODE EffectiveSyncMode; volatile BOOLEAN SwitchBsp; volatile BOOLEAN *CandidateBsp; + EFI_AP_PROCEDURE StartupProcedure; + VOID *StartupProcArgs; } SMM_DISPATCHER_MP_SYNC_DATA; =20 #define SMM_PSD_OFFSET 0xfb00 @@ -410,6 +424,7 @@ typedef struct { SPIN_LOCK *Busy; volatile UINT32 *Run; volatile BOOLEAN *Present; + SPIN_LOCK *Token; } SMM_CPU_SEMAPHORE_CPU; =20 /// @@ -439,6 +454,7 @@ extern SPIN_LOCK *mConfigSmmC= odeAccessCheckLock; extern EFI_SMRAM_DESCRIPTOR *mSmmCpuSmramRanges; extern UINTN mSmmCpuSmramRangeCount; extern UINT8 mPhysicalAddressBits; +extern SPIN_LOCK **mApTokenLock; =20 // // Copy of the PcdPteMemoryEncryptionAddressOrMask @@ -1259,4 +1275,146 @@ RestoreCr2 ( IN UINTN Cr2 ); =20 +/** + Schedule a procedure to run on the specified CPU. + + @param[in] Procedure The address of the procedure t= o run + @param[in] CpuIndex Target CPU Index + @param[in,out] ProcArguments The parameter to pass to the p= rocedure + @param[in,out] Token This is an optional parameter = that allows the caller to execute the + procedure in a blocking or non= -blocking fashion. If it is NULL the + call is blocking, and the call= will not return until the AP has + completed the procedure. If th= e token is not NULL, the call will + return immediately. The caller= can check whether the procedure has + completed with CheckOnProcedur= e or WaitForProcedure. + @param[in] TimeoutInMicroseconds Indicates the time limit in mi= croseconds for the APs to finish + execution of Procedure, either= for blocking or non-blocking mode. + Zero means infinity. If the ti= meout expires before all APs return + from Procedure, then Procedure= on the failed APs is terminated. If + the timeout expires in blockin= g mode, the call returns EFI_TIMEOUT. + If the timeout expires in non-= blocking mode, the timeout determined + can be through CheckOnProcedur= e or WaitForProcedure. + Note that timeout support is o= ptional. Whether an implementation + supports this feature can be d= etermined via the Attributes data + member. + @param[in,out] CPUStatus This optional pointer may be u= sed to get the status code returned + by Procedure when it completes= execution on the target AP, or with + EFI_TIMEOUT if the Procedure f= ails to complete within the optional + timeout. The implementation wi= ll update this variable with + EFI_NOT_READY prior to startin= g Procedure on the target AP. + + + @retval EFI_INVALID_PARAMETER CpuNumber not valid + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not e= nter SMM + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy + @retval EFI_SUCCESS The procedure has been successfully sch= eduled + +**/ +EFI_STATUS +InternalSmmStartupThisAp ( + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN CpuIndex, + IN OUT VOID *ProcArguments OPTIONAL, + IN SPIN_LOCK *Token, + IN UINTN TimeoutInMicroseconds, + IN OUT EFI_STATUS *CpuStatus + ); + +/** + Checks whether the input token is the current used token. + + @param[in] CpuIndex Cpu Index. + @param[in] Token This parameter describes the token that was passe= d into DispatchProcedure or + BroadcastProcedure. + + @retval TRUE The input token is the current used token. + @retval FALSE The input token is not the current used token. +**/ +BOOLEAN +IsCurrentToken ( + IN UINTN CpuIndex, + IN SPIN_LOCK *Token + ); + +/** + Checks status of specified AP. + + This function checks whether the specified AP has finished the task assi= gned + by StartupThisAP(), and whether timeout expires. + + @param[in] Token This parameter describes the token that wa= s 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 tim= eout has not expired. +**/ +EFI_STATUS +IsApReady ( + IN SPIN_LOCK *Token + ); + +/** + Worker function to execute a caller provided function on all enabled APs. + + @param[in] Procedure A pointer to the function to be r= un on + enabled APs of the system. + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for + APs to return from Procedure, eit= her for + blocking or non-blocking mode. + @param[in,out] ProcedureArgument The parameter passed into Procedu= re for + all APs. + @param[in,out] Token This is an optional parameter tha= t allows the caller to execute the + procedure in a blocking or non-bl= ocking fashion. If it is NULL the + call is blocking, and the call wi= ll not return until the AP has + completed the procedure. If the t= oken is not NULL, the call will + return immediately. The caller ca= n check whether the procedure has + completed with CheckOnProcedure o= r WaitForProcedure. + @param[in,out] CPUStatus This optional pointer may be used= to get the status code returned + by Procedure when it completes ex= ecution on the target AP, or with + EFI_TIMEOUT if the Procedure fail= s to complete within the optional + timeout. The implementation will = update this variable with + EFI_NOT_READY prior to starting P= rocedure on the target AP. + + + @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_PROCEDUR= E is defined below in Volume 2 + with the related definitions of + EFI_MP_SERVICES_PROTOCOL.StartupAll= APs. + 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 co= mmon mailbox between APs and + the caller to share information + + @retval EFI_SUCCESS The Procedure has been set successf= ully. + @retval EFI_INVALID_PARAMETER The Procedure is NULL but Procedure= Arguments not NULL. + +**/ +EFI_STATUS +RegisterStartupProcedure ( + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArguments OPTIONAL + ); + #endif diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSm= mCpuDxeSmm/PiSmmCpuDxeSmm.inf index 466c568d49..da0308c47f 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -40,6 +40,8 @@ SmmProfileInternal.h SmramSaveState.c SmmCpuMemoryManagement.c + SmmMp.h + SmmMp.c =20 [Sources.Ia32] Ia32/Semaphore.c @@ -105,6 +107,7 @@ gEfiSmmReadyToLockProtocolGuid ## NOTIFY gEfiSmmCpuServiceProtocolGuid ## PRODUCES gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES + gEfiMmMpProtocolGuid ## PRODUCES =20 [Guids] gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # = it is used for S3 boot. diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c b/UefiCpuPkg/PiSmmCpuDxeSmm/= SmmMp.c new file mode 100644 index 0000000000..bfbc78691f --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c @@ -0,0 +1,372 @@ +/** @file +SMM MP protocol implementation + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCpuDxeSmm.h" +#include "SmmMp.h" + +/// +/// SMM MP Protocol instance +/// +EFI_MM_MP_PROTOCOL mSmmMp =3D { + EFI_MM_MP_PROTOCOL_REVISION, + 0, + SmmMpGetNumberOfProcessors, + SmmMpDispatchProcedure, + SmmMpBroadcastProcedure, + SmmMpSetStartupProcedure, + SmmMpCheckForProcedure, + SmmMpWaitForProcedure +}; + +/** + Service to retrieves the number of logical processor in the platform. + + @param[in] This The EFI_MM_MP_PROTOCOL instance. + @param[out] NumberOfProcessors Pointer to the total number of logical p= rocessors in the system, + including the BSP and all APs. + + @retval EFI_SUCCESS The number of processors was retrieved s= uccessfully + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL +**/ +EFI_STATUS +EFIAPI +SmmMpGetNumberOfProcessors ( + IN CONST EFI_MM_MP_PROTOCOL *This, + OUT UINTN *NumberOfProcessors + ) +{ + if (NumberOfProcessors =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + *NumberOfProcessors =3D gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; + + return EFI_SUCCESS; +} + + +/** + This service allows the caller to invoke a procedure one of the applicat= ion processors (AP). This + function uses an optional token parameter to support blocking and non-bl= ocking modes. If the token + is passed into the call, the function will operate in a non-blocking fas= hion 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 r= un on the designated target + AP of the system. Type EFI_AP_PROC= EDURE2 is defined below in + related definitions. + @param[in] CpuNumber The zero-based index of the proces= sor number of the target + AP, on which the code stream is su= pposed to run. If the number + points to the calling processor th= en it will not run the + supplied code. + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for this AP to + finish execution of Procedure, eit= her for blocking or + non-blocking mode. Zero means infi= nity. If the timeout + expires before this AP returns fro= m Procedure, then Procedure + on the AP is terminated. If the ti= meout 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 WaitForProcedu= re. + Note that timeout support is optio= nal. Whether an + implementation supports this featu= re, can be determined via + the Attributes data member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 exe= cution on the target AP, or with + EFI_TIMEOUT if the Procedure fails= to complete within the optional + timeout. The implementation will u= pdate this variable with + EFI_NOT_READY prior to starting Pr= ocedure on the target AP. + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the target AP. + In the non-blocking case this indi= cates that the procedure has + been successfully scheduled for ex= ecution on the target AP. + @retval EFI_INVALID_PARAMETER The input arguments are out of ran= ge. Either the target AP is the + caller of the function, or the Pro= cedure 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 anothe= r procedure + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before the specified AP + has finished + @retval EFI_OUT_OF_RESOURCES Could not allocate a required reso= urce. + +**/ +EFI_STATUS +EFIAPI +SmmMpDispatchProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN CpuNumber, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus + ) +{ + SPIN_LOCK *CpuToken; + + if (Token !=3D NULL) { + CpuToken =3D AllocatePool (sizeof (SPIN_LOCK)); + ASSERT (CpuToken !=3D NULL); + if (CpuToken =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + InitializeSpinLock ((SPIN_LOCK *)(CpuToken)); + + *Token =3D (MM_COMPLETION)CpuToken; + } + + return InternalSmmStartupThisAp ( + Procedure, + CpuNumber, + ProcedureArguments, + Token !=3D NULL ? CpuToken : NULL, + TimeoutInMicroseconds, + CPUStatus + ); +} + +/** + This service allows the caller to invoke a procedure on all running appl= ication processors (AP) + except the caller. This function uses an optional token parameter to sup= port blocking and + nonblocking modes. If the token is passed into the call, the function wi= ll 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 micros= econds for the APs to finish + execution of Procedure, either for= blocking or non-blocking mode. + Zero means infinity. If the timeou= t expires before all APs return + from Procedure, then Procedure on = the failed APs is terminated. If + the timeout expires in blocking mo= de, the call returns EFI_TIMEOUT. + If the timeout expires in non-bloc= king mode, the timeout determined + can be through CheckOnProcedure or= WaitForProcedure. + Note that timeout support is optio= nal. Whether an implementation + supports this feature can be deter= mined via the Attributes data + member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 particip= ated in the broadcast. This + parameter if used provides the bas= e 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 Ge= tNumberOfProcessors function. + As mentioned above, the broadcast = may not include every processor + in the system. Some implementation= s may exclude processors that + have been powered down in such a w= ay that they are not responsive + to interrupts. Additionally the br= oadcast excludes the processor + which is making the BroadcastProce= dure call. For every excluded + processor, the array entry must co= ntain a value of EFI_NOT_STARTED + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the APs. + In the non-blocking case this indi= cates that the procedure has + been successfully scheduled for ex= ecution 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 anothe= r procedure + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before the specified AP + has finished. + @retval EFI_OUT_OF_RESOURCES Could not allocate a required reso= urce. + +**/ +EFI_STATUS +EFIAPI +SmmMpBroadcastProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus + ) +{ + SPIN_LOCK *CpuToken; + + if (Token !=3D NULL) { + CpuToken =3D AllocatePool (sizeof (SPIN_LOCK)); + ASSERT (CpuToken !=3D NULL); + if (CpuToken =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + InitializeSpinLock ((SPIN_LOCK *)(CpuToken)); + + *Token =3D (MM_COMPLETION)CpuToken; + } + + return InternalSmmStartupAllAPs( + Procedure, + TimeoutInMicroseconds, + ProcedureArguments, + Token !=3D NULL ? CpuToken : NULL, + CPUStatus + ); +} + + +/** + This service allows the caller to set a startup procedure that will be e= xecuted when an AP powers + up from a state where core configuration and context is lost. The proced= ure is execution has the + following properties: + 1. The procedure executes before the processor is handed over to the ope= rating system. + 2. All processors execute the same startup procedure. + 3. The procedure may run in parallel with other procedures invoked throu= gh 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_PROCEDUR= E is defined below in Volume 2 + with the related definitions of + EFI_MP_SERVICES_PROTOCOL.StartupAll= APs. + 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 co= mmon mailbox between APs and + the caller to share information + + @retval EFI_SUCCESS The Procedure has been set successf= ully. + @retval EFI_INVALID_PARAMETER The Procedure is NULL but Procedure= Arguments not NULL. + +**/ +EFI_STATUS +EFIAPI +SmmMpSetStartupProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN OUT VOID *ProcedureArguments OPTIONAL + ) +{ + return RegisterStartupProcedure (Procedure, ProcedureArguments); +} + +/** + When non-blocking execution of a procedure on an AP is invoked with Disp= atchProcedure, + via the use of a token, this function can be used to check for completio= n 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 o= n the same AP, this function + returns EFI_SUCESS. In this case the status returned by the procedure th= at executed on the AP is + returned in the token's Status field. If the procedure has not yet compl= eted, then this function + returns EFI_NOT_READY. + + When a non-blocking execution of a procedure is invoked with BroadcastPr= ocedure, 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 Bro= adcastProcedure + call. If the procedure is complete on all broadcast APs this function re= turns 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 th= e first observed failure. + If the procedure has not yet completed on the broadcast APs, the functio= n 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 BroadcastProce= dure. + + @retval EFI_SUCCESS Procedure has completed. + @retval EFI_NOT_READY The Procedure has not completed. + @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL + @retval EFI_NOT_FOUND Token is not currently in use for a= non-blocking call + +**/ +EFI_STATUS +EFIAPI +SmmMpCheckForProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token + ) +{ + if (Token =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IsCurrentToken ((UINTN)-1, (SPIN_LOCK *)Token)) { + return EFI_NOT_FOUND; + } + + return IsApReady ((SPIN_LOCK *)Token); +} + +/** + When a non-blocking execution of a procedure on an AP is invoked via Dis= patchProcedure, + this function will block the caller until the remote procedure has compl= eted on the designated AP. + The non-blocking procedure invocation is identified by the Token paramet= er, which must match the + token that used when DispatchProcedure was called. Upon completion the s= tatus returned by + the procedure that executed on the AP is used to update the token's Stat= us field. + + When a non-blocking execution of a procedure on an AP is invoked via Bro= adcastProcedure + this function will block the caller until the remote procedure has compl= eted on all of the APs that + entered MM. The non-blocking procedure invocation is identified by the T= oken 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 exec= utions 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 BroadcastProce= dure. + + @retval EFI_SUCCESS Procedure has completed. + @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL + @retval EFI_NOT_FOUND Token is not currently in use for a= non-blocking call + +**/ +EFI_STATUS +EFIAPI +SmmMpWaitForProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token + ) +{ + EFI_STATUS Status; + + do { + Status =3D SmmMpCheckForProcedure (This, Token); + } while (Status =3D=3D EFI_NOT_READY); + + return Status; +} + diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h b/UefiCpuPkg/PiSmmCpuDxeSmm/= SmmMp.h new file mode 100644 index 0000000000..e0d823a4b1 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h @@ -0,0 +1,286 @@ +/** @file +Include file for SMM MP protocol implementation. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMM_MP_PROTOCOL_H_ +#define _SMM_MP_PROTOCOL_H_ + +// +// SMM MP Protocol function prototypes. +// + +/** + Service to retrieves the number of logical processor in the platform. + + @param[in] This The EFI_MM_MP_PROTOCOL instance. + @param[out] NumberOfProcessors Pointer to the total number of logical p= rocessors in the system, + including the BSP and all APs. + + @retval EFI_SUCCESS The number of processors was retrieved s= uccessfully + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL +**/ + +EFI_STATUS +EFIAPI +SmmMpGetNumberOfProcessors ( + IN CONST EFI_MM_MP_PROTOCOL *This, + OUT UINTN *NumberOfProcessors + ); + + +/** + This service allows the caller to invoke a procedure one of the applicat= ion processors (AP). This + function uses an optional token parameter to support blocking and non-bl= ocking modes. If the token + is passed into the call, the function will operate in a non-blocking fas= hion 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 r= un on the designated target + AP of the system. Type EFI_AP_PROC= EDURE2 is defined below in + related definitions. + @param[in] CpuNumber The zero-based index of the proces= sor number of the target + AP, on which the code stream is su= pposed to run. If the number + points to the calling processor th= en it will not run the + supplied code. + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for this AP to + finish execution of Procedure, eit= her for blocking or + non-blocking mode. Zero means infi= nity. If the timeout + expires before this AP returns fro= m Procedure, then Procedure + on the AP is terminated. If the ti= meout 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 WaitForProcedu= re. + Note that timeout support is optio= nal. Whether an + implementation supports this featu= re, can be determined via + the Attributes data member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 exe= cution on the target AP, or with + EFI_TIMEOUT if the Procedure fails= to complete within the optional + timeout. The implementation will u= pdate this variable with + EFI_NOT_READY prior to starting Pr= ocedure on the target AP. + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the target AP. + In the non-blocking case this indi= cates that the procedure has + been successfully scheduled for ex= ecution on the target AP. + @retval EFI_INVALID_PARAMETER The input arguments are out of ran= ge. Either the target AP is the + caller of the function, or the Pro= cedure 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 anothe= r procedure + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before the specified AP + has finished + @retval EFI_OUT_OF_RESOURCES Could not allocate a required reso= urce. + +**/ +EFI_STATUS +EFIAPI +SmmMpDispatchProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN CpuNumber, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus + ); + +/** + This service allows the caller to invoke a procedure on all running appl= ication processors (AP) + except the caller. This function uses an optional token parameter to sup= port blocking and + nonblocking modes. If the token is passed into the call, the function wi= ll 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 micros= econds for the APs to finish + execution of Procedure, either for= blocking or non-blocking mode. + Zero means infinity. If the timeou= t expires before all APs return + from Procedure, then Procedure on = the failed APs is terminated. If + the timeout expires in blocking mo= de, the call returns EFI_TIMEOUT. + If the timeout expires in non-bloc= king mode, the timeout determined + can be through CheckOnProcedure or= WaitForProcedure. + Note that timeout support is optio= nal. Whether an implementation + supports this feature can be deter= mined via the Attributes data + member. + @param[in,out] ProcedureArguments Allows the caller to pass a list o= f parameters to the code + that is run by the AP. It is an op= tional common mailbox + between APs and the caller to shar= e information. + @param[in,out] Token This is parameter is broken into t= wo 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 comple= ted the procedure. If the + token is not NULL, the call will r= eturn immediately. The caller + can check whether the procedure ha= s completed with + CheckOnProcedure or WaitForProcedu= re. + 2.Token->Status The implementation= updates the address pointed + at by this variable with the statu= s 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 thi= s 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 particip= ated in the broadcast. This + parameter if used provides the bas= e 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 Ge= tNumberOfProcessors function. + As mentioned above, the broadcast = may not include every processor + in the system. Some implementation= s may exclude processors that + have been powered down in such a w= ay that they are not responsive + to interrupts. Additionally the br= oadcast excludes the processor + which is making the BroadcastProce= dure call. For every excluded + processor, the array entry must co= ntain a value of EFI_NOT_STARTED + + @retval EFI_SUCCESS In the blocking case, this indicat= es that Procedure has completed + execution on the APs. + In the non-blocking case this indi= cates that the procedure has + been successfully scheduled for ex= ecution 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 anothe= r procedure + @retval EFI_TIMEOUT In blocking mode, the timeout expi= red before the specified AP + has finished + @retval EFI_OUT_OF_RESOURCES Could not allocate a required reso= urce. + +**/ +EFI_STATUS +EFIAPI +SmmMpBroadcastProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE2 Procedure, + IN UINTN TimeoutInMicroseconds, + IN OUT VOID *ProcedureArguments OPTIONAL, + IN OUT MM_COMPLETION *Token, + IN OUT EFI_STATUS *CPUStatus + ); + + +/** + This service allows the caller to set a startup procedure that will be e= xecuted when an AP powers + up from a state where core configuration and context is lost. The proced= ure is execution has the + following properties: + 1. The procedure executes before the processor is handed over to the ope= rating system. + 2. All processors execute the same startup procedure. + 3. The procedure may run in parallel with other procedures invoked throu= gh 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_PROCEDUR= E is defined below in Volume 2 + with the related definitions of + EFI_MP_SERVICES_PROTOCOL.StartupAll= APs. + 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 co= mmon mailbox between APs and + the caller to share information + + @retval EFI_SUCCESS The Procedure has been set successf= ully. + @retval EFI_INVALID_PARAMETER The Procedure is NULL but Procedure= Arguments not NULL. +**/ +EFI_STATUS +EFIAPI +SmmMpSetStartupProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN OUT VOID *ProcedureArguments OPTIONAL + ); + +/** + When non-blocking execution of a procedure on an AP is invoked with Disp= atchProcedure, + via the use of a token, this function can be used to check for completio= n 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 o= n the same AP, this function + returns EFI_SUCESS. In this case the status returned by the procedure th= at executed on the AP is + returned in the token's Status field. If the procedure has not yet compl= eted, then this function + returns EFI_NOT_READY. + + When a non-blocking execution of a procedure is invoked with BroadcastPr= ocedure, 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 Bro= adcastProcedure + call. If the procedure is complete on all broadcast APs this function re= turns 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 th= e first observed failure. + If the procedure has not yet completed on the broadcast APs, the functio= n 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 BroadcastProce= dure. + + @retval EFI_SUCCESS Procedure has completed. + @retval EFI_NOT_READY The Procedure has not completed. + @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL + @retval EFI_NOT_FOUND Token is not currently in use for a= non-blocking call + +**/ +EFI_STATUS +EFIAPI +SmmMpCheckForProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token + ); + +/** + When a non-blocking execution of a procedure on an AP is invoked via Dis= patchProcedure, + this function will block the caller until the remote procedure has compl= eted on the designated AP. + The non-blocking procedure invocation is identified by the Token paramet= er, which must match the + token that used when DispatchProcedure was called. Upon completion the s= tatus returned by + the procedure that executed on the AP is used to update the token's Stat= us field. + + When a non-blocking execution of a procedure on an AP is invoked via Bro= adcastProcedure + this function will block the caller until the remote procedure has compl= eted on all of the APs that + entered MM. The non-blocking procedure invocation is identified by the T= oken 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 exec= utions 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 BroadcastProce= dure. + + @retval EFI_SUCCESS Procedure has completed. + @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL + @retval EFI_NOT_FOUND Token is not currently in use for a= non-blocking call + +**/ +EFI_STATUS +EFIAPI +SmmMpWaitForProcedure ( + IN CONST EFI_MM_MP_PROTOCOL *This, + IN MM_COMPLETION Token + ); + +#endif --=20 2.21.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#43189): https://edk2.groups.io/g/devel/message/43189 Mute This Topic: https://groups.io/mt/32293746/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-