From nobody Sat Feb 7 05:56:34 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+112957+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+112957+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1703757976; cv=none; d=zohomail.com; s=zohoarc; b=DENanX5be0FDtqdLnFbx8RaMa+g4ME+AOiDo27Cbd1uVFrZ0hpV3QpAPDoPJzzpiokzxZ/Q97le89EZC3iX9UVZ1yhJTTd7FbNNvSePoe+h15eUVAKn3OA8eUJC81XySzW9RTvgDdP4EOY2OpA+BQuFtI+y6QYj+ULXB5vYnajw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1703757976; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=hF//UwnKc3fPB9rZkUaBPB15zNM1INq46LV3dajNWQM=; b=GLWzPIG3FYP9aXmCiIc+OGdPCjPkGR/4eODMKONjiloq6m6s16OhLrjPcOxRKVyTjEskb4JrJ6KQOizSKogD+zc6hyqzNgok/bs014EWLXEKtxLcuEP8Y0//S9/3By01Dnn4pfgLfkLYewbFpgM9DzuklA3+/7/nefxW8r6Pj0g= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+112957+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1703757976404548.8116568886427; Thu, 28 Dec 2023 02:06:16 -0800 (PST) Return-Path: DKIM-Signature: a=rsa-sha256; bh=p6gUVd0PqgLVgBf8Qcqjp/ABHdQaaqUiVCkOL3UzSnU=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1703757976; v=1; b=nxug/Q7tBK6Mo4NKJw3M+mOeqUpt2MrTP+XpEm0Aixgw5JD2++bsyDX6bBKhepaiPQiOyaYR TgU3T0RglF/UYpQV3owt5NGBno4klXBrSnkW5+CdbTbHkJNuZXowSPbBetBYORtVkcj2tlYLtsj lutglHD55GbFvsA4BBfP2OME= X-Received: by 127.0.0.2 with SMTP id fFAuYY1788612xegTQw5TM9t; Thu, 28 Dec 2023 02:06:16 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.120291.1703757974193370150 for ; Thu, 28 Dec 2023 02:06:15 -0800 X-Received: from loongson.cn (unknown [10.2.9.245]) by gateway (Coremail) with SMTP id _____8CxbeuTSI1l_wIAAA--.49S3; Thu, 28 Dec 2023 18:06:11 +0800 (CST) X-Received: from code-server.gen (unknown [10.2.9.245]) by localhost.localdomain (Coremail) with SMTP id AQAAf8BxC76SSI1lygQOAA--.19802S2; Thu, 28 Dec 2023 18:06:10 +0800 (CST) From: "Chao Li" To: devel@edk2.groups.io Cc: Eric Dong , Ray Ni , Rahul Kumar , Gerd Hoffmann Subject: [edk2-devel] [PATCH v5 14/36] UefiCpuPkg: Add multiprocessor library for LoongArch64 Date: Thu, 28 Dec 2023 18:06:09 +0800 Message-Id: <20231228100609.1765491-1-lichao@loongson.cn> In-Reply-To: <20231228100351.1756165-1-lichao@loongson.cn> References: <20231228100351.1756165-1-lichao@loongson.cn> MIME-Version: 1.0 X-CM-TRANSID: AQAAf8BxC76SSI1lygQOAA--.19802S2 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQATCGWM2y8KPQAYso X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== Precedence: Bulk List-Subscribe: List-Help: 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,lichao@loongson.cn List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: MFOaPCH2uJ7GHIc0yr9BcY3nx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1703757977841100003 Content-Type: text/plain; charset="utf-8" Added a new library named LoongArch64MpInitLib. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4584 Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Signed-off-by: Chao Li Acked-by: Ray Ni --- .../LoongArch64MpInitLib/DxeMpInitLib.inf | 45 + .../LoongArch64MpInitLib/DxeMpInitLib.uni | 15 + .../Library/LoongArch64MpInitLib/DxeMpLib.c | 480 +++++ .../Library/LoongArch64MpInitLib/MpLib.c | 1596 +++++++++++++++++ .../Library/LoongArch64MpInitLib/MpLib.h | 361 ++++ .../LoongArch64MpInitLib/PeiMpInitLib.inf | 37 + .../LoongArch64MpInitLib/PeiMpInitLib.uni | 15 + .../Library/LoongArch64MpInitLib/PeiMpLib.c | 404 +++++ UefiCpuPkg/UefiCpuPkg.dsc | 2 + 9 files changed, 2955 insertions(+) create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf b/Uef= iCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf new file mode 100644 index 0000000000..519af41209 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf @@ -0,0 +1,45 @@ +## @file +# LoongArch64 MP initialize support functions for DXE phase. +# +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION =3D 1.29 + BASE_NAME =3D DxeMpInitLib + MODULE_UNI_FILE =3D DxeMpInitLib.uni + FILE_GUID =3D C3B9ACAA-B67C-D3E0-E70D-7982B6EA2931 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.1 + LIBRARY_CLASS =3D MpInitLib|DXE_DRIVER + +[Sources.common] + DxeMpLib.c + MpLib.c + MpLib.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + CpuLib + DebugAgentLib + HobLib + MemoryAllocationLib + SynchronizationLib + TimerLib + UefiLib + +[Protocols] + gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## C= ONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## C= ONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## C= ONSUMES diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni b/Uef= iCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni new file mode 100644 index 0000000000..c1c67291a6 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni @@ -0,0 +1,15 @@ +// /** @file +// MP Initialize Library instance for DXE driver. +// +// MP Initialize Library instance for DXE driver. +// +// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Lib= rary instance for DXE driver." + +#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Lib= rary instance for DXE driver." diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c b/UefiCpuPk= g/Library/LoongArch64MpInitLib/DxeMpLib.c new file mode 100644 index 0000000000..739da77e32 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c @@ -0,0 +1,480 @@ +/** @file + LoongArch64 MP initialize support functions for DXE phase. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" + +#include +#include +#include + +#include + +CPU_MP_DATA *mCpuMpData =3D NULL; +EFI_EVENT mCheckAllApsEvent =3D NULL; +volatile BOOLEAN mStopCheckAllApsStatus =3D TRUE; + +/** + Enable Debug Agent to support source debugging on AP function. + +**/ +VOID +EnableDebugAgent ( + VOID + ) +{ + // + // Initialize Debug Agent to support source level debug in DXE phase + // + InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL); +} + +/** + Get the pointer to CPU MP Data structure. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpData ( + VOID + ) +{ + ASSERT (mCpuMpData !=3D NULL); + return mCpuMpData; +} + +/** + Save the pointer to CPU MP Data structure. + + @param[in] CpuMpData The pointer to CPU MP Data structure will be saved. +**/ +VOID +SaveCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + mCpuMpData =3D CpuMpData; +} + +/** + Get available EfiBootServicesCode memory below 4GB by specified size. + + This buffer is required to safely transfer AP from real address mode to + protected mode or long mode, due to the fact that the buffer returned by + GetWakeupBuffer() may be marked as non-executable. + + @param[in] BufferSize Wakeup transition buffer size. + + @retval other Return wakeup transition buffer address below 4GB. + @retval 0 Cannot find free memory below 4GB. +**/ +UINTN +GetModeTransitionBuffer ( + IN UINTN BufferSize + ) +{ + return 0; +} + +/** + Checks APs status and updates APs status if needed. + +**/ +VOID +CheckAndUpdateApsStatus ( + VOID + ) +{ + UINTN ProcessorNumber; + EFI_STATUS Status; + CPU_MP_DATA *CpuMpData; + + CpuMpData =3D GetCpuMpData (); + + // + // First, check whether pending StartupAllAPs() exists. + // + if (CpuMpData->WaitEvent !=3D NULL) { + Status =3D CheckAllAPs (); + // + // If all APs finish for StartupAllAPs(), signal the WaitEvent for it. + // + if (Status !=3D EFI_NOT_READY) { + Status =3D gBS->SignalEvent (CpuMpData->WaitEvent); + CpuMpData->WaitEvent =3D NULL; + } + } + + // + // Second, check whether pending StartupThisAPs() callings exist. + // + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; Proce= ssorNumber++) { + if (CpuMpData->CpuData[ProcessorNumber].WaitEvent =3D=3D NULL) { + continue; + } + + Status =3D CheckThisAP (ProcessorNumber); + + if (Status !=3D EFI_NOT_READY) { + gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent); + CpuMpData->CpuData[ProcessorNumber].WaitEvent =3D NULL; + } + } +} + +/** + Checks APs' status periodically. + + This function is triggered by timer periodically to check the + state of APs for StartupAllAPs() and StartupThisAP() executed + in non-blocking mode. + + @param[in] Event Event triggered. + @param[in] Context Parameter passed with the event. + +**/ +VOID +EFIAPI +CheckApsStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // If CheckApsStatus() is not stopped, otherwise return immediately. + // + if (!mStopCheckAllApsStatus) { + CheckAndUpdateApsStatus (); + } +} + +/** + Initialize global data for MP support. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +InitMpGlobalData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + EFI_STATUS Status; + + SaveCpuMpData (CpuMpData); + + Status =3D gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + CheckApsStatus, + NULL, + &mCheckAllApsEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Set timer to check all APs status. + // + Status =3D gBS->SetTimer ( + mCheckAllApsEvent, + TimerPeriodic, + EFI_TIMER_PERIOD_MICROSECONDS ( + PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds) + ) + ); + ASSERT_EFI_ERROR (Status); +} + +/** + This service executes 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. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs ex= ecute + the function specified by Procedure = one by + one, in ascending order of processor= handle + number. If FALSE, then all the enab= led APs + execute the function specified by Pr= ocedure + simultaneously. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until all A= Ps finish + or TimeoutInMicroSeconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on all the e= nabled + APs, and go on executing immediately= . If + all return from Procedure, or Timeou= tInMicroSeconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + APs to return from Procedure, either= for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + all APs return from Procedure, then = Procedure + on the failed APs is terminated. All= enabled + APs are available for next function = assigned + by MpInitLibStartupAllAPs() or + MPInitLibStartupThisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. = Otherwise, + if all APs finish successfully, then= its + content is set to NULL. If not all A= Ps + finish before timeout expires, then = its + content is set to address of the buf= fer + holding handle numbers of the failed= APs. + The buffer is allocated by MP Initia= lization + library, and it's the caller's respo= nsibility to + free the buffer with FreePool() serv= ice. + In blocking mode, it is ready for co= nsumption + when the call returns. In non-blocki= ng mode, + it is ready when WaitEvent is signal= ed. The + list of failed CPU is terminated by + END_OF_CPU_LIST. + + @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 EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mo= de is not + supported. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupAllAPs ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Temporarily stop checkAllApsStatus for avoid resource dead-lock. + // + mStopCheckAllApsStatus =3D TRUE; + + Status =3D StartupAllCPUsWorker ( + Procedure, + SingleThread, + TRUE, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); + + // + // Start checkAllApsStatus + // + mStopCheckAllApsStatus =3D FALSE; + + return Status; +} + +/** + This service lets the caller get one enabled AP to execute a caller-prov= ided + function. + + @param[in] Procedure A pointer to the function to be run = on the + designated AP of the system. See type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The ran= ge is + from 0 to the total number of logical + processors minus 1. The total number= of + logical processors can be retrieved = by + MpInitLibGetNumberOfProcessors(). + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until this = AP finish + or TimeoutInMicroSeconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on this AP, + and go on executing immediately. If = this AP + return from Procedure or TimeoutInMi= croSeconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + this AP to finish this Procedure, ei= ther for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + this AP returns from Procedure, then= Procedure + on the AP is terminated. The + AP is available for next function as= signed + by MpInitLibStartupAllAPs() or + MpInitLibStartupThisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = on the + specified AP. + @param[out] Finished If NULL, this parameter is ignored. = In + blocking mode, this parameter is ign= ored. + In non-blocking mode, if AP returns = from + Procedure before the timeout expires= , its + content is set to TRUE. Otherwise, t= he + value is set to FALSE. The caller can + determine if the AP returned from Pr= ocedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished = before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has b= een + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mo= de is not + supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or dis= abled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupThisAP ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // temporarily stop checkAllApsStatus for avoid resource dead-lock. + // + mStopCheckAllApsStatus =3D TRUE; + + Status =3D StartupThisAPWorker ( + Procedure, + ProcessorNumber, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + Finished + ); + + mStopCheckAllApsStatus =3D FALSE; + + return Status; +} + +/** + This service switches the requested AP to be the BSP from that point onw= ard. + This service changes the BSP for all purposes. This call can only be per= formed + by the current BSP. + + @param[in] ProcessorNumber The handle number of AP that is to become t= he new + BSP. The range is from 0 to the total numbe= r of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + MpInitLibGetNumberOfProcessors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as= an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed pr= ior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BS= P or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibSwitchBSP ( + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This service lets the caller enable or disable an AP from this point onw= ard. + This service may only be called from the BSP. + + @param[in] ProcessorNumber The handle number of AP. + The range is from 0 to the total number of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + MpInitLibGetNumberOfProcessors(). + @param[in] EnableAP Specifies the new state for the processor f= or + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that spec= ifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo()= . Only + the PROCESSOR_HEALTH_STATUS_BIT is used. Al= l other + bits are ignored. If it is NULL, this para= meter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled= successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be co= mpleted + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not suppo= rted. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by P= rocessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibEnableDisableAP ( + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c b/UefiCpuPkg/L= ibrary/LoongArch64MpInitLib/MpLib.c new file mode 100644 index 0000000000..b7d859050e --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c @@ -0,0 +1,1596 @@ +/** @file + LoongArch64 CPU MP Initialize Library common functions. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" + +#include +#include + +EFI_GUID mCpuInitMpLibHobGuid =3D CPU_INIT_MP_LIB_HOB_GUID; +EFI_GUID mProcessorResourceHobGuid =3D PROCESSOR_RESOURCE_HOB_GUID; + +/** + Get the Application Processors state. + + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP + + @return The AP status +**/ +CPU_STATE +GetApState ( + IN CPU_AP_DATA *CpuData + ) +{ + return CpuData->State; +} + +/** + Set the Application Processors state. + + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP + @param[in] State The AP status +**/ +VOID +SetApState ( + IN CPU_AP_DATA *CpuData, + IN CPU_STATE State + ) +{ + AcquireSpinLock (&CpuData->ApLock); + CpuData->State =3D State; + ReleaseSpinLock (&CpuData->ApLock); +} + +/** + Get APIC ID of the executing processor. + + @return 32-bit APIC ID of the executing processor. +**/ +UINT32 +GetApicId ( + VOID + ) +{ + UINTN CpuNum; + + CpuNum =3D CsrRead (LOONGARCH_CSR_CPUNUM); + + return CpuNum & 0x3ff; +} + +/** + Find the current Processor number by APIC ID. + + @param[in] CpuMpData Pointer to PEI CPU MP Data + @param[out] ProcessorNumber Return the pocessor number found + + @retval EFI_SUCCESS ProcessorNumber is found and returned. + @retval EFI_NOT_FOUND ProcessorNumber is not found. +**/ +EFI_STATUS +GetProcessorNumber ( + IN CPU_MP_DATA *CpuMpData, + OUT UINTN *ProcessorNumber + ) +{ + UINTN TotalProcessorNumber; + UINTN Index; + CPU_INFO_IN_HOB *CpuInfoInHob; + + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + + TotalProcessorNumber =3D CpuMpData->CpuCount; + for (Index =3D 0; Index < TotalProcessorNumber; Index++) { + if (CpuInfoInHob[Index].ApicId =3D=3D GetApicId ()) { + *ProcessorNumber =3D Index; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Sort the APIC ID of all processors. + + This function sorts the APIC ID of all processors so that processor numb= er is + assigned in the ascending order of APIC ID which eases MP debugging. + + @param[in] CpuMpData Pointer to PEI CPU MP Data +**/ +VOID +SortApicId ( + IN CPU_MP_DATA *CpuMpData + ) +{ + UINTN Index1; + UINTN Index2; + UINTN Index3; + UINT32 ApicId; + CPU_INFO_IN_HOB CpuInfo; + UINT32 ApCount; + CPU_INFO_IN_HOB *CpuInfoInHob; + volatile UINT32 *StartupApSignal; + + ApCount =3D CpuMpData->CpuCount - 1; + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + if (ApCount !=3D 0) { + for (Index1 =3D 0; Index1 < ApCount; Index1++) { + Index3 =3D Index1; + // + // Sort key is the hardware default APIC ID + // + ApicId =3D CpuInfoInHob[Index1].ApicId; + for (Index2 =3D Index1 + 1; Index2 <=3D ApCount; Index2++) { + if (ApicId > CpuInfoInHob[Index2].ApicId) { + Index3 =3D Index2; + ApicId =3D CpuInfoInHob[Index2].ApicId; + } + } + + if (Index3 !=3D Index1) { + CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB)= ); + CopyMem ( + &CpuInfoInHob[Index3], + &CpuInfoInHob[Index1], + sizeof (CPU_INFO_IN_HOB) + ); + CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB)= ); + + // + // Also exchange the StartupApSignal. + // + StartupApSignal =3D CpuMpData->CpuData[= Index3].StartupApSignal; + CpuMpData->CpuData[Index3].StartupApSignal =3D + CpuMpData->CpuData[Index1].StartupApSignal; + CpuMpData->CpuData[Index1].StartupApSignal =3D StartupApSignal; + } + } + + // + // Get the processor number for the BSP + // + ApicId =3D GetApicId (); + for (Index1 =3D 0; Index1 < CpuMpData->CpuCount; Index1++) { + if (CpuInfoInHob[Index1].ApicId =3D=3D ApicId) { + CpuMpData->BspNumber =3D (UINT32)Index1; + break; + } + } + } +} + +/** + Get pointer to Processor Resource Data structure from GUIDd HOB. + + @return The pointer to Processor Resource Data structure. +**/ +PROCESSOR_RESOURCE_DATA * +GetProcessorResourceDataFromGuidedHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + VOID *DataInHob; + PROCESSOR_RESOURCE_DATA *ResourceData; + + ResourceData =3D NULL; + GuidHob =3D GetFirstGuidHob (&mProcessorResourceHobGuid); + if (GuidHob !=3D NULL) { + DataInHob =3D GET_GUID_HOB_DATA (GuidHob); + ResourceData =3D (PROCESSOR_RESOURCE_DATA *)(*(UINTN *)DataInHob); + } + + return ResourceData; +} + +/** + This function will get CPU count in the system. + + @param[in] CpuMpData Pointer to PEI CPU MP Data + + @return CPU count detected +**/ +UINTN +CollectProcessorCount ( + IN CPU_MP_DATA *CpuMpData + ) +{ + PROCESSOR_RESOURCE_DATA *ProcessorResourceData; + + ProcessorResourceData =3D NULL; + + // + // Set the default loop mode for APs. + // + CpuMpData->ApLoopMode =3D ApInRunLoop; + + // + // Beacuse LoongArch does not have SIPI now, the APIC ID must be obtaine= d before + // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 Mail= box0 is used + // as the first broadcast method to wake up all APs, and all of APs will= read NODE0 + // Core0 Mailbox0 in an infinit loop. + // + ProcessorResourceData =3D GetProcessorResourceDataFromGuidedHob (); + + if (ProcessorResourceData !=3D NULL) { + CpuMpData->ApLoopMode =3D ApInHltLoop; + CpuMpData->CpuCount =3D ProcessorResourceData->CpuCount; + CpuMpData->CpuInfoInHob =3D (UINTN)(ProcessorResourceData->CpuInfoInHo= b); + } + + // + // Send 1st broadcast IPI to APs to wakeup APs + // + CpuMpData->InitFlag =3D ApInitConfig; + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, FALSE); + CpuMpData->InitFlag =3D ApInitDone; + + // + // When InitFlag =3D=3D ApInitConfig, WakeUpAP () guarantees all APs are= checked in. + // FinishedCount is the number of check-in APs. + // + CpuMpData->CpuCount =3D CpuMpData->FinishedCount + 1; + ASSERT (CpuMpData->CpuCount <=3D PcdGet32 (PcdCpuMaxLogicalProcessorNumb= er)); + + // + // Wait for all APs finished the initialization + // + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { + CpuPause (); + } + + // + // Sort BSP/Aps by CPU APIC ID in ascending order + // + SortApicId (CpuMpData); + + DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpD= ata->CpuCount)); + + return CpuMpData->CpuCount; +} + +/** + Initialize CPU AP Data when AP is wakeup at the first time. + + @param[in, out] CpuMpData Pointer to PEI CPU MP Data + @param[in] ProcessorNumber The handle number of processor + @param[in] BistData Processor BIST data + +**/ +VOID +InitializeApData ( + IN OUT CPU_MP_DATA *CpuMpData, + IN UINTN ProcessorNumber, + IN UINT32 BistData + ) +{ + CPU_INFO_IN_HOB *CpuInfoInHob; + + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)(CpuMpData->CpuInfoInHob); + + CpuInfoInHob[ProcessorNumber].ApicId =3D GetApicId (); + CpuInfoInHob[ProcessorNumber].Health =3D BistData; + + CpuMpData->CpuData[ProcessorNumber].Waiting =3D FALSE; + CpuMpData->CpuData[ProcessorNumber].CpuHealthy =3D (BistData =3D=3D 0) ?= TRUE : FALSE; + + InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock); + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle); +} + +/** + Ap wake up function. + + Ap will wait for scheduling here, and if the IPI or wake-up signal is en= abled, + Ap will preform the corresponding functions. + + @param[in] ApIndex Number of current executing AP + @param[in] ExchangeInfo Pointer to the MP exchange info buffer +**/ +VOID +EFIAPI +ApWakeupFunction ( + IN UINTN ApIndex, + IN MP_CPU_EXCHANGE_INFO *ExchangeInfo + ) +{ + CPU_MP_DATA *CpuMpData; + UINTN ProcessorNumber; + volatile UINT32 *ApStartupSignalBuffer; + EFI_AP_PROCEDURE Procedure; + VOID *Parameter; + + CpuMpData =3D ExchangeInfo->CpuMpData; + + while (TRUE) { + if (CpuMpData->InitFlag =3D=3D ApInitConfig) { + ProcessorNumber =3D ApIndex; + // + // If the AP can running to here, then the BIST must be zero. + // + InitializeApData (CpuMpData, ProcessorNumber, 0); + ApStartupSignalBuffer =3D CpuMpData->CpuData[ProcessorNumber].Startu= pApSignal; + } else { + // + // Execute AP function if AP is ready + // + GetProcessorNumber (CpuMpData, &ProcessorNumber); + + // + // Clear AP start-up signal when AP waken up + // + ApStartupSignalBuffer =3D CpuMpData->CpuData[ProcessorNumber].Startu= pApSignal; + InterlockedCompareExchange32 ( + (UINT32 *)ApStartupSignalBuffer, + WAKEUP_AP_SIGNAL, + 0 + ); + + // + // Invoke AP function here + // + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D CpuStat= eReady) { + Procedure =3D (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber= ].ApFunction; + Parameter =3D (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFuncti= onArgument; + if (Procedure !=3D NULL) { + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy); + Procedure (Parameter); + } + + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished= ); + } + } + + // + // Updates the finished count + // + InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount); + + while (TRUE) { + // + // Clean per-core mail box registers. + // + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0); + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF1, 0x0); + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF2, 0x0); + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0); + + // + // Enable IPI interrupt and global interrupt + // + EnableLocalInterrupts (1 << 12); + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFULL); + EnableInterrupts (); + + // + // Ap entry HLT mode + // + CpuSleep (); + + // + // Disable global interrupts when wake up + // + DisableInterrupts (); + + // + // Update CpuMpData + // + if (CpuMpData !=3D ExchangeInfo->CpuMpData) { + CpuMpData =3D ExchangeInfo->CpuMpData; + GetProcessorNumber (CpuMpData, &ProcessorNumber); + ApStartupSignalBuffer =3D CpuMpData->CpuData[ProcessorNumber].Star= tupApSignal; + } + + // + // Break out of the loop if wake up signal is not NULL. + // + if (*ApStartupSignalBuffer =3D=3D WAKEUP_AP_SIGNAL) { + break; + } + } + } +} + +/** + Calculate timeout value and return the current performance counter value. + + Calculate the number of performance counter ticks required for a timeout. + If TimeoutInMicroseconds is 0, return value is also 0, which is recogniz= ed + as infinity. + + @param[in] TimeoutInMicroseconds Timeout value in microseconds. + @param[out] CurrentTime Returns the current value of the per= formance counter. + + @return Expected time stamp counter for timeout. + If TimeoutInMicroseconds is 0, return value is also 0, which is = recognized + as infinity. + +**/ +UINT64 +CalculateTimeout ( + IN UINTN TimeoutInMicroseconds, + OUT UINT64 *CurrentTime + ) +{ + UINT64 TimeoutInSeconds; + UINT64 TimestampCounterFreq; + + // + // Read the current value of the performance counter + // + *CurrentTime =3D GetPerformanceCounter (); + + // + // If TimeoutInMicroseconds is 0, return value is also 0, which is recog= nized + // as infinity. + // + if (TimeoutInMicroseconds =3D=3D 0) { + return 0; + } + + // + // GetPerformanceCounterProperties () returns the timestamp counter's fr= equency + // in Hz. + // + TimestampCounterFreq =3D GetPerformanceCounterProperties (NULL, NULL); + + // + // Check the potential overflow before calculate the number of ticks for= the timeout value. + // + if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < Times= tampCounterFreq) { + // + // Convert microseconds into seconds if direct multiplication overflows + // + TimeoutInSeconds =3D DivU64x32 (TimeoutInMicroseconds, 1000000); + // + // Assertion if the final tick count exceeds MAX_UINT64 + // + ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >=3D T= imestampCounterFreq); + return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds); + } else { + // + // No overflow case, multiply the return value with TimeoutInMicroseco= nds and then divide + // it by 1,000,000, to get the number of ticks for the timeout value. + // + return DivU64x32 ( + MultU64x64 ( + TimestampCounterFreq, + TimeoutInMicroseconds + ), + 1000000 + ); + } +} + +/** + Checks whether timeout expires. + + Check whether the number of elapsed performance counter ticks required f= or + a timeout condition has been reached. + If Timeout is zero, which means infinity, return value is always FALSE. + + @param[in, out] PreviousTime On input, the value of the performance = counter + when it was last read. + On output, the current value of the perf= ormance + counter + @param[in] TotalTime The total amount of elapsed time in perf= ormance + counter ticks. + @param[in] Timeout The number of performance counter ticks = required + to reach a timeout condition. + + @retval TRUE A timeout condition has been reached. + @retval FALSE A timeout condition has not been reached. + +**/ +BOOLEAN +CheckTimeout ( + IN OUT UINT64 *PreviousTime, + IN UINT64 *TotalTime, + IN UINT64 Timeout + ) +{ + UINT64 Start; + UINT64 End; + UINT64 CurrentTime; + INT64 Delta; + INT64 Cycle; + + if (Timeout =3D=3D 0) { + return FALSE; + } + + GetPerformanceCounterProperties (&Start, &End); + Cycle =3D End - Start; + if (Cycle < 0) { + Cycle =3D -Cycle; + } + + Cycle++; + CurrentTime =3D GetPerformanceCounter (); + Delta =3D (INT64)(CurrentTime - *PreviousTime); + if (Start > End) { + Delta =3D -Delta; + } + + if (Delta < 0) { + Delta +=3D Cycle; + } + + *TotalTime +=3D Delta; + *PreviousTime =3D CurrentTime; + if (*TotalTime > Timeout) { + return TRUE; + } + + return FALSE; +} + +/** + Helper function that waits until the finished AP count reaches the speci= fied + limit, or the specified timeout elapses (whichever comes first). + + @param[in] CpuMpData Pointer to CPU MP Data. + @param[in] FinishedApLimit The number of finished APs to wait for. + @param[in] TimeLimit The number of microseconds to wait for. +**/ +VOID +TimedWaitForApFinish ( + IN CPU_MP_DATA *CpuMpData, + IN UINT32 FinishedApLimit, + IN UINT32 TimeLimit + ) +{ + // + // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0 + // "infinity", so check for (TimeLimit =3D=3D 0) explicitly. + // + if (TimeLimit =3D=3D 0) { + return; + } + + CpuMpData->TotalTime =3D 0; + CpuMpData->ExpectedTime =3D CalculateTimeout ( + TimeLimit, + &CpuMpData->CurrentTime + ); + while (CpuMpData->FinishedCount < FinishedApLimit && + !CheckTimeout ( + &CpuMpData->CurrentTime, + &CpuMpData->TotalTime, + CpuMpData->ExpectedTime + )) + { + CpuPause (); + } + + if (CpuMpData->FinishedCount >=3D FinishedApLimit) { + DEBUG (( + DEBUG_VERBOSE, + "%a: reached FinishedApLimit=3D%u in %Lu microseconds\n", + __FUNCTION__, + FinishedApLimit, + DivU64x64Remainder ( + MultU64x32 (CpuMpData->TotalTime, 1000000), + GetPerformanceCounterProperties (NULL, NULL), + NULL + ) + )); + } +} + +/** + Wait for AP wakeup and write AP start-up signal till AP is waken up. + + @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal +**/ +VOID +WaitApWakeup ( + IN volatile UINT32 *ApStartupSignalBuffer + ) +{ + // + // If AP is waken up, StartupApSignal should be cleared. + // Otherwise, write StartupApSignal again till AP waken up. + // + while (InterlockedCompareExchange32 ( + (UINT32 *)ApStartupSignalBuffer, + WAKEUP_AP_SIGNAL, + WAKEUP_AP_SIGNAL + ) !=3D 0) + { + CpuPause (); + } +} + +/** + This function will fill the exchange info structure. + + @param[in] CpuMpData Pointer to CPU MP Data + +**/ +VOID +FillExchangeInfoData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; + + if (!CpuMpData->MpCpuExchangeInfo) { + CpuMpData->MpCpuExchangeInfo =3D (MP_CPU_EXCHANGE_INFO *)AllocatePool = (sizeof (MP_CPU_EXCHANGE_INFO)); + } + + ExchangeInfo =3D CpuMpData->MpCpuExchangeInfo; + ExchangeInfo->CpuMpData =3D CpuMpData; +} + +/** + This function will be called by BSP to wakeup AP. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] Broadcast TRUE: Send broadcast IPI to all APs + FALSE: Send IPI to AP by ApicId + @param[in] ProcessorNumber The handle number of specified processor + @param[in] Procedure The function to be invoked by AP + @param[in] ProcedureArgument The argument to be passed into AP function + @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in br= oadcast mode. Currently not used on LoongArch. +**/ +VOID +WakeUpAP ( + IN CPU_MP_DATA *CpuMpData, + IN BOOLEAN Broadcast, + IN UINTN ProcessorNumber, + IN EFI_AP_PROCEDURE Procedure OPTIONAL, + IN VOID *ProcedureArgument OPTIONAL, + IN BOOLEAN WakeUpDisabledAps + ) +{ + volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; + UINTN Index; + CPU_AP_DATA *CpuData; + CPU_INFO_IN_HOB *CpuInfoInHob; + + CpuMpData->FinishedCount =3D 0; + + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + + if (CpuMpData->InitFlag !=3D ApInitDone) { + FillExchangeInfoData (CpuMpData); + } + + ExchangeInfo =3D CpuMpData->MpCpuExchangeInfo; + // + // If InitFlag is ApInitConfig, broadcasts all APs to initize themselves. + // + if (CpuMpData->InitFlag =3D=3D ApInitConfig) { + DEBUG ((EFI_D_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", __func__= , ApWakeupFunction, (UINTN)ExchangeInfo)); + if (CpuMpData->ApLoopMode =3D=3D ApInHltLoop) { + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { + if (Index !=3D CpuMpData->BspNumber) { + IoCsrWrite64 ( + LOONGARCH_IOCSR_MBUF_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (IOCSR_MBUF_SEND_BOX_HI (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + ((UINTN)(ExchangeInfo) & IOCSR_MBUF_SEND_H32_MASK)) + ); + IoCsrWrite64 ( + LOONGARCH_IOCSR_MBUF_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (IOCSR_MBUF_SEND_BOX_LO (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + ((UINTN)ExchangeInfo) << IOCSR_MBUF_SEND_BUF_SHIFT) + ); + + IoCsrWrite64 ( + LOONGARCH_IOCSR_MBUF_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (IOCSR_MBUF_SEND_BOX_HI (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + ((UINTN)(ApWakeupFunction) & IOCSR_MBUF_SEND_H32_MASK)) + ); + IoCsrWrite64 ( + LOONGARCH_IOCSR_MBUF_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (IOCSR_MBUF_SEND_BOX_LO (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + ((UINTN)ApWakeupFunction) << IOCSR_MBUF_SEND_BUF_SHIFT) + ); + + // + // Send IPI 4 interrupt to wake up APs. + // + IoCsrWrite64 ( + LOONGARCH_IOCSR_IPI_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + 0x2 // Bit 2 + ) + ); + } + } + } else { + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, (UINTN)ExchangeInfo); + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, (UINTN)ApWakeupFunction); + } + + TimedWaitForApFinish ( + CpuMpData, + PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1, + PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds) + ); + } else { + if (Broadcast) { + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { + if (Index !=3D CpuMpData->BspNumber) { + CpuData =3D &CpuMpData->CpuData[Index]; + if ((GetApState (CpuData) =3D=3D CpuStateDisabled) && !WakeUpDis= abledAps) { + continue; + } + + CpuData->ApFunction =3D (UINTN)Procedure; + CpuData->ApFunctionArgument =3D (UINTN)ProcedureArgument; + SetApState (CpuData, CpuStateReady); + *(UINT32 *)CpuData->StartupApSignal =3D WAKEUP_AP_SIGNAL; + + // + // Send IPI 4 interrupt to wake up APs. + // + IoCsrWrite64 ( + LOONGARCH_IOCSR_IPI_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) | + 0x2 // Bit 2 + ) + ); + } + } + + // + // Wait all APs waken up. + // + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { + CpuData =3D &CpuMpData->CpuData[Index]; + if (Index !=3D CpuMpData->BspNumber) { + WaitApWakeup (CpuData->StartupApSignal); + } + } + } else { + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + CpuData->ApFunction =3D (UINTN)Procedure; + CpuData->ApFunctionArgument =3D (UINTN)ProcedureArgument; + SetApState (CpuData, CpuStateReady); + // + // Wakeup specified AP + // + *(UINT32 *)CpuData->StartupApSignal =3D WAKEUP_AP_SIGNAL; + + // + // Send IPI 4 interrupt to wake up APs. + // + IoCsrWrite64 ( + LOONGARCH_IOCSR_IPI_SEND, + (IOCSR_MBUF_SEND_BLOCKING | + (CpuInfoInHob[ProcessorNumber].ApicId << IOCSR_MBUF_SEND_CPU_SHIF= T) | + 0x2 // Bit 2 + ) + ); + + // + // Wait specified AP waken up + // + WaitApWakeup (CpuData->StartupApSignal); + } + } +} + +/** + Searches for the next waiting AP. + + Search for the next AP that is put in waiting state by single-threaded S= tartupAllAPs(). + + @param[out] NextProcessorNumber Pointer to the processor number of the= next waiting AP. + + @retval EFI_SUCCESS The next waiting AP has been found. + @retval EFI_NOT_FOUND No waiting AP exists. + +**/ +EFI_STATUS +GetNextWaitingProcessorNumber ( + OUT UINTN *NextProcessorNumber + ) +{ + UINTN ProcessorNumber; + CPU_MP_DATA *CpuMpData; + + CpuMpData =3D GetCpuMpData (); + + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; Proce= ssorNumber++) { + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { + *NextProcessorNumber =3D ProcessorNumber; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** 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] ProcessorNumber The handle number of processor. + + @retval EFI_SUCCESS Specified AP has finished task assigned by= StartupThisAPs(). + @retval EFI_TIMEOUT The timeout expires. + @retval EFI_NOT_READY Specified AP has not finished task and tim= eout has not expired. +**/ +EFI_STATUS +CheckThisAP ( + IN UINTN ProcessorNumber + ) +{ + CPU_MP_DATA *CpuMpData; + CPU_AP_DATA *CpuData; + + CpuMpData =3D GetCpuMpData (); + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + + // + // If the AP finishes for StartupThisAP(), return EFI_SUCCESS. + // + if (GetApState (CpuData) =3D=3D CpuStateFinished) { + if (CpuData->Finished !=3D NULL) { + *(CpuData->Finished) =3D TRUE; + } + + SetApState (CpuData, CpuStateIdle); + return EFI_SUCCESS; + } else { + // + // If timeout expires for StartupThisAP(), report timeout. + // + if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData-= >ExpectedTime)) { + if (CpuData->Finished !=3D NULL) { + *(CpuData->Finished) =3D FALSE; + } + + return EFI_TIMEOUT; + } + } + + return EFI_NOT_READY; +} + +/** + Checks status of all APs. + + This function checks whether all APs have finished task assigned by Star= tupAllAPs(), + and whether timeout expires. + + @retval EFI_SUCCESS All APs have finished task assigned by Sta= rtupAllAPs(). + @retval EFI_TIMEOUT The timeout expires. + @retval EFI_NOT_READY APs have not finished task and timeout has= not expired. +**/ +EFI_STATUS +CheckAllAPs ( + VOID + ) +{ + UINTN ProcessorNumber; + UINTN NextProcessorNumber; + EFI_STATUS Status; + CPU_MP_DATA *CpuMpData; + CPU_AP_DATA *CpuData; + + CpuMpData =3D GetCpuMpData (); + + NextProcessorNumber =3D 0; + + // + // Go through all APs that are responsible for the StartupAllAPs(). + // + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; Proce= ssorNumber++) { + if (!CpuMpData->CpuData[ProcessorNumber].Waiting) { + continue; + } + + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + // + // Check the CPU state of AP. If it is CpuStateIdle, then the AP has f= inished its task. + // Only BSP and corresponding AP access this unit of CPU Data. This me= ans the AP will not modify the + // value of state after setting the it to CpuStateIdle, so BSP can saf= ely make use of its value. + // + if (GetApState (CpuData) =3D=3D CpuStateFinished) { + CpuMpData->RunningCount--; + CpuMpData->CpuData[ProcessorNumber].Waiting =3D FALSE; + SetApState (CpuData, CpuStateIdle); + + // + // If in Single Thread mode, then search for the next waiting AP for= execution. + // + if (CpuMpData->SingleThread) { + Status =3D GetNextWaitingProcessorNumber (&NextProcessorNumber); + + if (!EFI_ERROR (Status)) { + WakeUpAP ( + CpuMpData, + FALSE, + (UINT32)NextProcessorNumber, + CpuMpData->Procedure, + CpuMpData->ProcArguments, + TRUE + ); + } + } + } + } + + // + // If all APs finish, return EFI_SUCCESS. + // + if (CpuMpData->RunningCount =3D=3D 0) { + return EFI_SUCCESS; + } + + // + // If timeout expires, report timeout. + // + if (CheckTimeout ( + &CpuMpData->CurrentTime, + &CpuMpData->TotalTime, + CpuMpData->ExpectedTime + ) + ) + { + return EFI_TIMEOUT; + } + + return EFI_NOT_READY; +} + +/** + 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 ex= ecute + the function specified by Procedure = one by + one, in ascending order of processor= handle + number. If FALSE, then all the enab= led APs + execute the function specified by Pr= ocedure + simultaneously. + @param[in] ExcludeBsp Whether let BSP also trig this task. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds 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 A= Ps + finish before timeout expires, then = its + content is set to address of the buf= fer + 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 +StartupAllCPUsWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN BOOLEAN ExcludeBsp, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + EFI_STATUS Status; + CPU_MP_DATA *CpuMpData; + UINTN ProcessorCount; + UINTN ProcessorNumber; + UINTN CallerNumber; + CPU_AP_DATA *CpuData; + BOOLEAN HasEnabledAp; + CPU_STATE ApState; + + CpuMpData =3D GetCpuMpData (); + + if (FailedCpuList !=3D NULL) { + *FailedCpuList =3D NULL; + } + + if ((CpuMpData->CpuCount =3D=3D 1) && ExcludeBsp) { + return EFI_NOT_STARTED; + } + + if (Procedure =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether caller processor is BSP + // + MpInitLibWhoAmI (&CallerNumber); + if (CallerNumber !=3D CpuMpData->BspNumber) { + return EFI_DEVICE_ERROR; + } + + // + // Update AP state + // + CheckAndUpdateApsStatus (); + + ProcessorCount =3D CpuMpData->CpuCount; + HasEnabledAp =3D FALSE; + // + // Check whether all enabled APs are idle. + // If any enabled AP is not idle, return EFI_NOT_READY. + // + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; ProcessorN= umber++) { + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + if (ProcessorNumber !=3D CpuMpData->BspNumber) { + ApState =3D GetApState (CpuData); + if (ApState !=3D CpuStateDisabled) { + HasEnabledAp =3D TRUE; + if (ApState !=3D CpuStateIdle) { + // + // If any enabled APs are busy, return EFI_NOT_READY. + // + return EFI_NOT_READY; + } + } + } + } + + if (!HasEnabledAp && ExcludeBsp) { + // + // If no enabled AP exists and not include Bsp to do the procedure, re= turn EFI_NOT_STARTED. + // + return EFI_NOT_STARTED; + } + + CpuMpData->RunningCount =3D 0; + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; ProcessorN= umber++) { + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + CpuData->Waiting =3D FALSE; + if (ProcessorNumber !=3D CpuMpData->BspNumber) { + if (CpuData->State =3D=3D CpuStateIdle) { + // + // Mark this processor as responsible for current calling. + // + CpuData->Waiting =3D TRUE; + CpuMpData->RunningCount++; + } + } + } + + CpuMpData->Procedure =3D Procedure; + CpuMpData->ProcArguments =3D ProcedureArgument; + CpuMpData->SingleThread =3D SingleThread; + CpuMpData->FinishedCount =3D 0; + CpuMpData->ExpectedTime =3D CalculateTimeout ( + TimeoutInMicroseconds, + &CpuMpData->CurrentTime + ); + CpuMpData->TotalTime =3D 0; + CpuMpData->WaitEvent =3D WaitEvent; + + if (!SingleThread) { + WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE); + } else { + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; Processo= rNumber++) { + if (ProcessorNumber =3D=3D CallerNumber) { + continue; + } + + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureA= rgument, TRUE); + break; + } + } + } + + if (!ExcludeBsp) { + // + // Start BSP. + // + Procedure (ProcedureArgument); + } + + Status =3D EFI_SUCCESS; + if (WaitEvent =3D=3D NULL) { + do { + Status =3D CheckAllAPs (); + } while (Status =3D=3D EFI_NOT_READY); + } + + return Status; +} + +/** + Worker function to let the caller get one enabled AP to execute a caller= -provided + function. + + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds 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] Finished If AP returns from Procedure before = the + timeout expires, its content is set = to TRUE. + Otherwise, the value is set to FALSE. + + @retval EFI_SUCCESS In blocking mode, specified AP finished = before + the timeout expires. + @retval others Failed to Startup AP. + +**/ +EFI_STATUS +StartupThisAPWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + EFI_STATUS Status; + CPU_MP_DATA *CpuMpData; + CPU_AP_DATA *CpuData; + UINTN CallerNumber; + + CpuMpData =3D GetCpuMpData (); + + if (Finished !=3D NULL) { + *Finished =3D FALSE; + } + + // + // Check whether caller processor is BSP + // + MpInitLibWhoAmI (&CallerNumber); + if (CallerNumber !=3D CpuMpData->BspNumber) { + return EFI_DEVICE_ERROR; + } + + // + // Check whether processor with the handle specified by ProcessorNumber = exists + // + if (ProcessorNumber >=3D CpuMpData->CpuCount) { + return EFI_NOT_FOUND; + } + + // + // Check whether specified processor is BSP + // + if (ProcessorNumber =3D=3D CpuMpData->BspNumber) { + return EFI_INVALID_PARAMETER; + } + + // + // Check parameter Procedure + // + if (Procedure =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Update AP state + // + CheckAndUpdateApsStatus (); + + // + // Check whether specified AP is disabled + // + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D CpuStateDis= abled) { + return EFI_INVALID_PARAMETER; + } + + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; + CpuData->WaitEvent =3D WaitEvent; + CpuData->Finished =3D Finished; + CpuData->ExpectedTime =3D CalculateTimeout (TimeoutInMicroseconds, &CpuD= ata->CurrentTime); + CpuData->TotalTime =3D 0; + + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgumen= t, FALSE); + + // + // If WaitEvent is NULL, execute in blocking mode. + // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expi= res. + // + Status =3D EFI_SUCCESS; + if (WaitEvent =3D=3D NULL) { + do { + Status =3D CheckThisAP (ProcessorNumber); + } while (Status =3D=3D EFI_NOT_READY); + } + + return Status; +} + +/** + This service executes a caller provided function on all enabled CPUs. + + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + APs to return from Procedure, either= for + blocking or non-blocking mode. Zero = means + infinity. TimeoutInMicroseconds is i= gnored + for BSP. + @param[in] ProcedureArgument The parameter passed into Procedure = for + all APs. + + @retval EFI_SUCCESS In blocking mode, all CPUs have finished= before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been = dispatched + to all enabled CPUs. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupAllCPUs ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL + ) +{ + return StartupAllCPUsWorker ( + Procedure, + TRUE, + FALSE, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + NULL + ); +} + +/** + MP Initialize Library initialization. + + This service will allocate AP reset vector and wakeup all APs to do APs + initialization. + + This service must be invoked before all other MP Initialize Library + service are invoked. + + @retval EFI_SUCCESS MP initialization succeeds. + @retval Others MP initialization fails. + +**/ +EFI_STATUS +EFIAPI +MpInitLibInitialize ( + VOID + ) +{ + CPU_MP_DATA *OldCpuMpData; + CPU_INFO_IN_HOB *CpuInfoInHob; + UINT32 MaxLogicalProcessorNumber; + UINTN BufferSize; + UINTN MonitorBufferSize; + VOID *MpBuffer; + CPU_MP_DATA *CpuMpData; + UINTN Index; + + OldCpuMpData =3D GetCpuMpDataFromGuidedHob (); + if (OldCpuMpData =3D=3D NULL) { + MaxLogicalProcessorNumber =3D PcdGet32 (PcdCpuMaxLogicalProcessorNumbe= r); + } else { + MaxLogicalProcessorNumber =3D OldCpuMpData->CpuCount; + } + + ASSERT (MaxLogicalProcessorNumber !=3D 0); + + MonitorBufferSize =3D sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessorNum= ber; + + BufferSize =3D 0; + BufferSize +=3D MonitorBufferSize; + BufferSize +=3D sizeof (CPU_MP_DATA); + BufferSize +=3D (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLo= gicalProcessorNumber; + MpBuffer =3D AllocatePages (EFI_SIZE_TO_PAGES (BufferSize)); + ASSERT (MpBuffer !=3D NULL); + ZeroMem (MpBuffer, BufferSize); + + CpuMpData =3D (CPU_MP_DATA *)MpBuffer; + + CpuMpData->CpuCount =3D 1; + CpuMpData->BspNumber =3D 0; + CpuMpData->CpuData =3D (CPU_AP_DATA *)(CpuMpData + 1); + CpuMpData->CpuInfoInHob =3D (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogi= calProcessorNumber); + + InitializeSpinLock (&CpuMpData->MpLock); + + // + // Set BSP basic information + // + InitializeApData (CpuMpData, 0, 0); + + // + // Set up APs wakeup signal buffer + // + for (Index =3D 0; Index < MaxLogicalProcessorNumber; Index++) { + CpuMpData->CpuData[Index].StartupApSignal =3D + (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof (WA= KEUP_AP_SIGNAL) * Index)); + } + + if (OldCpuMpData =3D=3D NULL) { + if (MaxLogicalProcessorNumber > 1) { + // + // Wakeup all APs and calculate the processor count in system + // + CollectProcessorCount (CpuMpData); + } + } else { + // + // APs have been wakeup before, just get the CPU Information + // from HOB + // + CpuMpData->CpuCount =3D OldCpuMpData->CpuCount; + CpuMpData->BspNumber =3D OldCpuMpData->BspNumber; + CpuMpData->CpuInfoInHob =3D OldCpuMpData->CpuInfoInHob; + CpuMpData->MpCpuExchangeInfo =3D OldCpuMpData->MpCpuExchangeInfo; + + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { + InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock); + CpuMpData->CpuData[Index].CpuHealthy =3D (CpuInfoInHob[Index].Health= =3D=3D 0) ? TRUE : FALSE; + } + + if (CpuMpData->CpuCount > 1) { + // + // Only needs to use this flag for DXE phase to update the wake up + // buffer. Wakeup buffer allocated in PEI phase is no longer valid + // in DXE. + // + CpuMpData->InitFlag =3D ApInitReconfig; + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE); + + // + // Wait for all APs finished initialization + // + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { + CpuPause (); + } + + CpuMpData->InitFlag =3D ApInitDone; + } + + if (MaxLogicalProcessorNumber > 1) { + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { + SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); + } + } + } + + // + // Initialize global data for MP support + // + InitMpGlobalData (CpuMpData); + + return EFI_SUCCESS; +} + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where informat= ion for + the requested processor is deposited. + @param[out] HealthData Return processor health data. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist in the pl= atform. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetProcessorInfo ( + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer, + OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL + ) +{ + CPU_MP_DATA *CpuMpData; + UINTN CallerNumber; + CPU_INFO_IN_HOB *CpuInfoInHob; + + CpuMpData =3D GetCpuMpData (); + CpuInfoInHob =3D (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + + // + // Check whether caller processor is BSP + // + MpInitLibWhoAmI (&CallerNumber); + if (CallerNumber !=3D CpuMpData->BspNumber) { + return EFI_DEVICE_ERROR; + } + + if (ProcessorInfoBuffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ProcessorNumber >=3D CpuMpData->CpuCount) { + return EFI_NOT_FOUND; + } + + ProcessorInfoBuffer->ProcessorId =3D (UINT64)CpuInfoInHob[ProcessorNumbe= r].ApicId; + ProcessorInfoBuffer->StatusFlag =3D 0; + if (ProcessorNumber =3D=3D CpuMpData->BspNumber) { + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_AS_BSP_BIT; + } + + if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) { + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_HEALTH_STATUS_BIT; + } + + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D CpuStateDis= abled) { + ProcessorInfoBuffer->StatusFlag &=3D ~PROCESSOR_ENABLED_BIT; + } else { + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_ENABLED_BIT; + } + + if (HealthData !=3D NULL) { + HealthData->Uint32 =3D CpuInfoInHob[ProcessorNumber].Health; + } + + return EFI_SUCCESS; +} + +/** + This return the handle number for the calling processor. This service m= ay be + called from the BSP and APs. + + @param[out] ProcessorNumber Pointer to the handle number of AP. + The range is from 0 to the total number of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + MpInitLibGetNumberOfProcessors(). + + @retval EFI_SUCCESS The current processor handle number was = returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibWhoAmI ( + OUT UINTN *ProcessorNumber + ) +{ + CPU_MP_DATA *CpuMpData; + + if (ProcessorNumber =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + CpuMpData =3D GetCpuMpData (); + + return GetProcessorNumber (CpuMpData, ProcessorNumber); +} + +/** + Retrieves the number of logical processor in the platform and the number= of + those logical processors that are enabled on this boot. This service may= only + be called from the BSP. + + @param[out] NumberOfProcessors Pointer to the total number of l= ogical + processors in the system, includ= ing the BSP + and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled= logical + processors that exist in system,= including + the BSP. + + @retval EFI_SUCCESS The number of logical processors and ena= bled + logical processors was retrieved. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfE= nabledProcessors + is NULL. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetNumberOfProcessors ( + OUT UINTN *NumberOfProcessors OPTIONAL, + OUT UINTN *NumberOfEnabledProcessors OPTIONAL + ) +{ + CPU_MP_DATA *CpuMpData; + UINTN CallerNumber; + UINTN ProcessorNumber; + UINTN EnabledProcessorNumber; + UINTN Index; + + CpuMpData =3D GetCpuMpData (); + + if ((NumberOfProcessors =3D=3D NULL) && (NumberOfEnabledProcessors =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether caller processor is BSP + // + MpInitLibWhoAmI (&CallerNumber); + if (CallerNumber !=3D CpuMpData->BspNumber) { + return EFI_DEVICE_ERROR; + } + + ProcessorNumber =3D CpuMpData->CpuCount; + EnabledProcessorNumber =3D 0; + for (Index =3D 0; Index < ProcessorNumber; Index++) { + if (GetApState (&CpuMpData->CpuData[Index]) !=3D CpuStateDisabled) { + EnabledProcessorNumber++; + } + } + + if (NumberOfProcessors !=3D NULL) { + *NumberOfProcessors =3D ProcessorNumber; + } + + if (NumberOfEnabledProcessors !=3D NULL) { + *NumberOfEnabledProcessors =3D EnabledProcessorNumber; + } + + return EFI_SUCCESS; +} + +/** + Get pointer to CPU MP Data structure from GUIDed HOB. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpDataFromGuidedHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + VOID *DataInHob; + CPU_MP_DATA *CpuMpData; + + CpuMpData =3D NULL; + GuidHob =3D GetFirstGuidHob (&mCpuInitMpLibHobGuid); + + if (GuidHob !=3D NULL) { + DataInHob =3D GET_GUID_HOB_DATA (GuidHob); + CpuMpData =3D (CPU_MP_DATA *)(*(UINTN *)DataInHob); + } + + return CpuMpData; +} diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h b/UefiCpuPkg/L= ibrary/LoongArch64MpInitLib/MpLib.h new file mode 100644 index 0000000000..ae5f63d267 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h @@ -0,0 +1,361 @@ +/** @file + Common header file for LoongArch MP Initialize Library. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef MP_LIB_H_ +#define MP_LIB_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') + +#define CPU_INIT_MP_LIB_HOB_GUID \ + { \ + 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad= , 0x4a } \ + } + +#define PROCESSOR_RESOURCE_HOB_GUID \ + { \ + 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x46= , 0x7e } \ + } + +// +// AP loop state when APs are in idle state +// It's value is the same with PcdCpuApLoopMode +// +typedef enum { + ApInHltLoop =3D 1, + ApInRunLoop =3D 2 +} AP_LOOP_MODE; + +// +// AP initialization state during APs wakeup +// +typedef enum { + ApInitConfig =3D 1, + ApInitReconfig =3D 2, + ApInitDone =3D 3 +} AP_INIT_STATE; + +// +// AP state +// +typedef enum { + CpuStateIdle, + CpuStateReady, + CpuStateBusy, + CpuStateFinished, + CpuStateDisabled +} CPU_STATE; + +// +// AP related data +// +typedef struct { + SPIN_LOCK ApLock; + volatile UINT32 *StartupApSignal; + volatile UINTN ApFunction; + volatile UINTN ApFunctionArgument; + BOOLEAN CpuHealthy; + volatile CPU_STATE State; + BOOLEAN Waiting; + BOOLEAN *Finished; + UINT64 ExpectedTime; + UINT64 CurrentTime; + UINT64 TotalTime; + EFI_EVENT WaitEvent; +} CPU_AP_DATA; + +// +// Basic CPU information saved in Guided HOB. +// Because the contents will be shard between PEI and DXE, +// we need to make sure the each fields offset same in different +// architecture. +// +#pragma pack (1) +typedef struct { + UINT32 ApicId; + UINT32 Health; +} CPU_INFO_IN_HOB; +#pragma pack () + +typedef struct _CPU_MP_DATA CPU_MP_DATA; + +#pragma pack(1) + +// +// MP CPU exchange information for AP reset code +// This structure is required to be packed because fixed field offsets +// into this structure are used in assembly code in this module +// +typedef struct { + CPU_MP_DATA *CpuMpData; +} MP_CPU_EXCHANGE_INFO; + +#pragma pack() + +typedef struct { + SPIN_LOCK Lock; + UINT32 CpuCount; + UINT64 CpuInfoInHob; +} PROCESSOR_RESOURCE_DATA; + +// +// CPU MP Data save in memory +// +struct _CPU_MP_DATA { + UINT64 CpuInfoInHob; + UINT32 CpuCount; + UINT32 BspNumber; + // + // The above fields data will be passed from PEI to DXE + // Please make sure the fields offset same in the different + // architecture. + // + SPIN_LOCK MpLock; + + volatile UINT32 FinishedCount; + UINT32 RunningCount; + BOOLEAN SingleThread; + EFI_AP_PROCEDURE Procedure; + VOID *ProcArguments; + BOOLEAN *Finished; + UINT64 ExpectedTime; + UINT64 CurrentTime; + UINT64 TotalTime; + EFI_EVENT WaitEvent; + + AP_INIT_STATE InitFlag; + UINT8 ApLoopMode; + CPU_AP_DATA *CpuData; + volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo; +}; + +extern EFI_GUID mCpuInitMpLibHobGuid; +extern EFI_GUID mProcessorResourceHobGuid; + +/** + Get the pointer to CPU MP Data structure. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpData ( + VOID + ); + +/** + Save the pointer to CPU MP Data structure. + + @param[in] CpuMpData The pointer to CPU MP Data structure will be saved. +**/ +VOID +SaveCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ); + +/** + This function will be called by BSP to wakeup AP. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] Broadcast TRUE: Send broadcast IPI to all APs + FALSE: Send IPI to AP by ApicId + @param[in] ProcessorNumber The handle number of specified processor + @param[in] Procedure The function to be invoked by AP + @param[in] ProcedureArgument The argument to be passed into AP function + @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in br= oadcast mode. +**/ +VOID +WakeUpAP ( + IN CPU_MP_DATA *CpuMpData, + IN BOOLEAN Broadcast, + IN UINTN ProcessorNumber, + IN EFI_AP_PROCEDURE Procedure OPTIONAL, + IN VOID *ProcedureArgument OPTIONAL, + IN BOOLEAN WakeUpDisabledAps + ); + +/** + Initialize global data for MP support. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +InitMpGlobalData ( + IN CPU_MP_DATA *CpuMpData + ); + +/** + 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 ex= ecute + the function specified by Procedure = one by + one, in ascending order of processor= handle + number. If FALSE, then all the enab= led APs + execute the function specified by Pr= ocedure + simultaneously. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds 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 A= Ps + finish before timeout expires, then = its + content is set to address of the buf= fer + 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 +StartupAllCPUsWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN BOOLEAN ExcludeBsp, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ); + +/** + Worker function to let the caller get one enabled AP to execute a caller= -provided + function. + + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds 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] Finished If AP returns from Procedure before = the + timeout expires, its content is set = to TRUE. + Otherwise, the value is set to FALSE. + + @retval EFI_SUCCESS In blocking mode, specified AP finished = before + the timeout expires. + @retval others Failed to Startup AP. + +**/ +EFI_STATUS +StartupThisAPWorker ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ); + +/** + Worker function to let the caller enable or disable an AP from this poin= t onward. + This service may only be called from the BSP. + This instance will be added in the future. + + @param[in] ProcessorNumber The handle number of AP. + @param[in] EnableAP Specifies the new state for the processor f= or + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that spec= ifies + the new health status of the AP. + + @retval EFI_SUCCESS The specified AP was enabled or disabled su= ccessfully. + @retval others Failed to Enable/Disable AP. + +**/ +EFI_STATUS +EnableDisableApWorker ( + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ); + +/** + Get pointer to CPU MP Data structure from GUIDed HOB. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpDataFromGuidedHob ( + VOID + ); + +/** 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] ProcessorNumber The handle number of processor. + + @retval EFI_SUCCESS Specified AP has finished task assigned by= StartupThisAPs(). + @retval EFI_TIMEOUT The timeout expires. + @retval EFI_NOT_READY Specified AP has not finished task and tim= eout has not expired. +**/ +EFI_STATUS +CheckThisAP ( + IN UINTN ProcessorNumber + ); + +/** + Checks status of all APs. + + This function checks whether all APs have finished task assigned by Star= tupAllAPs(), + and whether timeout expires. + + @retval EFI_SUCCESS All APs have finished task assigned by Sta= rtupAllAPs(). + @retval EFI_TIMEOUT The timeout expires. + @retval EFI_NOT_READY APs have not finished task and timeout has= not expired. +**/ +EFI_STATUS +CheckAllAPs ( + VOID + ); + +/** + Checks APs status and updates APs status if needed. + +**/ +VOID +CheckAndUpdateApsStatus ( + VOID + ); + +/** + Enable Debug Agent to support source debugging on AP function. + This instance will added in the future. + +**/ +VOID +EnableDebugAgent ( + VOID + ); + +#endif diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf b/Uef= iCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf new file mode 100644 index 0000000000..7ecda0cce8 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf @@ -0,0 +1,37 @@ +## @file +# LoongArch64 MP initialize support functions for PEI phase. +# +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 1.29 + BASE_NAME =3D PeiMpInitLib + MODULE_UNI_FILE =3D PeiMpInitLib.uni + FILE_GUID =3D ED078F16-A2D3-2F34-9267-E24D56E91FCF + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.1 + LIBRARY_CLASS =3D MpInitLib|PEIM + +[Sources.common] + PeiMpLib.c + MpLib.c + MpLib.h + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + CpuLib + HobLib + MemoryAllocationLib + SynchronizationLib + TimerLib + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONS= UMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONS= UMES diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni b/Uef= iCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni new file mode 100644 index 0000000000..51fdc618c6 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni @@ -0,0 +1,15 @@ +// /** @file +// MP Initialize Library instance for PEI driver. +// +// MP Initialize Library instance for PEI driver. +// +// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Lib= rary instance for PEI driver." + +#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Lib= rary instance for PEI driver." diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c b/UefiCpuPk= g/Library/LoongArch64MpInitLib/PeiMpLib.c new file mode 100644 index 0000000000..d1c5e55b57 --- /dev/null +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c @@ -0,0 +1,404 @@ +/** @file + LoongArch64 MP initialize support functions for PEI phase. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" + +/** + Enable Debug Agent to support source debugging on AP function. + +**/ +VOID +EnableDebugAgent ( + VOID + ) +{ +} + +/** + Get pointer to CPU MP Data structure. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpData ( + VOID + ) +{ + CPU_MP_DATA *CpuMpData; + + CpuMpData =3D GetCpuMpDataFromGuidedHob (); + ASSERT (CpuMpData !=3D NULL); + return CpuMpData; +} + +/** + Save the pointer to CPU MP Data structure. + + @param[in] CpuMpData The pointer to CPU MP Data structure will be saved. +**/ +VOID +SaveCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + UINT64 Data64; + + // + // Build location of CPU MP DATA buffer in HOB + // + Data64 =3D (UINT64)(UINTN)CpuMpData; + BuildGuidDataHob ( + &mCpuInitMpLibHobGuid, + (VOID *)&Data64, + sizeof (UINT64) + ); +} + +/** + Save the Processor Resource Data. + + @param[in] ResourceData The pointer to Processor Resource Data structur= e will be saved. +**/ +VOID +SaveProcessorResourceData ( + IN PROCESSOR_RESOURCE_DATA *ResourceData + ) +{ + UINT64 Data64; + + // + // Build location of Processor Resource Data buffer in HOB + // + Data64 =3D (UINT64)(UINTN)ResourceData; + BuildGuidDataHob ( + &mProcessorResourceHobGuid, + (VOID *)&Data64, + sizeof (UINT64) + ); +} + +/** + Get available EfiBootServicesCode memory below 4GB by specified size. + + This buffer is required to safely transfer AP from real address mode to + protected mode or long mode, due to the fact that the buffer returned by + GetWakeupBuffer() may be marked as non-executable. + + @param[in] BufferSize Wakeup transition buffer size. + + @retval other Return wakeup transition buffer address below 4GB. + @retval 0 Cannot find free memory below 4GB. +**/ +UINTN +GetModeTransitionBuffer ( + IN UINTN BufferSize + ) +{ + // + // PEI phase doesn't need to do such transition. So simply return 0. + // + return 0; +} + +/** + Checks APs status and updates APs status if needed. + +**/ +VOID +CheckAndUpdateApsStatus ( + VOID + ) +{ +} + +/** + Initialize global data for MP support. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +InitMpGlobalData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + SaveCpuMpData (CpuMpData); +} + +/** + This service executes 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. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs ex= ecute + the function specified by Procedure = one by + one, in ascending order of processor= handle + number. If FALSE, then all the enab= led APs + execute the function specified by Pr= ocedure + simultaneously. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until all A= Ps finish + or TimeoutInMicroSeconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on all the e= nabled + APs, and go on executing immediately= . If + all return from Procedure, or Timeou= tInMicroSeconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + APs to return from Procedure, either= for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + all APs return from Procedure, then = Procedure + on the failed APs is terminated. All= enabled + APs are available for next function = assigned + by MpInitLibStartupAllAPs() or + MPInitLibStartupThisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. = Otherwise, + if all APs finish successfully, then= its + content is set to NULL. If not all A= Ps + finish before timeout expires, then = its + content is set to address of the buf= fer + holding handle numbers of the failed= APs. + The buffer is allocated by MP Initia= lization + library, and it's the caller's respo= nsibility to + free the buffer with FreePool() serv= ice. + In blocking mode, it is ready for co= nsumption + when the call returns. In non-blocki= ng mode, + it is ready when WaitEvent is signal= ed. The + list of failed CPU is terminated by + END_OF_CPU_LIST. + + @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 EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mo= de is not + supported. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupAllAPs ( + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + if (WaitEvent !=3D NULL) { + return EFI_UNSUPPORTED; + } + + return StartupAllCPUsWorker ( + Procedure, + SingleThread, + TRUE, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); +} + +/** + This service lets the caller get one enabled AP to execute a caller-prov= ided + function. + + @param[in] Procedure A pointer to the function to be run = on the + designated AP of the system. See type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The ran= ge is + from 0 to the total number of logical + processors minus 1. The total number= of + logical processors can be retrieved = by + MpInitLibGetNumberOfProcessors(). + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until this = AP finish + or TimeoutInMicroSeconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on this AP, + and go on executing immediately. If = this AP + return from Procedure or TimeoutInMi= croSeconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + this AP to finish this Procedure, ei= ther for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + this AP returns from Procedure, then= Procedure + on the AP is terminated. The + AP is available for next function as= signed + by MpInitLibStartupAllAPs() or + MpInitLibStartupThisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = on the + specified AP. + @param[out] Finished If NULL, this parameter is ignored. = In + blocking mode, this parameter is ign= ored. + In non-blocking mode, if AP returns = from + Procedure before the timeout expires= , its + content is set to TRUE. Otherwise, t= he + value is set to FALSE. The caller can + determine if the AP returned from Pr= ocedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished = before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has b= een + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mo= de is not + supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or dis= abled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupThisAP ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + if (WaitEvent !=3D NULL) { + return EFI_UNSUPPORTED; + } + + return StartupThisAPWorker ( + Procedure, + ProcessorNumber, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + Finished + ); +} + +/** + This service switches the requested AP to be the BSP from that point onw= ard. + This service changes the BSP for all purposes. This call can only be per= formed + by the current BSP. + + @param[in] ProcessorNumber The handle number of AP that is to become t= he new + BSP. The range is from 0 to the total numbe= r of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + MpInitLibGetNumberOfProcessors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as= an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed pr= ior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BS= P or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibSwitchBSP ( + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This service lets the caller enable or disable an AP from this point onw= ard. + This service may only be called from the BSP. + + @param[in] ProcessorNumber The handle number of AP. + The range is from 0 to the total number of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + MpInitLibGetNumberOfProcessors(). + @param[in] EnableAP Specifies the new state for the processor f= or + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that spec= ifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo()= . Only + the PROCESSOR_HEALTH_STATUS_BIT is used. Al= l other + bits are ignored. If it is NULL, this para= meter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled= successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be co= mpleted + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not suppo= rted. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by P= rocessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + @retval EFI_NOT_READY MP Initialize Library is not initialized. + +**/ +EFI_STATUS +EFIAPI +MpInitLibEnableDisableAP ( + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 738013ec0c..0f0bce0029 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -213,6 +213,8 @@ UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHand= lerLib.inf UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf + UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf + UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf =20 [BuildOptions] *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES --=20 2.27.0 -=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 (#112957): https://edk2.groups.io/g/devel/message/112957 Mute This Topic: https://groups.io/mt/103398610/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-