From: "Chao Li" <lichao@loongson.cn>
To: devel@edk2.groups.io, Ray Ni <ray.ni@intel.com>,
Laszlo Ersek <lersek@redhat.com>
Cc: Eric Dong <eric.dong@intel.com>,
Rahul Kumar <rahul1.kumar@intel.com>,
Gerd Hoffmann <kraxel@redhat.com>
Subject: Re: [edk2-devel] [PATCH v8 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64
Date: Wed, 31 Jan 2024 13:33:22 +0800 [thread overview]
Message-ID: <a107e24a-edb4-4fee-a8d9-d2ae7db4d3b2@loongson.cn> (raw)
In-Reply-To: <17AF511741BD9C8B.15701@groups.io>
[-- Attachment #1: Type: text/plain, Size: 116755 bytes --]
Hi Ray and Laszlo,
I would very much like to be merged into stable202302, the soft feature
deadline is 2024-02-05, so could you please hlep to review this patch as
soon as passable? Please...
Thanks,
Chao
On 2024/1/31 11:32, Chao Li wrote:
>
> Hi Ray,
>
> Can you please help to review this patch again?
>
> On 2024/1/26 14:29, Chao Li wrote:
>> Added LoongArch multiprocessor initialization instance into MpInitLib.
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> 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/Library/MpInitLib/DxeMpInitLib.inf
>> index 55e46d4a1f..6db26f5fec 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> @@ -2,6 +2,7 @@
>> # MP Initialize Library instance for DXE driver.
>> #
>> # Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.<BR>
>> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All 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 = 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.<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 = 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.<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 = 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.<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 = 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.<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 = 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.<BR>
>> +# 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 = 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 (#114862): https://edk2.groups.io/g/devel/message/114862
Mute This Topic: https://groups.io/mt/104070182/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 110838 bytes --]
next prev parent reply other threads:[~2024-01-31 5:33 UTC|newest]
Thread overview: 89+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-26 6:27 [edk2-devel] [PATCH v8 00/37] Enable LoongArch virtual machine in edk2 Chao Li
2024-01-26 6:27 ` [edk2-devel] [PATCH v8 01/37] MdePkg: Add the header file named Csr.h for LoongArch64 Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 02/37] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 03/37] MdePkg: Add LoongArch64 exception function set into BaseLib Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 04/37] MdePkg: Add LoongArch64 local interrupt " Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 05/37] MdePkg: Add LoongArch Cpucfg function Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 06/37] MdePkg: Add read stable counter operation for LoongArch Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 07/37] MdePkg: Add CSR " Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 08/37] MdePkg: Add IOCSR " Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 09/37] MdePkg: Add a new library named PeiServicesTablePointerLibKs0 Chao Li
2024-01-26 6:28 ` [edk2-devel] [PATCH v8 10/37] MdePkg: Add some comments for LoongArch exceptions Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 11/37] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
2024-02-02 3:24 ` Ni, Ray
2024-02-02 3:38 ` Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 12/37] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
2024-02-02 3:30 ` Ni, Ray
2024-02-02 3:44 ` Chao Li
2024-02-02 4:30 ` Ni, Ray
2024-03-08 8:02 ` Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 13/37] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 14/37] UefiCpuPkg: Add CpuMmuLib " Chao Li
2024-01-31 9:47 ` Laszlo Ersek
2024-02-01 7:57 ` Chao Li
2024-02-01 22:46 ` Laszlo Ersek
2024-02-02 3:30 ` Chao Li
2024-02-02 3:33 ` Ni, Ray
2024-02-02 3:50 ` Chao Li
2024-02-02 4:30 ` Ni, Ray
2024-03-01 1:26 ` Chao Li
2024-03-01 11:27 ` Laszlo Ersek
2024-03-04 3:39 ` Chao Li
2024-03-05 9:26 ` Laszlo Ersek
2024-03-05 11:50 ` Chao Li
2024-03-05 12:09 ` Laszlo Ersek
2024-03-05 12:12 ` Chao Li
[not found] ` <17B87F9FA8D0E543.14067@groups.io>
2024-03-01 1:53 ` Chao Li
2024-01-31 10:33 ` Pedro Falcato
2024-01-31 13:41 ` Laszlo Ersek
2024-01-31 17:46 ` Pedro Falcato
2024-02-01 3:05 ` Chao Li
2024-02-01 19:36 ` Pedro Falcato
2024-02-01 23:02 ` Laszlo Ersek
2024-02-02 15:14 ` Leif Lindholm
2024-02-04 2:58 ` Chao Li
[not found] ` <17B0898B4883051D.13964@groups.io>
2024-02-06 2:57 ` Chao Li
2024-02-06 14:32 ` Laszlo Ersek
2024-02-06 16:45 ` Pedro Falcato
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 16/37] UefiCpuPkg: Add CpuDxe driver " Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 17/37] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64 Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 18/37] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg Chao Li
2024-02-01 23:20 ` Laszlo Ersek
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 19/37] UefiCpuPkg: Add a new CPU IO 2 driver named CpuMmio2Dxe Chao Li
2024-01-26 6:29 ` [edk2-devel] [PATCH v8 20/37] ArmVirtPkg: Enable CpuMmio2Dxe Chao Li
2024-02-01 22:19 ` Laszlo Ersek
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 21/37] OvmfPkg/RiscVVirt: " Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 22/37] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 23/37] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg Chao Li
2024-01-29 19:27 ` Laszlo Ersek
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 24/37] ArmVirtPkg: Move two PCD variables into OvmfPkg Chao Li
2024-01-29 19:49 ` Laszlo Ersek
2024-01-30 1:24 ` Chao Li
2024-01-30 16:45 ` Laszlo Ersek
2024-01-31 1:30 ` Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 25/37] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
2024-01-29 19:51 ` Laszlo Ersek
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 26/37] OvmfPkg/LoongArchVirt: Add stable timer driver Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 27/37] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 28/37] OvmfPkg/LoongArchVirt: Add serial port hook library Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 29/37] OvmfPkg/LoongArchVirt: Add the early serial port output library Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 30/37] OvmfPkg/LoongArchVirt: Add real time clock library Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 31/37] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib Chao Li
2024-01-26 6:30 ` [edk2-devel] [PATCH v8 32/37] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib Chao Li
2024-01-26 6:31 ` [edk2-devel] [PATCH v8 33/37] OvmfPkg/LoongArchVirt: Add reset system library Chao Li
2024-01-26 6:31 ` [edk2-devel] [PATCH v8 34/37] OvmfPkg/LoongArchVirt: Support SEC phase Chao Li
2024-01-26 6:31 ` [edk2-devel] [PATCH v8 35/37] OvmfPkg/LoongArchVirt: Support PEI phase Chao Li
2024-01-26 6:31 ` [edk2-devel] [PATCH v8 36/37] OvmfPkg/LoongArchVirt: Add build file Chao Li
2024-01-26 6:31 ` [edk2-devel] [PATCH v8 37/37] OvmfPkg/LoongArchVirt: Add self introduction file Chao Li
[not found] ` <17ADD1D5A196C454.24595@groups.io>
2024-01-31 3:30 ` [edk2-devel] [PATCH v8 11/37] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
[not found] ` <17AF510405DE784C.15701@groups.io>
2024-01-31 5:28 ` Chao Li
2024-01-31 10:47 ` Laszlo Ersek
[not found] ` <17ADD1D7001C37D6.11113@groups.io>
2024-01-31 3:31 ` [edk2-devel] [PATCH v8 12/37] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
[not found] ` <17AF510933F4B8FA.15701@groups.io>
2024-01-31 5:29 ` Chao Li
[not found] ` <17ADD1D9CA04F352.11113@groups.io>
2024-01-31 3:31 ` [edk2-devel] [PATCH v8 14/37] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Chao Li
[not found] ` <17AF511188DE2475.15701@groups.io>
2024-01-31 5:32 ` Chao Li
[not found] ` <17ADD1DB56FC4702.24595@groups.io>
2024-01-31 3:32 ` [edk2-devel] [PATCH v8 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
[not found] ` <17AF511741BD9C8B.15701@groups.io>
2024-01-31 5:33 ` Chao Li [this message]
[not found] ` <17ADD1DCBDD4B7FE.11113@groups.io>
2024-01-31 3:32 ` [edk2-devel] [PATCH v8 16/37] UefiCpuPkg: Add CpuDxe driver " Chao Li
[not found] ` <17AF511F29808828.16460@groups.io>
2024-01-31 5:33 ` Chao Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a107e24a-edb4-4fee-a8d9-d2ae7db4d3b2@loongson.cn \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox