From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id CD2EA740035 for ; Wed, 31 Jan 2024 05:33:34 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=GMcR+GeRhK5jEhTnRmAcgUk8O45k80im9PzyJcROyu8=; c=relaxed/simple; d=groups.io; h=Message-ID:Date:MIME-Version:User-Agent:Subject:From:To:Cc:Reply-To:References:In-Reply-To:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type; s=20140610; t=1706679213; v=1; b=aDmM/1S6aDpiRssKb2FcfRtQya58Mryes7gI6eIO7ur/9X0eZAzVIfZjk+W093FqSY/NmMTh Zf2imBAZoMjpPn/qAq8FzqEyCjGn81Nv06R4bgmhCkqsTx6QoK8RigqdEDVDM7ngVW7ZTViurTw 7cnd3uZGgC4xHUEupW1r5Bsw= X-Received: by 127.0.0.2 with SMTP id hOD2YY7687511xxqGmRFbDEc; Tue, 30 Jan 2024 21:33:33 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.8235.1706679210678319733 for ; Tue, 30 Jan 2024 21:33:32 -0800 X-Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8Dx6uim27llaskIAA--.6961S3; Wed, 31 Jan 2024 13:33:26 +0800 (CST) X-Received: from [10.40.24.149] (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8AxzxOj27llgpgpAA--.40401S3; Wed, 31 Jan 2024 13:33:23 +0800 (CST) Message-ID: Date: Wed, 31 Jan 2024 13:33:22 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [edk2-devel] [PATCH v8 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 From: "Chao Li" To: devel@edk2.groups.io, Ray Ni , Laszlo Ersek Cc: Eric Dong , Rahul Kumar , Gerd Hoffmann Reply-To: devel@edk2.groups.io,lichao@loongson.cn References: <20240126062715.3099433-1-lichao@loongson.cn> <17ADD1DB56FC4702.24595@groups.io> <17AF511741BD9C8B.15701@groups.io> In-Reply-To: <17AF511741BD9C8B.15701@groups.io> X-CM-TRANSID: AQAAf8AxzxOj27llgpgpAA--.40401S3 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQANCGW4s2EJfwAHs6 X-Coremail-Antispam: 1Uk129KBj9fXoWDuFW3Kr1UCFW7Jr4xAFWrZwc_yoWfJFyxZo WxA3yktw4UKrs3Wws5Crn5GF4fWFykursayry0qa4vyF1vqF13KrWj9w15JryfXa4kXF4D G34xJ34fAayayFyrl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn8Aqx4xG62kEwI0EY4vaYxAvb48xYxn0WfASr-VFAUDa7-sFnT9fnUUI cSsGvfJTRUUUbxkYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20x vaj40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2xF0cIa020Ex4CE44I27w Aqx4xG62kEwI0EY4vaYxAvb48xMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E87Iv67AK xVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IY64vIr41l7480Y4vEI4kI2Ix0rV Aqx4xJMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAF wI0_JrI_JrWlx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUAVWUtwCIc4 0Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY1x0267AK xVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr 1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU8xR67UU UUU== 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 List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: p4EfL6oATfIgwBsiGIx5XzdQx7686176AA= Content-Type: multipart/alternative; boundary="------------GvTr1EN9nBuRh4M0klgw0w77" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b="aDmM/1S6"; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io --------------GvTr1EN9nBuRh4M0klgw0w77 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Hi Ray and Laszlo, I would very much like to be merged into stable202302, the soft feature=20 deadline is 2024-02-05, so could you please hlep to review this patch as=20 soon as passable? Please... Thanks, Chao On 2024/1/31 11:32, Chao Li wrote: > > Hi Ray, > > Can you please help to review this patch again? > > On 2024/1/26 14:29, Chao Li wrote: >> Added LoongArch multiprocessor initialization instance into MpInitLib. >> >> 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 >> --- >> UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 27 +- >> .../Library/MpInitLib/LoongArch64/DxeMpLib.c | 480 +++++ >> .../Library/MpInitLib/LoongArch64/MpLib.c | 1621 +++++++++++++++++ >> .../Library/MpInitLib/LoongArch64/MpLib.h | 361 ++++ >> .../Library/MpInitLib/LoongArch64/PeiMpLib.c | 404 ++++ >> UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 27 +- >> 6 files changed, 2902 insertions(+), 18 deletions(-) >> create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c >> create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c >> create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h >> create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c >> >> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/= Library/MpInitLib/DxeMpInitLib.inf >> index 55e46d4a1f..6db26f5fec 100644 >> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf >> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf >> @@ -2,6 +2,7 @@ >> # MP Initialize Library instance for DXE driver. >> # >> # Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.<= BR> >> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rig= hts reserved.
>> # SPDX-License-Identifier: BSD-2-Clause-Patent >> # >> ## >> @@ -18,7 +19,7 @@ >> # >> # The following information is for reference only and not required by = the build tools. >> # >> -# VALID_ARCHITECTURES =3D IA32 X64 >> +# VALID_ARCHITECTURES =3D IA32 X64 LOONGARCH64 >> # >> =20 >> [Sources.IA32] >> @@ -31,7 +32,7 @@ >> X64/MpFuncs.nasm >> X64/CreatePageTable.c >> =20 >> -[Sources.common] >> +[Sources.IA32, Sources.X64] >> AmdSev.c >> MpEqu.inc >> DxeMpLib.c >> @@ -40,24 +41,32 @@ >> Microcode.c >> MpHandOff.h >> =20 >> +[Sources.LoongArch64] >> + LoongArch64/DxeMpLib.c >> + LoongArch64/MpLib.c >> + LoongArch64/MpLib.h >> + >> [Packages] >> MdePkg/MdePkg.dec >> MdeModulePkg/MdeModulePkg.dec >> UefiCpuPkg/UefiCpuPkg.dec >> =20 >> -[LibraryClasses] >> +[LibraryClasses.common] >> BaseLib >> - LocalApicLib >> - MemoryAllocationLib >> - HobLib >> - MtrrLib >> CpuLib >> - UefiBootServicesTableLib >> DebugAgentLib >> - SynchronizationLib >> + HobLib >> + MemoryAllocationLib >> PcdLib >> + UefiBootServicesTableLib >> + SynchronizationLib >> + >> +[LibraryClasses.IA32, LibraryClasses.X64] >> CcExitLib >> + LocalApicLib >> MicrocodeLib >> + MtrrLib >> + >> [LibraryClasses.X64] >> CpuPageTableLib >> =20 >> diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c b/UefiC= puPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c >> new file mode 100644 >> index 0000000000..739da77e32 >> --- /dev/null >> +++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c >> @@ -0,0 +1,480 @@ >> +/** @file >> + LoongArch64 MP initialize support functions for DXE phase. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts 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 sa= ved. >> +**/ >> +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; Pr= ocessorNumber++) { >> + 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 r= un on >> + enabled APs of the system. See ty= pe >> + EFI_AP_PROCEDURE. >> + @param[in] SingleThread If TRUE, then all the enabled APs= execute >> + the function specified by Procedu= re one by >> + one, in ascending order of proces= sor handle >> + number. If FALSE, then all the e= nabled APs >> + execute the function specified by= Procedure >> + simultaneously. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until al= l APs finish >> + or TimeoutInMicroSeconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on all th= e enabled >> + APs, and go on executing immediat= ely. If >> + all return from Procedure, or Tim= eoutInMicroSeconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + APs to return from Procedure, eit= her for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + all APs return from Procedure, th= en Procedure >> + on the failed APs is terminated. = All enabled >> + APs are available for next functi= on assigned >> + by MpInitLibStartupAllAPs() or >> + MPInitLibStartupThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] FailedCpuList If NULL, this parameter is ignore= d. Otherwise, >> + if all APs finish successfully, t= hen its >> + content is set to NULL. If not al= l APs >> + finish before timeout expires, th= en its >> + content is set to address of the = buffer >> + holding handle numbers of the fai= led APs. >> + The buffer is allocated by MP Ini= tialization >> + library, and it's the caller's re= sponsibility to >> + free the buffer with FreePool() s= ervice. >> + In blocking mode, it is ready for= consumption >> + when the call returns. In non-blo= cking mode, >> + it is ready when WaitEvent is sig= naled. The >> + list of failed CPU is terminated = by >> + END_OF_CPU_LIST. >> + >> + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en dispatched >> + to all enabled APs. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT was >> + signaled. >> + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking= mode 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 initiali= zed. >> + @retval EFI_TIMEOUT In blocking mode, the timeout expired= before >> + 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-p= rovided >> + function. >> + >> + @param[in] Procedure A pointer to the function to be r= un on the >> + designated AP of the system. See = type >> + EFI_AP_PROCEDURE. >> + @param[in] ProcessorNumber The handle number of the AP. The = range is >> + from 0 to the total number of log= ical >> + processors minus 1. The total num= ber of >> + logical processors can be retriev= ed by >> + MpInitLibGetNumberOfProcessors(). >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until th= is AP finish >> + or TimeoutInMicroSeconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on this A= P, >> + and go on executing immediately. = If this AP >> + return from Procedure or TimeoutI= nMicroSeconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + this AP to finish this Procedure,= either for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + this AP returns from Procedure, t= hen Procedure >> + on the AP is terminated. The >> + AP is available for next function= assigned >> + by MpInitLibStartupAllAPs() or >> + MpInitLibStartupThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re on the >> + specified AP. >> + @param[out] Finished If NULL, this parameter is ignore= d. In >> + blocking mode, this parameter is = ignored. >> + In non-blocking mode, if AP retur= ns from >> + Procedure before the timeout expi= res, its >> + content is set to TRUE. Otherwise= , the >> + value is set to FALSE. The caller= can >> + determine if the AP returned from= Procedure >> + by evaluating this value. >> + >> + @retval EFI_SUCCESS In blocking mode, specified AP finish= ed before >> + the timeout expires. >> + @retval EFI_SUCCESS In non-blocking mode, the function ha= s been >> + dispatched to specified AP. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT was >> + signaled. >> + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking= mode is not >> + supported. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_TIMEOUT In blocking mode, the timeout expired= before >> + the specified AP has finished. >> + @retval EFI_NOT_READY The specified AP is busy. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + @retval EFI_NOT_FOUND The processor with the handle specifi= ed by >> + ProcessorNumber does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or = disabled 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 = onward. >> + This service changes the BSP for all purposes. This call can only be = performed >> + by the current BSP. >> + >> + @param[in] ProcessorNumber The handle number of AP that is to becom= e the new >> + BSP. The range is from 0 to the total nu= mber of >> + logical processors minus 1. The total nu= mber 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 disabl= ed. >> + >> + @retval EFI_SUCCESS BSP successfully switched. >> + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed= prior 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 specifi= ed by >> + ProcessorNumber does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current= BSP or >> + a disabled AP. >> + @retval EFI_NOT_READY The specified AP is busy. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +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 = onward. >> + 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 nu= mber of >> + logical processors can be retrieved by >> + MpInitLibGetNumberOfProcessors(). >> + @param[in] EnableAP Specifies the new state for the processo= r for >> + enabled, FALSE for disabled. >> + @param[in] HealthFlag If not NULL, a pointer to a value that s= pecifies >> + the new health status of the AP. This fl= ag >> + corresponds to StatusFlag defined in >> + EFI_MP_SERVICES_PROTOCOL.GetProcessorInf= o(). Only >> + the PROCESSOR_HEALTH_STATUS_BIT is used.= All other >> + bits are ignored. If it is NULL, this p= arameter >> + is ignored. >> + >> + @retval EFI_SUCCESS The specified AP was enabled or disab= led successfully. >> + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be= completed >> + prior to this service returning. >> + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not su= pported. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_NOT_FOUND Processor with the handle specified b= y ProcessorNumber >> + does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +MpInitLibEnableDisableAP ( >> + IN UINTN ProcessorNumber, >> + IN BOOLEAN EnableAP, >> + IN UINT32 *HealthFlag OPTIONAL >> + ) >> +{ >> + return EFI_UNSUPPORTED; >> +} >> diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c b/UefiCpuP= kg/Library/MpInitLib/LoongArch64/MpLib.c >> new file mode 100644 >> index 0000000000..930d34aa3d >> --- /dev/null >> +++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c >> @@ -0,0 +1,1621 @@ >> +/** @file >> + LoongArch64 CPU MP Initialize Library common functions. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> + >> +**/ >> + >> +#include "MpLib.h" >> + >> +#include >> +#include >> + >> +#define INVALID_APIC_ID 0xFFFFFFFF >> + >> +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 n= umber 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) { >> + Index2 =3D 0; >> + for (Index1 =3D (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1); I= ndex1 > 0; Index1--) { >> + if (CpuInfoInHob[Index1].ApicId !=3D INVALID_APIC_ID) { >> + if (Index1 =3D=3D ApCount) { >> + break; >> + } else { >> + for ( ; Index2 <=3D ApCount; Index2++) { >> + if (CpuInfoInHob[Index2].ApicId =3D=3D INVALID_APIC_ID) { >> + CopyMem (&CpuInfoInHob[Index2], &CpuInfoInHob[Index1], si= zeof (CPU_INFO_IN_HOB)); >> + CpuMpData->CpuData[Index2] =3D CpuMpData->CpuData[Index1= ]; >> + CpuInfoInHob[Index1].ApicId =3D INVALID_APIC_ID; >> + break; >> + } >> + } >> + } >> + } else { >> + continue; >> + } >> + } >> + >> + 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_H= OB)); >> + CopyMem ( >> + &CpuInfoInHob[Index3], >> + &CpuInfoInHob[Index1], >> + sizeof (CPU_INFO_IN_HOB) >> + ); >> + CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_H= OB)); >> + >> + // >> + // Also exchange the StartupApSignal. >> + // >> + StartupApSignal =3D CpuMpData->CpuDa= ta[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 obta= ined before >> + // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 M= ailbox0 is used >> + // as the first broadcast method to wake up all APs, and all of APs w= ill 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->CpuInfoI= nHob); >> + } >> + >> + // >> + // 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 (PcdCpuMaxLogicalProcessorN= umber)); >> + >> + // >> + // 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", Cpu= MpData->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= enabled, >> + 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].Sta= rtupApSignal; >> + } 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].Sta= rtupApSignal; >> + InterlockedCompareExchange32 ( >> + (UINT32 *)ApStartupSignalBuffer, >> + WAKEUP_AP_SIGNAL, >> + 0 >> + ); >> + >> + // >> + // Invoke AP function here >> + // >> + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D CpuS= tateReady) { >> + Procedure =3D (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNum= ber].ApFunction; >> + Parameter =3D (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFun= ctionArgument; >> + if (Procedure !=3D NULL) { >> + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBus= y); >> + Procedure (Parameter); >> + } >> + >> + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinis= hed); >> + } >> + } >> + >> + // >> + // 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 (BIT12); >> + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFU); >> + 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].S= tartupApSignal; >> + } >> + >> + // >> + // 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 va= lue. >> + >> + Calculate the number of performance counter ticks required for a time= out. >> + If TimeoutInMicroseconds is 0, return value is also 0, which is recog= nized >> + as infinity. >> + >> + @param[in] TimeoutInMicroseconds Timeout value in microseconds. >> + @param[out] CurrentTime Returns the current value of the = performance 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 re= cognized >> + // as infinity. >> + // >> + if (TimeoutInMicroseconds =3D=3D 0) { >> + return 0; >> + } >> + >> + // >> + // GetPerformanceCounterProperties () returns the timestamp counter's= frequency >> + // 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) < Ti= mestampCounterFreq) { >> + // >> + // Convert microseconds into seconds if direct multiplication overf= lows >> + // >> + TimeoutInSeconds =3D DivU64x32 (TimeoutInMicroseconds, 1000000); >> + // >> + // Assertion if the final tick count exceeds MAX_UINT64 >> + // >> + ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= =3D TimestampCounterFreq); >> + return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds); >> + } else { >> + // >> + // No overflow case, multiply the return value with TimeoutInMicros= econds and then divide >> + // it by 1,000,000, to get the number of ticks for the timeout valu= e. >> + // >> + return DivU64x32 ( >> + MultU64x64 ( >> + TimestampCounterFreq, >> + TimeoutInMicroseconds >> + ), >> + 1000000 >> + ); >> + } >> +} >> + >> +/** >> + Checks whether timeout expires. >> + >> + Check whether the number of elapsed performance counter ticks require= d for >> + a timeout condition has been reached. >> + If Timeout is zero, which means infinity, return value is always FALS= E. >> + >> + @param[in, out] PreviousTime On input, the value of the performan= ce counter >> + when it was last read. >> + On output, the current value of the p= erformance >> + counter >> + @param[in] TotalTime The total amount of elapsed time in p= erformance >> + counter ticks. >> + @param[in] Timeout The number of performance counter tic= ks required >> + to reach a timeout condition. >> + >> + @retval TRUE A timeout condition has been reached. >> + @retval FALSE A timeout condition has not been reac= hed. >> + >> +**/ >> +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 sp= ecified >> + 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", >> + __func__, >> + 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 *)AllocatePo= ol (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 processo= r >> + @param[in] Procedure The function to be invoked by AP >> + @param[in] ProcedureArgument The argument to be passed into AP funct= ion >> + @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in= broadcast 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 themsel= ves. >> + // >> + if (CpuMpData->InitFlag =3D=3D ApInitConfig) { >> + DEBUG ((DEBUG_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", __fun= c__, 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) && !WakeUp= DisabledAps) { >> + 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[ProcessorNumb= er]; >> + 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_S= HIFT) | >> + 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-threade= d StartupAllAPs(). >> + >> + @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; Pr= ocessorNumber++) { >> + 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 a= ssigned >> + 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 = timeout 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, CpuDa= ta->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 S= tartupAllAPs(), >> + and whether timeout expires. >> + >> + @retval EFI_SUCCESS All APs have finished task assigned by = StartupAllAPs(). >> + @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; Pr= ocessorNumber++) { >> + if (!CpuMpData->CpuData[ProcessorNumber].Waiting) { >> + continue; >> + } >> + >> + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; >> + // >> + // Check the CPU state of AP. If it is CpuStateIdle, then the AP ha= s finished its task. >> + // Only BSP and corresponding AP access this unit of CPU Data. This= means the AP will not modify the >> + // value of state after setting the it to CpuStateIdle, so BSP can = safely 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 r= un on >> + enabled APs of the system. >> + @param[in] SingleThread If TRUE, then all the enabled APs= execute >> + the function specified by Procedu= re one by >> + one, in ascending order of proces= sor handle >> + number. If FALSE, then all the e= nabled APs >> + execute the function specified by= Procedure >> + simultaneously. >> + @param[in] ExcludeBsp Whether let BSP also trig this ta= sk. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. >> + @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] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] FailedCpuList If all APs finish successfully, t= hen its >> + content is set to NULL. If not al= l APs >> + finish before timeout expires, th= en its >> + content is set to address of the = buffer >> + holding handle numbers of the fai= led APs. >> + >> + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en 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; Process= orNumber++) { >> + 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,= return EFI_NOT_STARTED. >> + // >> + return EFI_NOT_STARTED; >> + } >> + >> + CpuMpData->RunningCount =3D 0; >> + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; Process= orNumber++) { >> + 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; Proce= ssorNumber++) { >> + if (ProcessorNumber =3D=3D CallerNumber) { >> + continue; >> + } >> + >> + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { >> + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, Procedu= reArgument, 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 cal= ler-provided >> + function. >> + >> + @param[in] Procedure A pointer to the function to be r= un on >> + enabled APs of the system. >> + @param[in] ProcessorNumber The handle number of the AP. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. >> + @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] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] Finished If AP returns from Procedure befo= re the >> + timeout expires, its content is s= et to TRUE. >> + Otherwise, the value is set to FA= LSE. >> + >> + @retval EFI_SUCCESS In blocking mode, specified AP finish= ed 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 ProcessorNumb= er 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 CpuState= Disabled) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; >> + CpuData->WaitEvent =3D WaitEvent; >> + CpuData->Finished =3D Finished; >> + CpuData->ExpectedTime =3D CalculateTimeout (TimeoutInMicroseconds, &C= puData->CurrentTime); >> + CpuData->TotalTime =3D 0; >> + >> + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgu= ment, FALSE); >> + >> + // >> + // If WaitEvent is NULL, execute in blocking mode. >> + // BSP checks AP's state until it finishes or TimeoutInMicrosecsond e= xpires. >> + // >> + 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 r= un on >> + enabled APs of the system. See ty= pe >> + EFI_AP_PROCEDURE. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + APs to return from Procedure, eit= her for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. TimeoutInMicroseconds i= s ignored >> + for BSP. >> + @param[in] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + >> + @retval EFI_SUCCESS In blocking mode, all CPUs have finis= hed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en 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 initiali= zed. >> + @retval EFI_TIMEOUT In blocking mode, the timeout expired= before >> + 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 A= Ps >> + 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 (PcdCpuMaxLogicalProcessorNu= mber); >> + } else { >> + MaxLogicalProcessorNumber =3D OldCpuMpData->CpuCount; >> + } >> + >> + ASSERT (MaxLogicalProcessorNumber !=3D 0); >> + >> + MonitorBufferSize =3D sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessor= Number; >> + >> + BufferSize =3D 0; >> + BufferSize +=3D MonitorBufferSize; >> + BufferSize +=3D sizeof (CPU_MP_DATA); >> + BufferSize +=3D (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* Ma= xLogicalProcessorNumber; >> + 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 + MaxL= ogicalProcessorNumber); >> + >> + InitializeSpinLock (&CpuMpData->MpLock); >> + >> + // >> + // Set BSP basic information >> + // >> + InitializeApData (CpuMpData, 0, 0); >> + >> + // >> + // Set up APs wakeup signal buffer and initialization APs ApicId stat= us. >> + // >> + for (Index =3D 0; Index < MaxLogicalProcessorNumber; Index++) { >> + CpuMpData->CpuData[Index].StartupApSignal =3D >> + (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof = (WAKEUP_AP_SIGNAL) * Index)); >> + if ((OldCpuMpData =3D=3D NULL) && (Index !=3D CpuMpData->BspNumber)= ) { >> + ((CPU_INFO_IN_HOB *)CpuMpData->CpuInfoInHob)[Index].ApicId =3D I= NVALID_APIC_ID; >> + } >> + } >> + >> + 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].Hea= lth =3D=3D 0) ? TRUE : FALSE; >> + } >> + >> + if (CpuMpData->CpuCount > 1) { >> + // >> + // Only needs to use this flag for DXE phase to update the wake u= p >> + // buffer. Wakeup buffer allocated in PEI phase is no longer vali= d >> + // 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 th= e >> + instant this call is made. This service may only be called from the B= SP. >> + >> + @param[in] ProcessorNumber The handle number of processor. >> + @param[out] ProcessorInfoBuffer A pointer to the buffer where infor= mation for >> + the requested processor is deposite= d. >> + @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 specifi= ed by >> + ProcessorNumber does not exist in the= platform. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +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[ProcessorNu= mber].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 CpuState= Disabled) { >> + 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 servic= e may 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 nu= mber of >> + logical processors can be retrieved by >> + MpInitLibGetNumberOfProcessors(). >> + >> + @retval EFI_SUCCESS The current processor handle number w= as returned >> + in ProcessorNumber. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +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 num= ber 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 o= f logical >> + processors in the system, inc= luding the BSP >> + and disabled APs. >> + @param[out] NumberOfEnabledProcessors Pointer to the number of enab= led logical >> + processors that exist in syst= em, including >> + the BSP. >> + >> + @retval EFI_SUCCESS The number of logical processors and = enabled >> + logical processors was retrieved. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and Number= OfEnabledProcessors >> + is NULL. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +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/MpInitLib/LoongArch64/MpLib.h b/UefiCpuP= kg/Library/MpInitLib/LoongArch64/MpLib.h >> new file mode 100644 >> index 0000000000..b9c6c55b41 >> --- /dev/null >> +++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h >> @@ -0,0 +1,361 @@ >> +/** @file >> + Common header file for LoongArch MP Initialize Library. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts 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, 0= xad, 0x4a } \ >> + } >> + >> +#define PROCESSOR_RESOURCE_HOB_GUID \ >> + { \ >> + 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0= x46, 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 MP_CPU_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 MP_CPU_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 sa= ved. >> +**/ >> +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 processo= r >> + @param[in] Procedure The function to be invoked by AP >> + @param[in] ProcedureArgument The argument to be passed into AP funct= ion >> + @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in= broadcast 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 r= un on >> + enabled APs of the system. >> + @param[in] SingleThread If TRUE, then all the enabled APs= execute >> + the function specified by Procedu= re one by >> + one, in ascending order of proces= sor handle >> + number. If FALSE, then all the e= nabled APs >> + execute the function specified by= Procedure >> + simultaneously. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. >> + @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] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] FailedCpuList If all APs finish successfully, t= hen its >> + content is set to NULL. If not al= l APs >> + finish before timeout expires, th= en its >> + content is set to address of the = buffer >> + holding handle numbers of the fai= led APs. >> + >> + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en 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 cal= ler-provided >> + function. >> + >> + @param[in] Procedure A pointer to the function to be r= un on >> + enabled APs of the system. >> + @param[in] ProcessorNumber The handle number of the AP. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. >> + @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] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] Finished If AP returns from Procedure befo= re the >> + timeout expires, its content is s= et to TRUE. >> + Otherwise, the value is set to FA= LSE. >> + >> + @retval EFI_SUCCESS In blocking mode, specified AP finish= ed 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 p= oint 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 processo= r for >> + enabled, FALSE for disabled. >> + @param[in] HealthFlag If not NULL, a pointer to a value that s= pecifies >> + the new health status of the AP. >> + >> + @retval EFI_SUCCESS The specified AP was enabled or disabled= successfully. >> + @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 a= ssigned >> + 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 = timeout 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 S= tartupAllAPs(), >> + and whether timeout expires. >> + >> + @retval EFI_SUCCESS All APs have finished task assigned by = StartupAllAPs(). >> + @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/MpInitLib/LoongArch64/PeiMpLib.c b/UefiC= puPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c >> new file mode 100644 >> index 0000000000..d1c5e55b57 >> --- /dev/null >> +++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c >> @@ -0,0 +1,404 @@ >> +/** @file >> + LoongArch64 MP initialize support functions for PEI phase. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts 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 sa= ved. >> +**/ >> +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 struc= ture 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 r= un on >> + enabled APs of the system. See ty= pe >> + EFI_AP_PROCEDURE. >> + @param[in] SingleThread If TRUE, then all the enabled APs= execute >> + the function specified by Procedu= re one by >> + one, in ascending order of proces= sor handle >> + number. If FALSE, then all the e= nabled APs >> + execute the function specified by= Procedure >> + simultaneously. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until al= l APs finish >> + or TimeoutInMicroSeconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on all th= e enabled >> + APs, and go on executing immediat= ely. If >> + all return from Procedure, or Tim= eoutInMicroSeconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + APs to return from Procedure, eit= her for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + all APs return from Procedure, th= en Procedure >> + on the failed APs is terminated. = All enabled >> + APs are available for next functi= on assigned >> + by MpInitLibStartupAllAPs() or >> + MPInitLibStartupThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] FailedCpuList If NULL, this parameter is ignore= d. Otherwise, >> + if all APs finish successfully, t= hen its >> + content is set to NULL. If not al= l APs >> + finish before timeout expires, th= en its >> + content is set to address of the = buffer >> + holding handle numbers of the fai= led APs. >> + The buffer is allocated by MP Ini= tialization >> + library, and it's the caller's re= sponsibility to >> + free the buffer with FreePool() s= ervice. >> + In blocking mode, it is ready for= consumption >> + when the call returns. In non-blo= cking mode, >> + it is ready when WaitEvent is sig= naled. The >> + list of failed CPU is terminated = by >> + END_OF_CPU_LIST. >> + >> + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en dispatched >> + to all enabled APs. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT was >> + signaled. >> + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking= mode 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 initiali= zed. >> + @retval EFI_TIMEOUT In blocking mode, the timeout expired= before >> + 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-p= rovided >> + function. >> + >> + @param[in] Procedure A pointer to the function to be r= un on the >> + designated AP of the system. See = type >> + EFI_AP_PROCEDURE. >> + @param[in] ProcessorNumber The handle number of the AP. The = range is >> + from 0 to the total number of log= ical >> + processors minus 1. The total num= ber of >> + logical processors can be retriev= ed by >> + MpInitLibGetNumberOfProcessors(). >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until th= is AP finish >> + or TimeoutInMicroSeconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on this A= P, >> + and go on executing immediately. = If this AP >> + return from Procedure or TimeoutI= nMicroSeconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + this AP to finish this Procedure,= either for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + this AP returns from Procedure, t= hen Procedure >> + on the AP is terminated. The >> + AP is available for next function= assigned >> + by MpInitLibStartupAllAPs() or >> + MpInitLibStartupThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re on the >> + specified AP. >> + @param[out] Finished If NULL, this parameter is ignore= d. In >> + blocking mode, this parameter is = ignored. >> + In non-blocking mode, if AP retur= ns from >> + Procedure before the timeout expi= res, its >> + content is set to TRUE. Otherwise= , the >> + value is set to FALSE. The caller= can >> + determine if the AP returned from= Procedure >> + by evaluating this value. >> + >> + @retval EFI_SUCCESS In blocking mode, specified AP finish= ed before >> + the timeout expires. >> + @retval EFI_SUCCESS In non-blocking mode, the function ha= s been >> + dispatched to specified AP. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT was >> + signaled. >> + @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking= mode is not >> + supported. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_TIMEOUT In blocking mode, the timeout expired= before >> + the specified AP has finished. >> + @retval EFI_NOT_READY The specified AP is busy. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + @retval EFI_NOT_FOUND The processor with the handle specifi= ed by >> + ProcessorNumber does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or = disabled 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 = onward. >> + This service changes the BSP for all purposes. This call can only be = performed >> + by the current BSP. >> + >> + @param[in] ProcessorNumber The handle number of AP that is to becom= e the new >> + BSP. The range is from 0 to the total nu= mber of >> + logical processors minus 1. The total nu= mber 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 disabl= ed. >> + >> + @retval EFI_SUCCESS BSP successfully switched. >> + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed= prior 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 specifi= ed by >> + ProcessorNumber does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current= BSP or >> + a disabled AP. >> + @retval EFI_NOT_READY The specified AP is busy. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +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 = onward. >> + 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 nu= mber of >> + logical processors can be retrieved by >> + MpInitLibGetNumberOfProcessors(). >> + @param[in] EnableAP Specifies the new state for the processo= r for >> + enabled, FALSE for disabled. >> + @param[in] HealthFlag If not NULL, a pointer to a value that s= pecifies >> + the new health status of the AP. This fl= ag >> + corresponds to StatusFlag defined in >> + EFI_MP_SERVICES_PROTOCOL.GetProcessorInf= o(). Only >> + the PROCESSOR_HEALTH_STATUS_BIT is used.= All other >> + bits are ignored. If it is NULL, this p= arameter >> + is ignored. >> + >> + @retval EFI_SUCCESS The specified AP was enabled or disab= led successfully. >> + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be= completed >> + prior to this service returning. >> + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not su= pported. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_NOT_FOUND Processor with the handle specified b= y ProcessorNumber >> + does not exist. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. >> + @retval EFI_NOT_READY MP Initialize Library is not initiali= zed. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +MpInitLibEnableDisableAP ( >> + IN UINTN ProcessorNumber, >> + IN BOOLEAN EnableAP, >> + IN UINT32 *HealthFlag OPTIONAL >> + ) >> +{ >> + return EFI_UNSUPPORTED; >> +} >> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/= Library/MpInitLib/PeiMpInitLib.inf >> index bc3d716aa9..36ee6b9c29 100644 >> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf >> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf >> @@ -2,6 +2,7 @@ >> # MP Initialize Library instance for PEI driver. >> # >> # Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<= BR> >> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rig= hts reserved.
>> # SPDX-License-Identifier: BSD-2-Clause-Patent >> # >> ## >> @@ -18,7 +19,7 @@ >> # >> # The following information is for reference only and not required by = the build tools. >> # >> -# VALID_ARCHITECTURES =3D IA32 X64 >> +# VALID_ARCHITECTURES =3D IA32 X64 LOONGARCH64 >> # >> =20 >> [Sources.IA32] >> @@ -29,7 +30,7 @@ >> X64/AmdSev.c >> X64/MpFuncs.nasm >> =20 >> -[Sources.common] >> +[Sources.IA32, Sources.X64] >> AmdSev.c >> MpEqu.inc >> PeiMpLib.c >> @@ -37,23 +38,31 @@ >> MpLib.h >> Microcode.c >> MpHandOff.h >> + >> +[Sources.LoongArch64] >> + LoongArch64/PeiMpLib.c >> + LoongArch64/MpLib.c >> + LoongArch64/MpLib.h >> + >> [Packages] >> MdePkg/MdePkg.dec >> UefiCpuPkg/UefiCpuPkg.dec >> MdeModulePkg/MdeModulePkg.dec >> =20 >> -[LibraryClasses] >> +[LibraryClasses.common] >> BaseLib >> - LocalApicLib >> - MemoryAllocationLib >> - HobLib >> - MtrrLib >> CpuLib >> - SynchronizationLib >> - PeiServicesLib >> + HobLib >> + MemoryAllocationLib >> PcdLib >> + PeiServicesLib >> + SynchronizationLib >> + >> +[LibraryClasses.IA32, LibraryClasses.X64] >> CcExitLib >> + LocalApicLib >> MicrocodeLib >> + MtrrLib >> =20 >> [Pcd] >> gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## = CONSUMES >=20 -=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 (#114862): https://edk2.groups.io/g/devel/message/114862 Mute This Topic: https://groups.io/mt/104070182/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --------------GvTr1EN9nBuRh4M0klgw0w77 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

Hi Ray and Laszlo,

I would very much like to be merged into stable202302, the soft feature deadline is 2024-02-05, so could you please hlep to review this patch as soon as passable? Please...


=
Thanks,
Chao
On 2024/1/31 11:32, Chao Li wrote:

Hi Ray,

Can you please help to review this patch again?

On 2024/1/26 14:29, Chao Li wrote:
Added LoongArch multiprocess=
or initialization instance into MpInitLib.

BZ: https://bugzilla.tianocore.org/show_bug.cg=
i?id=3D4584

Cc: Eric Dong <er=
ic.dong@intel.com>
Cc: Ray Ni <ray.n=
i@intel.com>
Cc: Rahul Kumar <=
;rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <krax=
el@redhat.com>
Signed-off-by: Chao Li <lic=
hao@loongson.cn>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   27 +-
 .../Library/MpInitLib/LoongArch64/DxeMpLib.c  |  480 +++++
 .../Library/MpInitLib/LoongArch64/MpLib.c     | 1621 +++++++++++++++++
 .../Library/MpInitLib/LoongArch64/MpLib.h     |  361 ++++
 .../Library/MpInitLib/LoongArch64/PeiMpLib.c  |  404 ++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   27 +-
 6 files changed, 2902 insertions(+), 18 deletions(-)
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Lib=
rary/MpInitLib/DxeMpInitLib.inf
index 55e46d4a1f..6db26f5fec 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -2,6 +2,7 @@
 #  MP Initialize Library instance for DXE driver.
 #
 #  Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.<B=
R>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights=
 reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,7 +19,7 @@
 #
 # The following information is for reference only and not required by the =
build tools.
 #
-#  VALID_ARCHITECTURES           =3D IA32 X64
+#  VALID_ARCHITECTURES           =3D IA32 X64 LOONGARCH64
 #
=20
 [Sources.IA32]
@@ -31,7 +32,7 @@
   X64/MpFuncs.nasm
   X64/CreatePageTable.c
=20
-[Sources.common]
+[Sources.IA32, Sources.X64]
   AmdSev.c
   MpEqu.inc
   DxeMpLib.c
@@ -40,24 +41,32 @@
   Microcode.c
   MpHandOff.h
=20
+[Sources.LoongArch64]
+  LoongArch64/DxeMpLib.c
+  LoongArch64/MpLib.c
+  LoongArch64/MpLib.h
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
=20
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
-  LocalApicLib
-  MemoryAllocationLib
-  HobLib
-  MtrrLib
   CpuLib
-  UefiBootServicesTableLib
   DebugAgentLib
-  SynchronizationLib
+  HobLib
+  MemoryAllocationLib
   PcdLib
+  UefiBootServicesTableLib
+  SynchronizationLib
+
+[LibraryClasses.IA32, LibraryClasses.X64]
   CcExitLib
+  LocalApicLib
   MicrocodeLib
+  MtrrLib
+
 [LibraryClasses.X64]
   CpuPageTableLib
=20
diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c b/UefiCpuP=
kg/Library/MpInitLib/LoongArch64/DxeMpLib.c
new file mode 100644
index 0000000000..739da77e32
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/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.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/DebugAgentLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Timer.h>
+
+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->WaitEven=
t);
+      CpuMpData->WaitEvent =3D NULL;
+    }
+  }
+
+  //
+  // Second, check whether pending StartupThisAPs() callings exist.
+  //
+  for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount;=
 ProcessorNumber++) {
+    if (CpuMpData->CpuData[ProcessorNumber].WaitEvent =3D=3D NULL) {
+      continue;
+    }
+
+    Status =3D CheckThisAP (ProcessorNumber);
+
+    if (Status !=3D EFI_NOT_READY) {
+      gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEven=
t);
+      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 typ=
e
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The ran=
ge is
+                                      from 0 to the total number of logica=
l
+                                      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 ca=
n
+                                      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/MpInitLib/LoongArch64/MpLib.c b/UefiCpuPkg/=
Library/MpInitLib/LoongArch64/MpLib.c
new file mode 100644
index 0000000000..930d34aa3d
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
@@ -0,0 +1,1621 @@
+/** @file
+  LoongArch64 CPU MP Initialize Library common functions.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights =
reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#define INVALID_APIC_ID  0xFFFFFFFF
+
+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) {
+    Index2 =3D 0;
+    for (Index1 =3D (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1); Inde=
x1 > 0; Index1--) {
+      if (CpuInfoInHob[Index1].ApicId !=3D INVALID_APIC_ID) {
+        if (Index1 =3D=3D ApCount) {
+          break;
+        } else {
+          for ( ; Index2 <=3D ApCount; Index2++) {
+            if (CpuInfoInHob[Index2].ApicId =3D=3D INVALID_APIC_ID) {
+              CopyMem (&CpuInfoInHob[Index2], &CpuInfoInHob[Index1=
], sizeof (CPU_INFO_IN_HOB));
+              CpuMpData->CpuData[Index2]  =3D CpuMpData->CpuData[Ind=
ex1];
+              CpuInfoInHob[Index1].ApicId =3D INVALID_APIC_ID;
+              break;
+            }
+          }
+        }
+      } else {
+        continue;
+      }
+    }
+
+    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->CpuDa=
ta[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->CpuIn=
foInHob);
+  }
+
+  //
+  // 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 (PcdCpuMaxLogicalProcess=
orNumber));
+
+  //
+  // 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].Sta=
rtupApSignal;
+    } 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].Sta=
rtupApSignal;
+      InterlockedCompareExchange32 (
+        (UINT32 *)ApStartupSignalBuffer,
+        WAKEUP_AP_SIGNAL,
+        0
+        );
+
+      //
+      // Invoke AP function here
+      //
+      if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D =
CpuStateReady) {
+        Procedure =3D (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNum=
ber].ApFunction;
+        Parameter =3D (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFun=
ctionArgument;
+        if (Procedure !=3D NULL) {
+          SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStat=
eBusy);
+          Procedure (Parameter);
+        }
+
+        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateF=
inished);
+      }
+    }
+
+    //
+    // 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 (BIT12);
+      IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFU);
+      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].S=
tartupApSignal;
+      }
+
+      //
+      // 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) < Ti=
mestampCounterFreq) {
+    //
+    // Convert microseconds into seconds if direct multiplication overflow=
s
+    //
+    TimeoutInSeconds =3D DivU64x32 (TimeoutInMicroseconds, 1000000);
+    //
+    // Assertion if the final tick count exceeds MAX_UINT64
+    //
+    ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >=
=3D TimestampCounterFreq);
+    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",
+      __func__,
+      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 *)AllocatePo=
ol (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 ((DEBUG_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_SH=
IFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIF=
T) |
+             ((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_SH=
IFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIF=
T) |
+             ((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_SH=
IFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIF=
T) |
+             ((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_SH=
IFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIF=
T) |
+             ((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_SHIF=
T) |
+             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) && !W=
akeUpDisabledAps) {
+            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_SHIF=
T) |
+             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[Processor=
Number];
+      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_CP=
U_SHIFT) |
+         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;=
 ProcessorNumber++) {
+    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->Total=
Time, 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;=
 ProcessorNumber++) {
+    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; Process=
orNumber++) {
+    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; Process=
orNumber++) {
+    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; Proce=
ssorNumber++) {
+      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 CpuS=
tateDisabled) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CpuData               =3D &CpuMpData->CpuData[ProcessorNumber];
+  CpuData->WaitEvent    =3D WaitEvent;
+  CpuData->Finished     =3D Finished;
+  CpuData->ExpectedTime =3D CalculateTimeout (TimeoutInMicroseconds, &a=
mp;CpuData->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 + M=
axLogicalProcessorNumber);
+
+  InitializeSpinLock (&CpuMpData->MpLock);
+
+  //
+  // Set BSP basic information
+  //
+  InitializeApData (CpuMpData, 0, 0);
+
+  //
+  // Set up APs wakeup signal buffer and initialization APs ApicId status.
+  //
+  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) && (Index !=3D CpuMpData->Bs=
pNumber)) {
+      ((CPU_INFO_IN_HOB  *)CpuMpData->CpuInfoInHob)[Index].ApicId =3D I=
NVALID_APIC_ID;
+    }
+  }
+
+  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].Hea=
lth =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[ProcessorNu=
mber].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 CpuS=
tateDisabled) {
+    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) && (NumberOfEnabledProcesso=
rs =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 CpuStateDisabl=
ed) {
+      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/MpInitLib/LoongArch64/MpLib.h b/UefiCpuPkg/=
Library/MpInitLib/LoongArch64/MpLib.h
new file mode 100644
index 0000000000..b9c6c55b41
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_LIB_H_
+#define MP_LIB_H_
+
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Library/MpInitLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/HobLib.h>
+
+#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 MP_CPU_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 MP_CPU_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/MpInitLib/LoongArch64/PeiMpLib.c b/UefiCpuP=
kg/Library/MpInitLib/LoongArch64/PeiMpLib.c
new file mode 100644
index 0000000000..d1c5e55b57
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/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.<BR>
+  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 typ=
e
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The ran=
ge is
+                                      from 0 to the total number of logica=
l
+                                      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 ca=
n
+                                      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/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Lib=
rary/MpInitLib/PeiMpInitLib.inf
index bc3d716aa9..36ee6b9c29 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -2,6 +2,7 @@
 #  MP Initialize Library instance for PEI driver.
 #
 #  Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<B=
R>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights=
 reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,7 +19,7 @@
 #
 # The following information is for reference only and not required by the =
build tools.
 #
-#  VALID_ARCHITECTURES           =3D IA32 X64
+#  VALID_ARCHITECTURES           =3D IA32 X64 LOONGARCH64
 #
=20
 [Sources.IA32]
@@ -29,7 +30,7 @@
   X64/AmdSev.c
   X64/MpFuncs.nasm
=20
-[Sources.common]
+[Sources.IA32, Sources.X64]
   AmdSev.c
   MpEqu.inc
   PeiMpLib.c
@@ -37,23 +38,31 @@
   MpLib.h
   Microcode.c
   MpHandOff.h
+
+[Sources.LoongArch64]
+  LoongArch64/PeiMpLib.c
+  LoongArch64/MpLib.c
+  LoongArch64/MpLib.h
+
 [Packages]
   MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
   MdeModulePkg/MdeModulePkg.dec
=20
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
-  LocalApicLib
-  MemoryAllocationLib
-  HobLib
-  MtrrLib
   CpuLib
-  SynchronizationLib
-  PeiServicesLib
+  HobLib
+  MemoryAllocationLib
   PcdLib
+  PeiServicesLib
+  SynchronizationLib
+
+[LibraryClasses.IA32, LibraryClasses.X64]
   CcExitLib
+  LocalApicLib
   MicrocodeLib
+  MtrrLib
=20
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber        ## CONS=
UMES
=20
_._,_._,_

Groups.io Links:

=20 You receive all messages sent to this group. =20 =20

View/Reply Online (#114862) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [rebecca@openfw.io]

_._,_._,_
--------------GvTr1EN9nBuRh4M0klgw0w77--