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=4584 > > Cc: Eric Dong > Cc: Ray Ni > Cc: Rahul Kumar > Cc: Gerd Hoffmann > Signed-off-by: Chao Li > --- > UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 27 +- > .../Library/MpInitLib/LoongArch64/DxeMpLib.c | 480 +++++ > .../Library/MpInitLib/LoongArch64/MpLib.c | 1621 +++++++++++++++++ > .../Library/MpInitLib/LoongArch64/MpLib.h | 361 ++++ > .../Library/MpInitLib/LoongArch64/PeiMpLib.c | 404 ++++ > UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 27 +- > 6 files changed, 2902 insertions(+), 18 deletions(-) > create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c > create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c > create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h > create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c > > diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf > index 55e46d4a1f..6db26f5fec 100644 > --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf > +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf > @@ -2,6 +2,7 @@ > # MP Initialize Library instance for DXE driver. > # > # Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.
> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -18,7 +19,7 @@ > # > # The following information is for reference only and not required by the build tools. > # > -# VALID_ARCHITECTURES = IA32 X64 > +# VALID_ARCHITECTURES = IA32 X64 LOONGARCH64 > # > > [Sources.IA32] > @@ -31,7 +32,7 @@ > X64/MpFuncs.nasm > X64/CreatePageTable.c > > -[Sources.common] > +[Sources.IA32, Sources.X64] > AmdSev.c > MpEqu.inc > DxeMpLib.c > @@ -40,24 +41,32 @@ > Microcode.c > MpHandOff.h > > +[Sources.LoongArch64] > + LoongArch64/DxeMpLib.c > + LoongArch64/MpLib.c > + LoongArch64/MpLib.h > + > [Packages] > MdePkg/MdePkg.dec > MdeModulePkg/MdeModulePkg.dec > UefiCpuPkg/UefiCpuPkg.dec > > -[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 > > diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c b/UefiCpuPkg/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.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "MpLib.h" > + > +#include > +#include > +#include > + > +#include > + > +CPU_MP_DATA *mCpuMpData = NULL; > +EFI_EVENT mCheckAllApsEvent = NULL; > +volatile BOOLEAN mStopCheckAllApsStatus = 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 != 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 = 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 = GetCpuMpData (); > + > + // > + // First, check whether pending StartupAllAPs() exists. > + // > + if (CpuMpData->WaitEvent != NULL) { > + Status = CheckAllAPs (); > + // > + // If all APs finish for StartupAllAPs(), signal the WaitEvent for it. > + // > + if (Status != EFI_NOT_READY) { > + Status = gBS->SignalEvent (CpuMpData->WaitEvent); > + CpuMpData->WaitEvent = NULL; > + } > + } > + > + // > + // Second, check whether pending StartupThisAPs() callings exist. > + // > + for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) { > + if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) { > + continue; > + } > + > + Status = CheckThisAP (ProcessorNumber); > + > + if (Status != EFI_NOT_READY) { > + gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent); > + CpuMpData->CpuData[ProcessorNumber].WaitEvent = 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 = gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + CheckApsStatus, > + NULL, > + &mCheckAllApsEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Set timer to check all APs status. > + // > + Status = 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 execute > + the function specified by Procedure one by > + one, in ascending order of processor handle > + number. If FALSE, then all the enabled APs > + execute the function specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until all APs finish > + or TimeoutInMicroSeconds expires. If it's > + not NULL, then execute in non-blocking mode. > + BSP requests the function specified by > + Procedure to be started on all the enabled > + APs, and go on executing immediately. If > + all return from Procedure, or TimeoutInMicroSeconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. Zero means > + infinity. If the timeout expires before > + all APs return from Procedure, then Procedure > + on the failed APs is terminated. All enabled > + APs are available for next function assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + 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 APs > + finish before timeout expires, then its > + content is set to address of the buffer > + holding handle numbers of the failed APs. > + The buffer is allocated by MP Initialization > + library, and it's the caller's responsibility to > + free the buffer with FreePool() service. > + In blocking mode, it is ready for consumption > + when the call returns. In non-blocking mode, > + it is ready when WaitEvent is signaled. 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 after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT 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 initialized. > + @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 = TRUE; > + > + Status = StartupAllCPUsWorker ( > + Procedure, > + SingleThread, > + TRUE, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + FailedCpuList > + ); > + > + // > + // Start checkAllApsStatus > + // > + mStopCheckAllApsStatus = FALSE; > + > + return Status; > +} > + > +/** > + This service lets the caller get one enabled AP to execute a caller-provided > + function. > + > + @param[in] Procedure A pointer to the function to be run on the > + designated AP of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The range is > + from 0 to the total number of logical > + processors minus 1. The total number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until this AP finish > + or TimeoutInMicroSeconds expires. If it's > + not NULL, then execute in non-blocking 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 TimeoutInMicroSeconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for > + this AP to finish this Procedure, either for > + blocking or non-blocking mode. Zero means > + infinity. If the timeout expires before > + this AP returns from Procedure, then Procedure > + on the AP is terminated. 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 timeout > + expires in non-blocking mode, WaitEvent > + 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 ignored. > + In non-blocking mode, if AP returns from > + Procedure before the timeout expires, 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 finished 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 after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT 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 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 disabled AP. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupThisAP ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + > + // > + // temporarily stop checkAllApsStatus for avoid resource dead-lock. > + // > + mStopCheckAllApsStatus = TRUE; > + > + Status = StartupThisAPWorker ( > + Procedure, > + ProcessorNumber, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + Finished > + ); > + > + mStopCheckAllApsStatus = FALSE; > + > + return Status; > +} > + > +/** > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. This call can only be performed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] 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 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 specified 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 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 onward. > + This service may only be called from the BSP. > + > + @param[in] ProcessorNumber The handle number of AP. > + The range is from 0 to the total number of > + logical processors minus 1. The total number 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 specifies > + 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. All other > + bits are ignored. If it is NULL, this parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabled 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 supported. > + @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 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "MpLib.h" > + > +#include > +#include > + > +#define INVALID_APIC_ID 0xFFFFFFFF > + > +EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID; > +EFI_GUID mProcessorResourceHobGuid = 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 = 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 = 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 = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; > + > + TotalProcessorNumber = CpuMpData->CpuCount; > + for (Index = 0; Index < TotalProcessorNumber; Index++) { > + if (CpuInfoInHob[Index].ApicId == GetApicId ()) { > + *ProcessorNumber = 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 number 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 = CpuMpData->CpuCount - 1; > + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; > + if (ApCount != 0) { > + Index2 = 0; > + for (Index1 = (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1); Index1 > 0; Index1--) { > + if (CpuInfoInHob[Index1].ApicId != INVALID_APIC_ID) { > + if (Index1 == ApCount) { > + break; > + } else { > + for ( ; Index2 <= ApCount; Index2++) { > + if (CpuInfoInHob[Index2].ApicId == INVALID_APIC_ID) { > + CopyMem (&CpuInfoInHob[Index2], &CpuInfoInHob[Index1], sizeof (CPU_INFO_IN_HOB)); > + CpuMpData->CpuData[Index2] = CpuMpData->CpuData[Index1]; > + CpuInfoInHob[Index1].ApicId = INVALID_APIC_ID; > + break; > + } > + } > + } > + } else { > + continue; > + } > + } > + > + for (Index1 = 0; Index1 < ApCount; Index1++) { > + Index3 = Index1; > + // > + // Sort key is the hardware default APIC ID > + // > + ApicId = CpuInfoInHob[Index1].ApicId; > + for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) { > + if (ApicId > CpuInfoInHob[Index2].ApicId) { > + Index3 = Index2; > + ApicId = CpuInfoInHob[Index2].ApicId; > + } > + } > + > + if (Index3 != 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 = CpuMpData->CpuData[Index3].StartupApSignal; > + CpuMpData->CpuData[Index3].StartupApSignal = > + CpuMpData->CpuData[Index1].StartupApSignal; > + CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal; > + } > + } > + > + // > + // Get the processor number for the BSP > + // > + ApicId = GetApicId (); > + for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) { > + if (CpuInfoInHob[Index1].ApicId == ApicId) { > + CpuMpData->BspNumber = (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 = NULL; > + GuidHob = GetFirstGuidHob (&mProcessorResourceHobGuid); > + if (GuidHob != NULL) { > + DataInHob = GET_GUID_HOB_DATA (GuidHob); > + ResourceData = (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 = NULL; > + > + // > + // Set the default loop mode for APs. > + // > + CpuMpData->ApLoopMode = ApInRunLoop; > + > + // > + // Beacuse LoongArch does not have SIPI now, the APIC ID must be obtained before > + // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 Mailbox0 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 = GetProcessorResourceDataFromGuidedHob (); > + > + if (ProcessorResourceData != NULL) { > + CpuMpData->ApLoopMode = ApInHltLoop; > + CpuMpData->CpuCount = ProcessorResourceData->CpuCount; > + CpuMpData->CpuInfoInHob = (UINTN)(ProcessorResourceData->CpuInfoInHob); > + } > + > + // > + // Send 1st broadcast IPI to APs to wakeup APs > + // > + CpuMpData->InitFlag = ApInitConfig; > + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, FALSE); > + CpuMpData->InitFlag = ApInitDone; > + > + // > + // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in. > + // FinishedCount is the number of check-in APs. > + // > + CpuMpData->CpuCount = CpuMpData->FinishedCount + 1; > + ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); > + > + // > + // 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", CpuMpData->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 = (CPU_INFO_IN_HOB *)(UINTN)(CpuMpData->CpuInfoInHob); > + > + CpuInfoInHob[ProcessorNumber].ApicId = GetApicId (); > + CpuInfoInHob[ProcessorNumber].Health = BistData; > + > + CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE; > + CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 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 = ExchangeInfo->CpuMpData; > + > + while (TRUE) { > + if (CpuMpData->InitFlag == ApInitConfig) { > + ProcessorNumber = ApIndex; > + // > + // If the AP can running to here, then the BIST must be zero. > + // > + InitializeApData (CpuMpData, ProcessorNumber, 0); > + ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + } else { > + // > + // Execute AP function if AP is ready > + // > + GetProcessorNumber (CpuMpData, &ProcessorNumber); > + > + // > + // Clear AP start-up signal when AP waken up > + // > + ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + InterlockedCompareExchange32 ( > + (UINT32 *)ApStartupSignalBuffer, > + WAKEUP_AP_SIGNAL, > + 0 > + ); > + > + // > + // Invoke AP function here > + // > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) { > + Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction; > + Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument; > + if (Procedure != NULL) { > + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy); > + Procedure (Parameter); > + } > + > + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished); > + } > + } > + > + // > + // Updates the finished count > + // > + InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount); > + > + while (TRUE) { > + // > + // Clean per-core mail box registers. > + // > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF1, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF2, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0); > + > + // > + // Enable IPI interrupt and global interrupt > + // > + EnableLocalInterrupts (BIT12); > + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFU); > + EnableInterrupts (); > + > + // > + // Ap entry HLT mode > + // > + CpuSleep (); > + > + // > + // Disable global interrupts when wake up > + // > + DisableInterrupts (); > + > + // > + // Update CpuMpData > + // > + if (CpuMpData != ExchangeInfo->CpuMpData) { > + CpuMpData = ExchangeInfo->CpuMpData; > + GetProcessorNumber (CpuMpData, &ProcessorNumber); > + ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + } > + > + // > + // Break out of the loop if wake up signal is not NULL. > + // > + if (*ApStartupSignalBuffer == 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 recognized > + as infinity. > + > + @param[in] TimeoutInMicroseconds Timeout value in microseconds. > + @param[out] CurrentTime Returns the current value of the performance counter. > + > + @return Expected time stamp counter for timeout. > + If TimeoutInMicroseconds is 0, return value is also 0, which is recognized > + as infinity. > + > +**/ > +UINT64 > +CalculateTimeout ( > + IN UINTN TimeoutInMicroseconds, > + OUT UINT64 *CurrentTime > + ) > +{ > + UINT64 TimeoutInSeconds; > + UINT64 TimestampCounterFreq; > + > + // > + // Read the current value of the performance counter > + // > + *CurrentTime = GetPerformanceCounter (); > + > + // > + // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized > + // as infinity. > + // > + if (TimeoutInMicroseconds == 0) { > + return 0; > + } > + > + // > + // GetPerformanceCounterProperties () returns the timestamp counter's frequency > + // in Hz. > + // > + TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL); > + > + // > + // Check the potential overflow before calculate the number of ticks for the timeout value. > + // > + if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) { > + // > + // Convert microseconds into seconds if direct multiplication overflows > + // > + TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000); > + // > + // Assertion if the final tick count exceeds MAX_UINT64 > + // > + ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq); > + return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds); > + } else { > + // > + // No overflow case, multiply the return value with TimeoutInMicroseconds 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 performance counter > + when it was last read. > + On output, the current value of the performance > + counter > + @param[in] TotalTime The total amount of elapsed time in performance > + 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 == 0) { > + return FALSE; > + } > + > + GetPerformanceCounterProperties (&Start, &End); > + Cycle = End - Start; > + if (Cycle < 0) { > + Cycle = -Cycle; > + } > + > + Cycle++; > + CurrentTime = GetPerformanceCounter (); > + Delta = (INT64)(CurrentTime - *PreviousTime); > + if (Start > End) { > + Delta = -Delta; > + } > + > + if (Delta < 0) { > + Delta += Cycle; > + } > + > + *TotalTime += Delta; > + *PreviousTime = CurrentTime; > + if (*TotalTime > Timeout) { > + return TRUE; > + } > + > + return FALSE; > +} > + > +/** > + Helper function that waits until the finished AP count reaches the specified > + 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 == 0) explicitly. > + // > + if (TimeLimit == 0) { > + return; > + } > + > + CpuMpData->TotalTime = 0; > + CpuMpData->ExpectedTime = CalculateTimeout ( > + TimeLimit, > + &CpuMpData->CurrentTime > + ); > + while (CpuMpData->FinishedCount < FinishedApLimit && > + !CheckTimeout ( > + &CpuMpData->CurrentTime, > + &CpuMpData->TotalTime, > + CpuMpData->ExpectedTime > + )) > + { > + CpuPause (); > + } > + > + if (CpuMpData->FinishedCount >= FinishedApLimit) { > + DEBUG (( > + DEBUG_VERBOSE, > + "%a: reached FinishedApLimit=%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 > + ) != 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 = (MP_CPU_EXCHANGE_INFO *)AllocatePool (sizeof (MP_CPU_EXCHANGE_INFO)); > + } > + > + ExchangeInfo = CpuMpData->MpCpuExchangeInfo; > + ExchangeInfo->CpuMpData = 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 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 = 0; > + > + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; > + > + if (CpuMpData->InitFlag != ApInitDone) { > + FillExchangeInfoData (CpuMpData); > + } > + > + ExchangeInfo = CpuMpData->MpCpuExchangeInfo; > + // > + // If InitFlag is ApInitConfig, broadcasts all APs to initize themselves. > + // > + if (CpuMpData->InitFlag == ApInitConfig) { > + DEBUG ((DEBUG_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", __func__, ApWakeupFunction, (UINTN)ExchangeInfo)); > + if (CpuMpData->ApLoopMode == ApInHltLoop) { > + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { > + if (Index != 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 = 0; Index < CpuMpData->CpuCount; Index++) { > + if (Index != CpuMpData->BspNumber) { > + CpuData = &CpuMpData->CpuData[Index]; > + if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) { > + continue; > + } > + > + CpuData->ApFunction = (UINTN)Procedure; > + CpuData->ApFunctionArgument = (UINTN)ProcedureArgument; > + SetApState (CpuData, CpuStateReady); > + *(UINT32 *)CpuData->StartupApSignal = 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 = 0; Index < CpuMpData->CpuCount; Index++) { > + CpuData = &CpuMpData->CpuData[Index]; > + if (Index != CpuMpData->BspNumber) { > + WaitApWakeup (CpuData->StartupApSignal); > + } > + } > + } else { > + CpuData = &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->ApFunction = (UINTN)Procedure; > + CpuData->ApFunctionArgument = (UINTN)ProcedureArgument; > + SetApState (CpuData, CpuStateReady); > + // > + // Wakeup specified AP > + // > + *(UINT32 *)CpuData->StartupApSignal = 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_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 StartupAllAPs(). > + > + @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP. > + > + @retval EFI_SUCCESS The next waiting AP has been found. > + @retval EFI_NOT_FOUND No waiting AP exists. > + > +**/ > +EFI_STATUS > +GetNextWaitingProcessorNumber ( > + OUT UINTN *NextProcessorNumber > + ) > +{ > + UINTN ProcessorNumber; > + CPU_MP_DATA *CpuMpData; > + > + CpuMpData = GetCpuMpData (); > + > + for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) { > + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { > + *NextProcessorNumber = ProcessorNumber; > + return EFI_SUCCESS; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] ProcessorNumber The handle number of processor. > + > + @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired. > +**/ > +EFI_STATUS > +CheckThisAP ( > + IN UINTN ProcessorNumber > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + CPU_AP_DATA *CpuData; > + > + CpuMpData = GetCpuMpData (); > + CpuData = &CpuMpData->CpuData[ProcessorNumber]; > + > + // > + // If the AP finishes for StartupThisAP(), return EFI_SUCCESS. > + // > + if (GetApState (CpuData) == CpuStateFinished) { > + if (CpuData->Finished != NULL) { > + *(CpuData->Finished) = TRUE; > + } > + > + SetApState (CpuData, CpuStateIdle); > + return EFI_SUCCESS; > + } else { > + // > + // If timeout expires for StartupThisAP(), report timeout. > + // > + if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) { > + if (CpuData->Finished != NULL) { > + *(CpuData->Finished) = FALSE; > + } > + > + return EFI_TIMEOUT; > + } > + } > + > + return EFI_NOT_READY; > +} > + > +/** > + Checks status of all APs. > + > + This function checks whether all APs have finished task assigned by StartupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and timeout has not expired. > +**/ > +EFI_STATUS > +CheckAllAPs ( > + VOID > + ) > +{ > + UINTN ProcessorNumber; > + UINTN NextProcessorNumber; > + EFI_STATUS Status; > + CPU_MP_DATA *CpuMpData; > + CPU_AP_DATA *CpuData; > + > + CpuMpData = GetCpuMpData (); > + > + NextProcessorNumber = 0; > + > + // > + // Go through all APs that are responsible for the StartupAllAPs(). > + // > + for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) { > + if (!CpuMpData->CpuData[ProcessorNumber].Waiting) { > + continue; > + } > + > + CpuData = &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 safely make use of its value. > + // > + if (GetApState (CpuData) == CpuStateFinished) { > + CpuMpData->RunningCount--; > + CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE; > + SetApState (CpuData, CpuStateIdle); > + > + // > + // If in Single Thread mode, then search for the next waiting AP for execution. > + // > + if (CpuMpData->SingleThread) { > + Status = 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 == 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 execute > + the function specified by Procedure one by > + one, in ascending order of processor handle > + number. If FALSE, then all the enabled APs > + execute the function specified by Procedure > + simultaneously. > + @param[in] 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 microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, then its > + content is set to NULL. If not all APs > + finish before timeout expires, then its > + content is set to address of the buffer > + holding handle numbers of the failed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has been dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +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 = GetCpuMpData (); > + > + if (FailedCpuList != NULL) { > + *FailedCpuList = NULL; > + } > + > + if ((CpuMpData->CpuCount == 1) && ExcludeBsp) { > + return EFI_NOT_STARTED; > + } > + > + if (Procedure == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber != CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Update AP state > + // > + CheckAndUpdateApsStatus (); > + > + ProcessorCount = CpuMpData->CpuCount; > + HasEnabledAp = FALSE; > + // > + // Check whether all enabled APs are idle. > + // If any enabled AP is not idle, return EFI_NOT_READY. > + // > + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { > + CpuData = &CpuMpData->CpuData[ProcessorNumber]; > + if (ProcessorNumber != CpuMpData->BspNumber) { > + ApState = GetApState (CpuData); > + if (ApState != CpuStateDisabled) { > + HasEnabledAp = TRUE; > + if (ApState != 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 = 0; > + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { > + CpuData = &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->Waiting = FALSE; > + if (ProcessorNumber != CpuMpData->BspNumber) { > + if (CpuData->State == CpuStateIdle) { > + // > + // Mark this processor as responsible for current calling. > + // > + CpuData->Waiting = TRUE; > + CpuMpData->RunningCount++; > + } > + } > + } > + > + CpuMpData->Procedure = Procedure; > + CpuMpData->ProcArguments = ProcedureArgument; > + CpuMpData->SingleThread = SingleThread; > + CpuMpData->FinishedCount = 0; > + CpuMpData->ExpectedTime = CalculateTimeout ( > + TimeoutInMicroseconds, > + &CpuMpData->CurrentTime > + ); > + CpuMpData->TotalTime = 0; > + CpuMpData->WaitEvent = WaitEvent; > + > + if (!SingleThread) { > + WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE); > + } else { > + for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) { > + if (ProcessorNumber == CallerNumber) { > + continue; > + } > + > + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE); > + break; > + } > + } > + } > + > + if (!ExcludeBsp) { > + // > + // Start BSP. > + // > + Procedure (ProcedureArgument); > + } > + > + Status = EFI_SUCCESS; > + if (WaitEvent == NULL) { > + do { > + Status = CheckAllAPs (); > + } while (Status == 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 microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] 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 = GetCpuMpData (); > + > + if (Finished != NULL) { > + *Finished = FALSE; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber != CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Check whether processor with the handle specified by ProcessorNumber exists > + // > + if (ProcessorNumber >= CpuMpData->CpuCount) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Check whether specified processor is BSP > + // > + if (ProcessorNumber == CpuMpData->BspNumber) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check parameter Procedure > + // > + if (Procedure == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Update AP state > + // > + CheckAndUpdateApsStatus (); > + > + // > + // Check whether specified AP is disabled > + // > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) { > + return EFI_INVALID_PARAMETER; > + } > + > + CpuData = &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->WaitEvent = WaitEvent; > + CpuData->Finished = Finished; > + CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime); > + CpuData->TotalTime = 0; > + > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, FALSE); > + > + // > + // If WaitEvent is NULL, execute in blocking mode. > + // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires. > + // > + Status = EFI_SUCCESS; > + if (WaitEvent == NULL) { > + do { > + Status = CheckThisAP (ProcessorNumber); > + } while (Status == 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 microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. Zero means > + infinity. TimeoutInMicroseconds is ignored > + 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 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 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 = GetCpuMpDataFromGuidedHob (); > + if (OldCpuMpData == NULL) { > + MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber); > + } else { > + MaxLogicalProcessorNumber = OldCpuMpData->CpuCount; > + } > + > + ASSERT (MaxLogicalProcessorNumber != 0); > + > + MonitorBufferSize = sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessorNumber; > + > + BufferSize = 0; > + BufferSize += MonitorBufferSize; > + BufferSize += sizeof (CPU_MP_DATA); > + BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber; > + MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize)); > + ASSERT (MpBuffer != NULL); > + ZeroMem (MpBuffer, BufferSize); > + > + CpuMpData = (CPU_MP_DATA *)MpBuffer; > + > + CpuMpData->CpuCount = 1; > + CpuMpData->BspNumber = 0; > + CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1); > + CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber); > + > + InitializeSpinLock (&CpuMpData->MpLock); > + > + // > + // Set BSP basic information > + // > + InitializeApData (CpuMpData, 0, 0); > + > + // > + // Set up APs wakeup signal buffer and initialization APs ApicId status. > + // > + for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) { > + CpuMpData->CpuData[Index].StartupApSignal = > + (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof (WAKEUP_AP_SIGNAL) * Index)); > + if ((OldCpuMpData == NULL) && (Index != CpuMpData->BspNumber)) { > + ((CPU_INFO_IN_HOB *)CpuMpData->CpuInfoInHob)[Index].ApicId = INVALID_APIC_ID; > + } > + } > + > + if (OldCpuMpData == 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 = OldCpuMpData->CpuCount; > + CpuMpData->BspNumber = OldCpuMpData->BspNumber; > + CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; > + CpuMpData->MpCpuExchangeInfo = OldCpuMpData->MpCpuExchangeInfo; > + > + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; > + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { > + InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock); > + CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 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 = ApInitReconfig; > + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE); > + > + // > + // Wait for all APs finished initialization > + // > + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { > + CpuPause (); > + } > + > + CpuMpData->InitFlag = ApInitDone; > + } > + > + if (MaxLogicalProcessorNumber > 1) { > + for (Index = 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 information 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 platform. > + @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 = GetCpuMpData (); > + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber != CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + if (ProcessorInfoBuffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (ProcessorNumber >= CpuMpData->CpuCount) { > + return EFI_NOT_FOUND; > + } > + > + ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId; > + ProcessorInfoBuffer->StatusFlag = 0; > + if (ProcessorNumber == CpuMpData->BspNumber) { > + ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT; > + } > + > + if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) { > + ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT; > + } > + > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) { > + ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT; > + } else { > + ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT; > + } > + > + if (HealthData != NULL) { > + HealthData->Uint32 = 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 of > + logical processors minus 1. The total number 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 == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + CpuMpData = 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 logical > + processors in the system, including 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 enabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors > + 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 = GetCpuMpData (); > + > + if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber != CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + ProcessorNumber = CpuMpData->CpuCount; > + EnabledProcessorNumber = 0; > + for (Index = 0; Index < ProcessorNumber; Index++) { > + if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) { > + EnabledProcessorNumber++; > + } > + } > + > + if (NumberOfProcessors != NULL) { > + *NumberOfProcessors = ProcessorNumber; > + } > + > + if (NumberOfEnabledProcessors != NULL) { > + *NumberOfEnabledProcessors = 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 = NULL; > + GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid); > + > + if (GuidHob != NULL) { > + DataInHob = GET_GUID_HOB_DATA (GuidHob); > + CpuMpData = (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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef MP_LIB_H_ > +#define MP_LIB_H_ > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') > + > +#define CPU_INIT_MP_LIB_HOB_GUID \ > + { \ > + 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \ > + } > + > +#define PROCESSOR_RESOURCE_HOB_GUID \ > + { \ > + 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x46, 0x7e } \ > + } > + > +// > +// AP loop state when APs are in idle state > +// It's value is the same with PcdCpuApLoopMode > +// > +typedef enum { > + ApInHltLoop = 1, > + ApInRunLoop = 2 > +} AP_LOOP_MODE; > + > +// > +// AP initialization state during APs wakeup > +// > +typedef enum { > + ApInitConfig = 1, > + ApInitReconfig = 2, > + ApInitDone = 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 broadcast mode. > +**/ > +VOID > +WakeUpAP ( > + IN CPU_MP_DATA *CpuMpData, > + IN BOOLEAN Broadcast, > + IN UINTN ProcessorNumber, > + IN EFI_AP_PROCEDURE Procedure OPTIONAL, > + IN VOID *ProcedureArgument OPTIONAL, > + IN BOOLEAN WakeUpDisabledAps > + ); > + > +/** > + Initialize global data for MP support. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure. > +**/ > +VOID > +InitMpGlobalData ( > + IN CPU_MP_DATA *CpuMpData > + ); > + > +/** > + Worker function to execute a caller provided function on all enabled APs. > + > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs execute > + the function specified by Procedure one by > + one, in ascending order of processor handle > + number. If FALSE, then all the enabled APs > + execute the function specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, then its > + content is set to NULL. If not all APs > + finish before timeout expires, then its > + content is set to address of the buffer > + holding handle numbers of the failed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has been dispatched > + to all enabled APs. > + @retval others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +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 microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] 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 point 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 specifies > + 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 assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] ProcessorNumber The handle number of processor. > + > + @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired. > +**/ > +EFI_STATUS > +CheckThisAP ( > + IN UINTN ProcessorNumber > + ); > + > +/** > + Checks status of all APs. > + > + This function checks whether all APs have finished task assigned by StartupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and timeout has not expired. > +**/ > +EFI_STATUS > +CheckAllAPs ( > + VOID > + ); > + > +/** > + Checks APs status and updates APs status if needed. > + > +**/ > +VOID > +CheckAndUpdateApsStatus ( > + VOID > + ); > + > +/** > + Enable Debug Agent to support source debugging on AP function. > + This instance will added in the future. > + > +**/ > +VOID > +EnableDebugAgent ( > + VOID > + ); > + > +#endif > diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c b/UefiCpuPkg/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.
> + 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 = GetCpuMpDataFromGuidedHob (); > + ASSERT (CpuMpData != 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 = (UINT64)(UINTN)CpuMpData; > + BuildGuidDataHob ( > + &mCpuInitMpLibHobGuid, > + (VOID *)&Data64, > + sizeof (UINT64) > + ); > +} > + > +/** > + Save the Processor Resource Data. > + > + @param[in] ResourceData The pointer to Processor Resource Data structure will be saved. > +**/ > +VOID > +SaveProcessorResourceData ( > + IN PROCESSOR_RESOURCE_DATA *ResourceData > + ) > +{ > + UINT64 Data64; > + > + // > + // Build location of Processor Resource Data buffer in HOB > + // > + Data64 = (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 execute > + the function specified by Procedure one by > + one, in ascending order of processor handle > + number. If FALSE, then all the enabled APs > + execute the function specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until all APs finish > + or TimeoutInMicroSeconds expires. If it's > + not NULL, then execute in non-blocking mode. > + BSP requests the function specified by > + Procedure to be started on all the enabled > + APs, and go on executing immediately. If > + all return from Procedure, or TimeoutInMicroSeconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for > + APs to return from Procedure, either for > + blocking or non-blocking mode. Zero means > + infinity. If the timeout expires before > + all APs return from Procedure, then Procedure > + on the failed APs is terminated. All enabled > + APs are available for next function assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + 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 APs > + finish before timeout expires, then its > + content is set to address of the buffer > + holding handle numbers of the failed APs. > + The buffer is allocated by MP Initialization > + library, and it's the caller's responsibility to > + free the buffer with FreePool() service. > + In blocking mode, it is ready for consumption > + when the call returns. In non-blocking mode, > + it is ready when WaitEvent is signaled. 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 after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT 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 initialized. > + @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 != 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-provided > + function. > + > + @param[in] Procedure A pointer to the function to be run on the > + designated AP of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The range is > + from 0 to the total number of logical > + processors minus 1. The total number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until this AP finish > + or TimeoutInMicroSeconds expires. If it's > + not NULL, then execute in non-blocking 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 TimeoutInMicroSeconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for > + this AP to finish this Procedure, either for > + blocking or non-blocking mode. Zero means > + infinity. If the timeout expires before > + this AP returns from Procedure, then Procedure > + on the AP is terminated. 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 timeout > + expires in non-blocking mode, WaitEvent > + 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 ignored. > + In non-blocking mode, if AP returns from > + Procedure before the timeout expires, 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 finished 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 after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT 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 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 disabled AP. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupThisAP ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + if (WaitEvent != NULL) { > + return EFI_UNSUPPORTED; > + } > + > + return StartupThisAPWorker ( > + Procedure, > + ProcessorNumber, > + NULL, > + TimeoutInMicroseconds, > + ProcedureArgument, > + Finished > + ); > +} > + > +/** > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. This call can only be performed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] 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 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 specified 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 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 onward. > + This service may only be called from the BSP. > + > + @param[in] ProcessorNumber The handle number of AP. > + The range is from 0 to the total number of > + logical processors minus 1. The total number 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 specifies > + 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. All other > + bits are ignored. If it is NULL, this parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabled 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 supported. > + @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 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/Library/MpInitLib/PeiMpInitLib.inf > index bc3d716aa9..36ee6b9c29 100644 > --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf > +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf > @@ -2,6 +2,7 @@ > # MP Initialize Library instance for PEI driver. > # > # Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.
> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -18,7 +19,7 @@ > # > # The following information is for reference only and not required by the build tools. > # > -# VALID_ARCHITECTURES = IA32 X64 > +# VALID_ARCHITECTURES = IA32 X64 LOONGARCH64 > # > > [Sources.IA32] > @@ -29,7 +30,7 @@ > X64/AmdSev.c > X64/MpFuncs.nasm > > -[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 > > -[LibraryClasses] > +[LibraryClasses.common] > BaseLib > - LocalApicLib > - MemoryAllocationLib > - HobLib > - MtrrLib > CpuLib > - SynchronizationLib > - PeiServicesLib > + HobLib > + MemoryAllocationLib > PcdLib > + PeiServicesLib > + SynchronizationLib > + > +[LibraryClasses.IA32, LibraryClasses.X64] > CcExitLib > + LocalApicLib > MicrocodeLib > + MtrrLib > > [Pcd] > gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES -=-=-=-=-=-=-=-=-=-=-=- 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] -=-=-=-=-=-=-=-=-=-=-=-