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 EB31BD80127 for ; Wed, 31 Jan 2024 03:32:25 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=4LzSYYQ4f/dL0PuZP3ghKwarafReSIFnId0XITfqvPc=; 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=1706671944; v=1; b=KQgjgst14RKY7UPdUBvKYwRRWKPhWecALDDlG5CNVF6CeDFkokEM4p1wFSNb/BOS0K95pFIh fdMvy7xWc2Hmi70UtH0XBMINMHgRY4Beov4DbO7phwl//SlxhbLsDwWFl4IZSodcBr8SPiPIFUN /kZf1yEJNtnNdV4a6oDB4IC8= X-Received: by 127.0.0.2 with SMTP id CWJkYY7687511xGIYffRodmk; Tue, 30 Jan 2024 19:32:24 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.6659.1706671942166851270 for ; Tue, 30 Jan 2024 19:32:24 -0800 X-Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8CxLOtCv7llgsIIAA--.16249S3; Wed, 31 Jan 2024 11:32:18 +0800 (CST) X-Received: from [10.40.24.149] (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8AxHs8ov7llIHgpAA--.29596S4; Wed, 31 Jan 2024 11:32:17 +0800 (CST) Message-ID: <1d6f0aa4-a428-42a6-89db-0300d7ccc2f3@loongson.cn> Date: Wed, 31 Jan 2024 11:32:17 +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 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> In-Reply-To: <17ADD1DB56FC4702.24595@groups.io> X-CM-TRANSID: AQAAf8AxHs8ov7llIHgpAA--.29596S4 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQANCGW4s2EIuAAGs9 X-Coremail-Antispam: 1Uk129KBj9fXoWDuFW3Kr1UCFW7Jr4xAFWrZwc_yoWfJrWUXo WxA3yktw4UKrs3Wws5Crn5GF4fWFykursayry0qa4vyF1vqF13KrWj9w15JryfXa4kXF4D G34xJ34fAayayFyrl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrnUUv73VFW2AGmfu7bjvjm3AaLaJ3UjIYCTnIWjp_UUU5E7kC6x804xWl 14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwV WUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84ACjcxK6xIIjxv20xvE 14v26r4j6ryUM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4j6F4UM28EF7xvwVC2z280aV AFwI0_Cr0_Gr1UM28EF7xvwVC2z280aVCY1x0267AKxVW8Jr0_Cr1UM2AIxVAIcxkEcVAq 07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx1lYx0E2Ix0cI8IcVAFwI0_Jw0_Wr ylYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvEwIxGrwCj r7xvwVCIw2I0I7xG6c02F41l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr 1lx2IqxVAqx4xG67AKxVWUGVWUWwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE 14v26r126r1DMIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7 IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E 87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73Uj IFyTuYvjxUzfOzDUUUU 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: BTZTxuRcp9MrdVD8AgGDVdslx7686176AA= Content-Type: multipart/alternative; boundary="------------1Lm0tq9JvRGBVKPtAvxlYW5d" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=KQgjgst1; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io; dmarc=none --------------1Lm0tq9JvRGBVKPtAvxlYW5d Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Hi Ray, Can you please help to review this patch again? Thanks, Chao 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/L= ibrary/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. > +# Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -18,7 +19,7 @@ > # > # The following information is for reference only and not required by t= he 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/UefiCp= uPkg/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 right= s 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 sav= ed. > +**/ > +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 t= o > + 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 i= t. > + // > + 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; Pro= cessorNumber++) { > + 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until all= APs finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on all the= enabled > + APs, and go on executing immediate= ly. If > + all return from Procedure, or Time= outInMicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + all APs return from Procedure, the= n Procedure > + on the failed APs is terminated. A= ll enabled > + APs are available for next functio= n assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored= . Otherwise, > + if all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + The buffer is allocated by MP Init= ialization > + library, and it's the caller's res= ponsibility to > + free the buffer with FreePool() se= rvice. > + In blocking mode, it is ready for = consumption > + when the call returns. In non-bloc= king mode, > + it is ready when WaitEvent is sign= aled. The > + list of failed CPU is terminated b= y > + END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n dispatched > + to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made a= fter the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @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-pr= ovided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on the > + designated AP of the system. See t= ype > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The r= ange is > + from 0 to the total number of logi= cal > + processors minus 1. The total numb= er of > + logical processors can be retrieve= d by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until thi= s AP finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on this AP= , > + and go on executing immediately. I= f this AP > + return from Procedure or TimeoutIn= MicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + this AP to finish this Procedure, = either for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + this AP returns from Procedure, th= en Procedure > + on the AP is terminated. The > + AP is available for next function = assigned > + by MpInitLibStartupAllAPs() or > + MpInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e on the > + specified AP. > + @param[out] Finished If NULL, this parameter is ignored= . In > + blocking mode, this parameter is i= gnored. > + In non-blocking mode, if AP return= s from > + Procedure before the timeout expir= es, 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 finishe= d before > + the timeout expires. > + @retval EFI_SUCCESS In non-blocking mode, the function has= been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made a= fter the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @retval EFI_NOT_FOUND The processor with the handle specifie= d by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or d= isabled 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 o= nward. > + This service changes the BSP for all purposes. This call can only be p= erformed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to become= the new > + BSP. The range is from 0 to the total num= ber of > + logical processors minus 1. The total num= ber 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 disable= d. > + > + @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 specifie= d 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 initializ= ed. > + > +**/ > +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 o= nward. > + 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 o= f > + logical processors minus 1. The total num= ber of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the processor= for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that sp= ecifies > + the new health status of the AP. This fla= g > + corresponds to StatusFlag defined in > + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo= (). Only > + the PROCESSOR_HEALTH_STATUS_BIT is used. = All other > + bits are ignored. If it is NULL, this pa= rameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabl= ed 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 sup= ported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle specified by= ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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/UefiCpuPk= g/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 right= s 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 nu= mber 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); In= dex1 > 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], siz= eof (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_HO= B)); > + CopyMem ( > + &CpuInfoInHob[Index3], > + &CpuInfoInHob[Index1], > + sizeof (CPU_INFO_IN_HOB) > + ); > + CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HO= B)); > + > + // > + // Also exchange the StartupApSignal. > + // > + StartupApSignal =3D CpuMpData->CpuDat= a[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 obtai= ned before > + // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 Ma= ilbox0 is used > + // as the first broadcast method to wake up all APs, and all of APs wi= ll 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->CpuInfoIn= Hob); > + } > + > + // > + // 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 a= re checked in. > + // FinishedCount is the number of check-in APs. > + // > + CpuMpData->CpuCount =3D CpuMpData->FinishedCount + 1; > + ASSERT (CpuMpData->CpuCount <=3D PcdGet32 (PcdCpuMaxLogicalProcessorNu= mber)); > + > + // > + // 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", CpuM= pData->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].Star= tupApSignal; > + } 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].Star= tupApSignal; > + InterlockedCompareExchange32 ( > + (UINT32 *)ApStartupSignalBuffer, > + WAKEUP_AP_SIGNAL, > + 0 > + ); > + > + // > + // Invoke AP function here > + // > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D CpuSt= ateReady) { > + Procedure =3D (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumb= er].ApFunction; > + Parameter =3D (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunc= tionArgument; > + if (Procedure !=3D NULL) { > + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy= ); > + Procedure (Parameter); > + } > + > + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinish= ed); > + } > + } > + > + // > + // 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].St= artupApSignal; > + } > + > + // > + // 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 val= ue. > + > + Calculate the number of performance counter ticks required for a timeo= ut. > + If TimeoutInMicroseconds is 0, return value is also 0, which is recogn= ized > + as infinity. > + > + @param[in] TimeoutInMicroseconds Timeout value in microseconds. > + @param[out] CurrentTime Returns the current value of the p= erformance counter. > + > + @return Expected time stamp counter for timeout. > + If TimeoutInMicroseconds is 0, return value is also 0, which i= s 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 rec= ognized > + // 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 f= or the timeout value. > + // > + if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < Tim= estampCounterFreq) { > + // > + // Convert microseconds into seconds if direct multiplication overfl= ows > + // > + 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 TimeoutInMicrose= conds 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= for > + 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 performanc= e counter > + when it was last read. > + On output, the current value of the pe= rformance > + counter > + @param[in] TotalTime The total amount of elapsed time in pe= rformance > + counter ticks. > + @param[in] Timeout The number of performance counter tick= s required > + to reach a timeout condition. > + > + @retval TRUE A timeout condition has been reached. > + @retval FALSE A timeout condition has not been reach= ed. > + > +**/ > +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 spe= cified > + 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 *)AllocatePoo= l (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 functi= on > + @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 themselv= es. > + // > + 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_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) && !WakeUpD= isabledAps) { > + 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[ProcessorNumbe= r]; > + 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_SH= IFT) | > + 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= StartupAllAPs(). > + > + @param[out] NextProcessorNumber Pointer to the processor number of t= he 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; Pro= cessorNumber++) { > + 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 as= signed > + 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 t= imeout 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, CpuDat= a->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 St= artupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by S= tartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and timeout h= as 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; Pro= cessorNumber++) { > + 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= 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 s= afely 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 f= or 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 A= Ps. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] ExcludeBsp Whether let BSP also trig this tas= k. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +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; Processo= rNumber++) { > + 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; Processo= rNumber++) { > + 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; Proces= sorNumber++) { > + if (ProcessorNumber =3D=3D CallerNumber) { > + continue; > + } > + > + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, Procedur= eArgument, 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 call= er-provided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] Finished If AP returns from Procedure befor= e the > + timeout expires, its content is se= t to TRUE. > + Otherwise, the value is set to FAL= SE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finishe= d 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 ProcessorNumbe= r 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 CpuStateD= isabled) { > + return EFI_INVALID_PARAMETER; > + } > + > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->WaitEvent =3D WaitEvent; > + CpuData->Finished =3D Finished; > + CpuData->ExpectedTime =3D CalculateTimeout (TimeoutInMicroseconds, &Cp= uData->CurrentTime); > + CpuData->TotalTime =3D 0; > + > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgum= ent, FALSE); > + > + // > + // If WaitEvent is NULL, execute in blocking mode. > + // BSP checks AP's state until it finishes or TimeoutInMicrosecsond ex= pires. > + // > + 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. TimeoutInMicroseconds is= ignored > + for BSP. > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + > + @retval EFI_SUCCESS In blocking mode, all CPUs have finish= ed before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n 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 initializ= ed. > + @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 AP= s > + 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 (PcdCpuMaxLogicalProcessorNum= ber); > + } else { > + MaxLogicalProcessorNumber =3D OldCpuMpData->CpuCount; > + } > + > + ASSERT (MaxLogicalProcessorNumber !=3D 0); > + > + MonitorBufferSize =3D sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessorN= umber; > + > + BufferSize =3D 0; > + BufferSize +=3D MonitorBufferSize; > + BufferSize +=3D sizeof (CPU_MP_DATA); > + BufferSize +=3D (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* Max= LogicalProcessorNumber; > + 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 + MaxLo= gicalProcessorNumber); > + > + InitializeSpinLock (&CpuMpData->MpLock); > + > + // > + // Set BSP basic information > + // > + InitializeApData (CpuMpData, 0, 0); > + > + // > + // Set up APs wakeup signal buffer and initialization APs ApicId statu= s. > + // > + 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 IN= VALID_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].Heal= th =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 BS= P. > + > + @param[in] ProcessorNumber The handle number of processor. > + @param[out] ProcessorInfoBuffer A pointer to the buffer where inform= ation 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 specifie= d by > + ProcessorNumber does not exist in the = platform. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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[ProcessorNum= ber].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 CpuStateD= isabled) { > + 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= 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 o= f > + logical processors minus 1. The total num= ber of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle number wa= s returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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 numb= er of > + those logical processors that are enabled on this boot. This service m= ay only > + be called from the BSP. > + > + @param[out] NumberOfProcessors Pointer to the total number of= logical > + processors in the system, incl= uding the BSP > + and disabled APs. > + @param[out] NumberOfEnabledProcessors Pointer to the number of enabl= ed logical > + processors that exist in syste= m, including > + the BSP. > + > + @retval EFI_SUCCESS The number of logical processors and e= nabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberO= fEnabledProcessors > + is NULL. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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/UefiCpuPk= g/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 right= s 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, 0x= ad, 0x4a } \ > + } > + > +#define PROCESSOR_RESOURCE_HOB_GUID \ > + { \ > + 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x= 46, 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 sav= ed. > +**/ > +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 functi= on > + @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 A= Ps. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +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 call= er-provided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] Finished If AP returns from Procedure befor= e the > + timeout expires, its content is se= t to TRUE. > + Otherwise, the value is set to FAL= SE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finishe= d 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 po= int 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= for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that sp= ecifies > + 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 as= signed > + 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 t= imeout 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 St= artupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by S= tartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and timeout h= as 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/UefiCp= uPkg/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 right= s 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 sav= ed. > +**/ > +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 struct= ure 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 t= o > + 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until all= APs finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on all the= enabled > + APs, and go on executing immediate= ly. If > + all return from Procedure, or Time= outInMicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + all APs return from Procedure, the= n Procedure > + on the failed APs is terminated. A= ll enabled > + APs are available for next functio= n assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored= . Otherwise, > + if all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + The buffer is allocated by MP Init= ialization > + library, and it's the caller's res= ponsibility to > + free the buffer with FreePool() se= rvice. > + In blocking mode, it is ready for = consumption > + when the call returns. In non-bloc= king mode, > + it is ready when WaitEvent is sign= aled. The > + list of failed CPU is terminated b= y > + END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n dispatched > + to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made a= fter the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @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-pr= ovided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on the > + designated AP of the system. See t= ype > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The r= ange is > + from 0 to the total number of logi= cal > + processors minus 1. The total numb= er of > + logical processors can be retrieve= d by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller wi= th CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until thi= s AP finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on this AP= , > + and go on executing immediately. I= f this AP > + return from Procedure or TimeoutIn= MicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in micros= econds for > + this AP to finish this Procedure, = either for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + this AP returns from Procedure, th= en Procedure > + on the AP is terminated. The > + AP is available for next function = assigned > + by MpInitLibStartupAllAPs() or > + MpInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e on the > + specified AP. > + @param[out] Finished If NULL, this parameter is ignored= . In > + blocking mode, this parameter is i= gnored. > + In non-blocking mode, if AP return= s from > + Procedure before the timeout expir= es, 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 finishe= d before > + the timeout expires. > + @retval EFI_SUCCESS In non-blocking mode, the function has= been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made a= fter the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @retval EFI_NOT_FOUND The processor with the handle specifie= d by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or d= isabled 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 o= nward. > + This service changes the BSP for all purposes. This call can only be p= erformed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to become= the new > + BSP. The range is from 0 to the total num= ber of > + logical processors minus 1. The total num= ber 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 disable= d. > + > + @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 specifie= d 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 initializ= ed. > + > +**/ > +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 o= nward. > + 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 o= f > + logical processors minus 1. The total num= ber of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the processor= for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that sp= ecifies > + the new health status of the AP. This fla= g > + corresponds to StatusFlag defined in > + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo= (). Only > + the PROCESSOR_HEALTH_STATUS_BIT is used. = All other > + bits are ignored. If it is NULL, this pa= rameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabl= ed 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 sup= ported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle specified by= ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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/L= ibrary/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. > +# Copyright (c) 2024, Loongson Technology Corporation Limited. All righ= ts reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -18,7 +19,7 @@ > # > # The following information is for reference only and not required by t= he 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 ## C= ONSUMES -=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 (#114851): https://edk2.groups.io/g/devel/message/114851 Mute This Topic: https://groups.io/mt/104068953/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- --------------1Lm0tq9JvRGBVKPtAvxlYW5d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

Hi Ray,

Can you please help to review this patch again?


=
Thanks,
Chao
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 <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@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
_._,_._,_

Groups.io Links:

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

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

_._,_._,_
--------------1Lm0tq9JvRGBVKPtAvxlYW5d--