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 LoongArch64 CPU driver into CpuDxe. >> >> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584 >> >> Cc: Eric Dong >> Cc: Ray Ni >> Cc: Rahul Kumar >> Cc: Gerd Hoffmann >> Signed-off-by: Chao Li >> Co-authored-by: Baoqi Zhang >> Co-authored-by: Dongyan Qian >> --- >> UefiCpuPkg/CpuDxe/CpuDxe.inf | 23 +- >> UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c | 454 ++++++++++++++++++ >> UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h | 288 ++++++++++++ >> UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c | 544 ++++++++++++++++++++++ >> UefiCpuPkg/CpuDxe/LoongArch64/Exception.c | 159 +++++++ >> 5 files changed, 1464 insertions(+), 4 deletions(-) >> create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c >> create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h >> create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c >> create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c >> >> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf >> index 1d3e9f8cdb..18ebd2eb2c 100644 >> --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf >> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf >> @@ -3,6 +3,7 @@ >> # >> # Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.
>> # Copyright (c) 2017, AMD Incorporated. All rights reserved.
>> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
>> # >> # SPDX-License-Identifier: BSD-2-Clause-Patent >> # >> @@ -22,17 +23,16 @@ >> MdeModulePkg/MdeModulePkg.dec >> UefiCpuPkg/UefiCpuPkg.dec >> >> -[LibraryClasses] >> +[LibraryClasses.common] >> BaseLib >> BaseMemoryLib >> CpuLib >> + CacheMaintenanceLib >> DebugLib >> DxeServicesTableLib >> MemoryAllocationLib >> - MtrrLib >> UefiBootServicesTableLib >> UefiDriverEntryPoint >> - LocalApicLib >> UefiLib >> CpuExceptionHandlerLib >> HobLib >> @@ -41,7 +41,14 @@ >> TimerLib >> PeCoffGetEntryPointLib >> >> -[Sources] >> +[LibraryClasses.IA32, LibraryClasses.X64] >> + LocalApicLib >> + MtrrLib >> + >> +[LibraryClasses.LoongArch64] >> + CpuMmuLib >> + >> +[Sources.IA32, Sources.X64] >> CpuDxe.c >> CpuDxe.h >> CpuGdt.c >> @@ -59,6 +66,13 @@ >> X64/CpuAsm.nasm >> X64/PagingAttribute.c >> >> +[Sources.LoongArch64] >> + CpuMp.h >> + LoongArch64/CpuDxe.c >> + LoongArch64/CpuMp.c >> + LoongArch64/Exception.c >> + LoongArch64/CpuDxe.h >> + >> [Protocols] >> gEfiCpuArchProtocolGuid ## PRODUCES >> gEfiMpServiceProtocolGuid ## PRODUCES >> @@ -77,6 +91,7 @@ >> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES >> gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES >> gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES >> + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress ## CONSUMES >> gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES >> gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES >> gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask ## CONSUMES >> diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c >> new file mode 100644 >> index 0000000000..65ed0b3913 >> --- /dev/null >> +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c >> @@ -0,0 +1,454 @@ >> +/** @file CpuDxe.c >> + >> + CPU DXE Module to produce CPU ARCH Protocol. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#include "CpuDxe.h" >> +#include "CpuMp.h" >> +#include >> +#include >> +#include >> +#include >> + >> +UINT64 mTimerPeriod = 0; >> + >> +/** >> + IPI Interrupt Handler. >> + >> + @param InterruptType The type of interrupt that occurred >> + @param SystemContext A pointer to the system context when the interrupt occurred >> +**/ >> +VOID >> +EFIAPI >> +IpiInterruptHandler ( >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_SYSTEM_CONTEXT SystemContext >> + ); >> + >> +// >> +// Globals used to initialize the protocol >> +// >> +EFI_HANDLE mCpuHandle = NULL; >> +EFI_CPU_ARCH_PROTOCOL gCpu = { >> + CpuFlushCpuDataCache, >> + CpuEnableInterrupt, >> + CpuDisableInterrupt, >> + CpuGetInterruptState, >> + CpuInit, >> + CpuRegisterInterruptHandler, >> + CpuGetTimerValue, >> + CpuSetMemoryAttributes, >> + 0, // NumberOfTimers >> + 4, // DmaBufferAlignment >> +}; >> + >> +/** >> + This function flushes the range of addresses from Start to Start+Length >> + from the processor's data cache. If Start is not aligned to a cache line >> + boundary, then the bytes before Start to the preceding cache line boundary >> + are also flushed. If Start+Length is not aligned to a cache line boundary, >> + then the bytes past Start+Length to the end of the next cache line boundary >> + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be >> + supported. If the data cache is fully coherent with all DMA operations, then >> + this function can just return EFI_SUCCESS. If the processor does not support >> + flushing a range of the data cache, then the entire data cache can be flushed. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param Start The beginning physical address to flush from the processor's data >> + cache. >> + @param Length The number of bytes to flush from the processor's data cache. This >> + function may flush more bytes than Length specifies depending upon >> + the granularity of the flush operation that the processor supports. >> + @param FlushType Specifies the type of flush operation to perform. >> + >> + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from >> + the processor's data cache. >> + @retval EFI_INVALID_PARAMETER The processor does not support the cache flush type specified >> + by FlushType. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuFlushCpuDataCache ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_PHYSICAL_ADDRESS Start, >> + IN UINT64 Length, >> + IN EFI_CPU_FLUSH_TYPE FlushType >> + ) >> +{ >> + switch (FlushType) { >> + case EfiCpuFlushTypeWriteBack: >> + WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); >> + break; >> + case EfiCpuFlushTypeInvalidate: >> + InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); >> + break; >> + case EfiCpuFlushTypeWriteBackInvalidate: >> + WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); >> + break; >> + default: >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function enables interrupt processing by the processor. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @retval EFI_SUCCESS Interrupts are enabled on the processor. >> + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuEnableInterrupt ( >> + IN EFI_CPU_ARCH_PROTOCOL *This >> + ) >> +{ >> + EnableInterrupts (); >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function disables interrupt processing by the processor. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @retval EFI_SUCCESS Interrupts are disabled on the processor. >> + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuDisableInterrupt ( >> + IN EFI_CPU_ARCH_PROTOCOL *This >> + ) >> +{ >> + DisableInterrupts (); >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function retrieves the processor's current interrupt state a returns it in >> + State. If interrupts are currently enabled, then TRUE is returned. If interrupts >> + are currently disabled, then FALSE is returned. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param State A pointer to the processor's current interrupt state. Set to TRUE if >> + interrupts are enabled and FALSE if interrupts are disabled. >> + >> + @retval EFI_SUCCESS The processor's current interrupt state was returned in State. >> + @retval EFI_INVALID_PARAMETER State is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuGetInterruptState ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + OUT BOOLEAN *State >> + ) >> +{ >> + if (State == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + *State = GetInterruptState (); >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function generates an INIT on the processor. If this function succeeds, then the >> + processor will be reset, and control will not be returned to the caller. If InitType is >> + not supported by this processor, or the processor cannot programmatically generate an >> + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error >> + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param InitType The type of processor INIT to perform. >> + >> + @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. >> + @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported >> + by this processor. >> + @retval EFI_DEVICE_ERROR The processor INIT failed. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuInit ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_CPU_INIT_TYPE InitType >> + ) >> +{ >> + return EFI_UNSUPPORTED; >> +} >> + >> +/** >> + Registers a function to be called from the CPU interrupt handler. >> + >> + @param This Protocol instance structure >> + @param InterruptType Defines which interrupt to hook. IA-32 >> + valid range is 0x00 through 0xFF >> + @param InterruptHandler A pointer to a function of type >> + EFI_CPU_INTERRUPT_HANDLER that is called >> + when a processor interrupt occurs. A null >> + pointer is an error condition. >> + >> + @retval EFI_SUCCESS If handler installed or uninstalled. >> + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler >> + for InterruptType was previously installed. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for >> + InterruptType was not previously installed. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType >> + is not supported. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuRegisterInterruptHandler ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler >> + ) >> +{ >> + return RegisterInterruptHandler (InterruptType, InterruptHandler); >> +} >> + >> +/** >> + Returns a timer value from one of the CPU's internal timers. There is no >> + inherent time interval between ticks but is a function of the CPU frequency. >> + >> + @param This - Protocol instance structure. >> + @param TimerIndex - Specifies which CPU timer is requested. >> + @param TimerValue - Pointer to the returned timer value. >> + @param TimerPeriod - A pointer to the amount of time that passes >> + in femtoseconds (10-15) for each increment >> + of TimerValue. If TimerValue does not >> + increment at a predictable rate, then 0 is >> + returned. The amount of time that has >> + passed between two calls to GetTimerValue() >> + can be calculated with the formula >> + (TimerValue2 - TimerValue1) * TimerPeriod. >> + This parameter is optional and may be NULL. >> + >> + @retval EFI_SUCCESS - If the CPU timer count was returned. >> + @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers. >> + @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer. >> + @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuGetTimerValue ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN UINT32 TimerIndex, >> + OUT UINT64 *TimerValue, >> + OUT UINT64 *TimerPeriod OPTIONAL >> + ) >> +{ >> + UINT64 BeginValue; >> + UINT64 EndValue; >> + >> + if (TimerValue == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + if (TimerIndex != 0) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + *TimerValue = AsmReadStableCounter (); >> + >> + if (TimerPeriod != NULL) { >> + if (mTimerPeriod == 0) { >> + // >> + // Read time stamp counter before and after delay of 100 microseconds >> + // >> + BeginValue = AsmReadStableCounter (); >> + MicroSecondDelay (100); >> + EndValue = AsmReadStableCounter (); >> + // >> + // Calculate the actual frequency >> + // >> + mTimerPeriod = DivU64x64Remainder ( >> + MultU64x32 ( >> + 1000 * 1000 * 1000, >> + 100 >> + ), >> + EndValue - BeginValue, >> + NULL >> + ); >> + } >> + >> + *TimerPeriod = mTimerPeriod; >> + } >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function modifies the attributes for the memory region specified by BaseAddress and >> + Length from their current attributes to the attributes specified by Attributes. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param BaseAddress The physical address that is the start address of a memory region. >> + @param Length The size in bytes of the memory region. >> + @param EfiAttributes The bit mask of attributes to set for the memory region. >> + >> + @retval EFI_SUCCESS The attributes were set for the memory region. >> + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by >> + BaseAddress and Length cannot be modified. >> + @retval EFI_INVALID_PARAMETER Length is zero. >> + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of >> + the memory resource range. >> + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory >> + resource range specified by BaseAddress and Length. >> + The bit mask of attributes is not support for the memory resource >> + range specified by BaseAddress and Length. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuSetMemoryAttributes ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 EfiAttributes >> + ) >> +{ >> + EFI_STATUS Status; >> + UINTN LoongArchAttributes; >> + UINTN RegionBaseAddress; >> + UINTN RegionLength; >> + UINTN RegionLoongArchAttributes; >> + >> + RegionLength = Length; >> + Status = EFI_SUCCESS; >> + >> + if ((BaseAddress & (EFI_PAGE_SIZE - 1)) != 0) { >> + // >> + // Minimum granularity is SIZE_4KB. >> + // >> + DEBUG (( >> + DEBUG_INFO, >> + "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n", >> + BaseAddress, >> + Length, >> + EfiAttributes >> + )); >> + >> + Status = EFI_UNSUPPORTED; >> + >> + return Status; >> + } >> + >> + // >> + // Convert the 'Attribute' into LoongArch Attribute >> + // >> + LoongArchAttributes = EfiAttributeConverse (EfiAttributes); >> + >> + // >> + // Get the region starting from 'BaseAddress' and its 'Attribute' >> + // >> + RegionBaseAddress = BaseAddress; >> + Status = GetMemoryRegionAttributes ( >> + RegionBaseAddress, >> + &RegionLength, >> + &RegionLoongArchAttributes >> + ); >> + >> + // >> + // Data & Instruction Caches are flushed when we set new memory attributes. >> + // So, we only set the attributes if the new region is different. >> + // >> + if ((Status == EFI_NOT_FOUND) || (RegionLoongArchAttributes != LoongArchAttributes) || >> + ((BaseAddress + Length) > (RegionBaseAddress + RegionLength))) >> + { >> + Status = SetMemoryRegionAttributes (BaseAddress, Length, EfiAttributes, 0x0); >> + } >> + >> + ASSERT_EFI_ERROR (Status); >> + >> + return Status; >> +} >> + >> +/** >> + Callback function for idle events. >> + >> + @param Event Event whose notification function is being invoked. >> + @param Context The pointer to the notification function's context, >> + which is implementation-dependent. >> + >> +**/ >> +VOID >> +EFIAPI >> +IdleLoopEventCallback ( >> + IN EFI_EVENT Event, >> + IN VOID *Context >> + ) >> +{ >> + CpuSleep (); >> +} >> + >> +/** >> + Initialize the state information for the CPU Architectural Protocol. >> + >> + @param ImageHandle Image handle this driver. >> + @param SystemTable Pointer to the System Table. >> + >> + @retval EFI_SUCCESS Thread can be successfully created >> + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure >> + @retval EFI_DEVICE_ERROR Cannot create the thread >> + >> +**/ >> +EFI_STATUS >> +InitializeCpu ( >> + IN EFI_HANDLE ImageHandle, >> + IN EFI_SYSTEM_TABLE *SystemTable >> + ) >> +{ >> + EFI_STATUS Status; >> + EFI_EVENT IdleLoopEvent; >> + >> + InitializeExceptions (&gCpu); >> + >> + Status = gBS->InstallMultipleProtocolInterfaces ( >> + &mCpuHandle, >> + &gEfiCpuArchProtocolGuid, >> + &gCpu, >> + NULL >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + Status = gCpu.RegisterInterruptHandler ( >> + &gCpu, >> + EXCEPT_LOONGARCH_INT_IPI, >> + IpiInterruptHandler >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + // >> + // Setup a callback for idle events >> + // >> + Status = gBS->CreateEventEx ( >> + EVT_NOTIFY_SIGNAL, >> + TPL_NOTIFY, >> + IdleLoopEventCallback, >> + NULL, >> + &gIdleLoopEventGuid, >> + &IdleLoopEvent >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + InitializeMpSupport (); >> + >> + return Status; >> +} >> diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h >> new file mode 100644 >> index 0000000000..8bfbfa3442 >> --- /dev/null >> +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h >> @@ -0,0 +1,288 @@ >> +/** @file CpuDxe.c >> + >> + CPU DXE Module to produce CPU ARCH Protocol. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#ifndef CPU_DXE_H_ >> +#define CPU_DXE_H_ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> + >> +// >> +// For coding convenience, define the maximum valid >> +// LoongArch exception. >> +// Since UEFI V2.11, it will be present in DebugSupport.h. >> +// >> +#define MAX_LOONGARCH_EXCEPTION 64 >> + >> +/* >> + This function flushes the range of addresses from Start to Start+Length >> + from the processor's data cache. If Start is not aligned to a cache line >> + boundary, then the bytes before Start to the preceding cache line boundary >> + are also flushed. If Start+Length is not aligned to a cache line boundary, >> + then the bytes past Start+Length to the end of the next cache line boundary >> + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be >> + supported. If the data cache is fully coherent with all DMA operations, then >> + this function can just return EFI_SUCCESS. If the processor does not support >> + flushing a range of the data cache, then the entire data cache can be flushed. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param Start The beginning physical address to flush from the processor's data >> + cache. >> + @param Length The number of bytes to flush from the processor's data cache. This >> + function may flush more bytes than Length specifies depending upon >> + the granularity of the flush operation that the processor supports. >> + @param FlushType Specifies the type of flush operation to perform. >> + >> + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from >> + the processor's data cache. >> + @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified >> + by FlushType. >> + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed >> + from the processor's data cache. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuFlushCpuDataCache ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_PHYSICAL_ADDRESS Start, >> + IN UINT64 Length, >> + IN EFI_CPU_FLUSH_TYPE FlushType >> + ); >> + >> +/** >> + This function enables interrupt processing by the processor. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @retval EFI_SUCCESS Interrupts are enabled on the processor. >> + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuEnableInterrupt ( >> + IN EFI_CPU_ARCH_PROTOCOL *This >> + ); >> + >> +/** >> + This function disables interrupt processing by the processor. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @retval EFI_SUCCESS Interrupts are disabled on the processor. >> + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuDisableInterrupt ( >> + IN EFI_CPU_ARCH_PROTOCOL *This >> + ); >> + >> +/** >> + This function retrieves the processor's current interrupt state a returns it in >> + State. If interrupts are currently enabled, then TRUE is returned. If interrupts >> + are currently disabled, then FALSE is returned. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param State A pointer to the processor's current interrupt state. Set to TRUE if >> + interrupts are enabled and FALSE if interrupts are disabled. >> + >> + @retval EFI_SUCCESS The processor's current interrupt state was returned in State. >> + @retval EFI_INVALID_PARAMETER State is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuGetInterruptState ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + OUT BOOLEAN *State >> + ); >> + >> +/** >> + This function generates an INIT on the processor. If this function succeeds, then the >> + processor will be reset, and control will not be returned to the caller. If InitType is >> + not supported by this processor, or the processor cannot programmatically generate an >> + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error >> + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param InitType The type of processor INIT to perform. >> + >> + @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. >> + @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported >> + by this processor. >> + @retval EFI_DEVICE_ERROR The processor INIT failed. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuInit ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_CPU_INIT_TYPE InitType >> + ); >> + >> +/** >> + Registers a function to be called from the CPU interrupt handler. >> + >> + @param This Protocol instance structure >> + @param InterruptType Defines which interrupt to hook. IA-32 >> + valid range is 0x00 through 0xFF >> + @param InterruptHandler A pointer to a function of type >> + EFI_CPU_INTERRUPT_HANDLER that is called >> + when a processor interrupt occurs. A null >> + pointer is an error condition. >> + >> + @retval EFI_SUCCESS If handler installed or uninstalled. >> + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler >> + for InterruptType was previously installed. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for >> + InterruptType was not previously installed. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType >> + is not supported. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuRegisterInterruptHandler ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler >> + ); >> + >> +/** >> + Returns a timer value from one of the CPU's internal timers. There is no >> + inherent time interval between ticks but is a function of the CPU frequency. >> + >> + @param This - Protocol instance structure. >> + @param TimerIndex - Specifies which CPU timer is requested. >> + @param TimerValue - Pointer to the returned timer value. >> + @param TimerPeriod - A pointer to the amount of time that passes >> + in femtoseconds (10-15) for each increment >> + of TimerValue. If TimerValue does not >> + increment at a predictable rate, then 0 is >> + returned. The amount of time that has >> + passed between two calls to GetTimerValue() >> + can be calculated with the formula >> + (TimerValue2 - TimerValue1) * TimerPeriod. >> + This parameter is optional and may be NULL. >> + >> + @retval EFI_SUCCESS - If the CPU timer count was returned. >> + @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers. >> + @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer. >> + @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuGetTimerValue ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN UINT32 TimerIndex, >> + OUT UINT64 *TimerValue, >> + OUT UINT64 *TimerPeriod OPTIONAL >> + ); >> + >> +/** >> + This function registers and enables the handler specified by InterruptHandler for a processor >> + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the >> + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. >> + The installed handler is called once for each processor interrupt or exception. >> + >> + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts >> + are enabled and FALSE if interrupts are disabled. >> + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called >> + when a processor interrupt occurs. If this parameter is NULL, then the handler >> + will be uninstalled. >> + >> + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. >> + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was >> + previously installed. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not >> + previously installed. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. >> + >> +**/ >> +EFI_STATUS >> +RegisterInterruptHandler ( >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler >> + ); >> + >> +/** >> + This function modifies the attributes for the memory region specified by BaseAddress and >> + Length from their current attributes to the attributes specified by Attributes. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param BaseAddress The physical address that is the start address of a memory region. >> + @param Length The size in bytes of the memory region. >> + @param Attributes The bit mask of attributes to set for the memory region. >> + >> + @retval EFI_SUCCESS The attributes were set for the memory region. >> + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by >> + BaseAddress and Length cannot be modified. >> + @retval EFI_INVALID_PARAMETER Length is zero. >> + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of >> + the memory resource range. >> + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory >> + resource range specified by BaseAddress and Length. >> + The bit mask of attributes is not support for the memory resource >> + range specified by BaseAddress and Length. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +CpuSetMemoryAttributes ( >> + IN EFI_CPU_ARCH_PROTOCOL *This, >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 Attributes >> + ); >> + >> +/** >> + Initialize interrupt handling for DXE phase. >> + >> + @param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @return VOID. >> + >> +**/ >> +VOID >> +InitializeExceptions ( >> + IN EFI_CPU_ARCH_PROTOCOL *gCpu >> + ); >> + >> +/** >> + Converts EFI Attributes to corresponding architecture Attributes. >> + >> + @param[in] EfiAttributes Efi Attributes. >> + >> + @retval Corresponding architecture attributes. >> +**/ >> +UINTN >> +EFIAPI >> +EfiAttributeConverse ( >> + IN UINTN EfiAttributes >> + ); >> + >> +#endif // CPU_DXE_H_ >> diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c >> new file mode 100644 >> index 0000000000..3325914e53 >> --- /dev/null >> +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c >> @@ -0,0 +1,544 @@ >> +/** @file >> + CPU DXE Module to produce CPU MP Protocol. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#include "CpuDxe.h" >> +#include "CpuMp.h" >> + >> +EFI_HANDLE mMpServiceHandle = NULL; >> +UINTN mNumberOfProcessors = 1; >> + >> +EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = { >> + GetNumberOfProcessors, >> + GetProcessorInfo, >> + StartupAllAPs, >> + StartupThisAP, >> + SwitchBSP, >> + EnableDisableAP, >> + WhoAmI >> +}; >> + >> +/** >> + This service 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. >> + >> + This function is used to retrieve the following information: >> + - The number of logical processors that are present in the system. >> + - The number of enabled logical processors in the system at the instant >> + this call is made. >> + >> + Because MP Service Protocol provides services to enable and disable processors >> + dynamically, the number of enabled logical processors may vary during the >> + course of a boot session. >> + >> + If this service is called from an AP, then EFI_DEVICE_ERROR is returned. >> + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then >> + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors >> + is returned in NumberOfProcessors, the number of currently enabled processor >> + is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL >> + instance. >> + @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. >> + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +GetNumberOfProcessors ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + OUT UINTN *NumberOfProcessors, >> + OUT UINTN *NumberOfEnabledProcessors >> + ) >> +{ >> + if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + return MpInitLibGetNumberOfProcessors ( >> + NumberOfProcessors, >> + NumberOfEnabledProcessors >> + ); >> +} >> + >> +/** >> + 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. >> + >> + This service retrieves detailed MP-related information about any processor >> + on the platform. Note the following: >> + - The processor information may change during the course of a boot session. >> + - The information presented here is entirely MP related. >> + >> + Information regarding the number of caches and their sizes, frequency of operation, >> + slot numbers is all considered platform-related information and is not provided >> + by this service. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL >> + instance. >> + @param[in] ProcessorNumber The handle number of processor. >> + @param[out] ProcessorInfoBuffer A pointer to the buffer where information for >> + the requested processor is deposited. >> + >> + @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. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +GetProcessorInfo ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + IN UINTN ProcessorNumber, >> + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer >> + ) >> +{ >> + return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL); >> +} >> + >> +/** >> + This service executes a caller provided function on all enabled APs. APs can >> + run either simultaneously or one at a time in sequence. This service supports >> + both blocking and non-blocking requests. The non-blocking requests use EFI >> + events so the BSP can detect when the APs have finished. This service may only >> + be called from the BSP. >> + >> + This function is used to dispatch all the enabled APs to the function specified >> + by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned >> + immediately and Procedure is not started on any AP. >> + >> + If SingleThread is TRUE, all the enabled APs execute the function specified by >> + Procedure one by one, in ascending order of processor handle number. Otherwise, >> + all the enabled APs execute the function specified by Procedure simultaneously. >> + >> + If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all >> + APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking >> + mode, and the BSP returns from this service without waiting for APs. If a >> + non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT >> + is signaled, then EFI_UNSUPPORTED must be returned. >> + >> + If the timeout specified by TimeoutInMicroseconds expires before all APs return >> + from Procedure, then Procedure on the failed APs is terminated. All enabled APs >> + are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() >> + and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its >> + content points to the list of processor handle numbers in which Procedure was >> + terminated. >> + >> + Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() >> + to make sure that the nature of the code that is executed on the BSP and the >> + dispatched APs is well controlled. The MP Services Protocol does not guarantee >> + that the Procedure function is MP-safe. Hence, the tasks that can be run in >> + parallel are limited to certain independent tasks and well-controlled exclusive >> + code. EFI services and protocols may not be called by APs unless otherwise >> + specified. >> + >> + In blocking execution mode, BSP waits until all APs finish or >> + TimeoutInMicroseconds expires. >> + >> + In non-blocking execution mode, BSP is freed to return to the caller and then >> + proceed to the next task without having to wait for APs. The following >> + sequence needs to occur in a non-blocking execution mode: >> + >> + -# The caller that intends to use this MP Services Protocol in non-blocking >> + mode creates WaitEvent by calling the EFI CreateEvent() service. The caller >> + invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent >> + is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests >> + the function specified by Procedure to be started on all the enabled APs, >> + and releases the BSP to continue with other tasks. >> + -# The caller can use the CheckEvent() and WaitForEvent() services to check >> + the state of the WaitEvent created in step 1. >> + -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP >> + Service signals WaitEvent by calling the EFI SignalEvent() function. If >> + FailedCpuList is not NULL, its content is available when WaitEvent is >> + signaled. If all APs returned from Procedure prior to the timeout, then >> + FailedCpuList is set to NULL. If not all APs return from Procedure before >> + the timeout, then FailedCpuList is filled in with the list of the failed >> + APs. The buffer is allocated by MP Service Protocol using AllocatePool(). >> + It is the caller's responsibility to free the buffer with FreePool() service. >> + -# This invocation of SignalEvent() function informs the caller that invoked >> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed >> + the specified task or a timeout occurred. The contents of FailedCpuList >> + can be examined to determine which APs did not complete the specified task >> + prior to the timeout. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL >> + instance. >> + @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 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() >> + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). >> + 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 Service Protocol, >> + 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_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_TIMEOUT In blocking mode, the timeout expired before >> + all enabled APs have finished. >> + @retval EFI_INVALID_PARAMETER Procedure is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +StartupAllAPs ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + IN EFI_AP_PROCEDURE Procedure, >> + IN BOOLEAN SingleThread, >> + IN EFI_EVENT WaitEvent OPTIONAL, >> + IN UINTN TimeoutInMicroseconds, >> + IN VOID *ProcedureArgument OPTIONAL, >> + OUT UINTN **FailedCpuList OPTIONAL >> + ) >> +{ >> + return MpInitLibStartupAllAPs ( >> + Procedure, >> + SingleThread, >> + WaitEvent, >> + TimeoutInMicroseconds, >> + ProcedureArgument, >> + FailedCpuList >> + ); >> +} >> + >> +/** >> + This service lets the caller get one enabled AP to execute a caller-provided >> + function. The caller can request the BSP to either wait for the completion >> + of the AP or just proceed with the next task by using the EFI event mechanism. >> + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking >> + execution support. This service may only be called from the BSP. >> + >> + This function is used to dispatch one enabled AP to the function specified by >> + Procedure passing in the argument specified by ProcedureArgument. If WaitEvent >> + is NULL, execution is in blocking mode. The BSP waits until the AP finishes or >> + TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode. >> + BSP proceeds to the next task without waiting for the AP. If a non-blocking mode >> + is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, >> + then EFI_UNSUPPORTED must be returned. >> + >> + If the timeout specified by TimeoutInMicroseconds expires before the AP returns >> + from Procedure, then execution of Procedure by the AP is terminated. The AP is >> + available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and >> + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL >> + instance. >> + @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 >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). >> + @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 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() >> + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). >> + 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_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_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 >> +StartupThisAP ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + IN EFI_AP_PROCEDURE Procedure, >> + IN UINTN ProcessorNumber, >> + IN EFI_EVENT WaitEvent OPTIONAL, >> + IN UINTN TimeoutInMicroseconds, >> + IN VOID *ProcedureArgument OPTIONAL, >> + OUT BOOLEAN *Finished OPTIONAL >> + ) >> +{ >> + return MpInitLibStartupThisAP ( >> + Procedure, >> + ProcessorNumber, >> + WaitEvent, >> + 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. >> + >> + This service switches the requested AP to be the BSP from that point onward. >> + This service changes the BSP for all purposes. The new BSP can take over the >> + execution of the old BSP and continue seamlessly from where the old one left >> + off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT >> + is signaled. >> + >> + If the BSP cannot be switched prior to the return from this service, then >> + EFI_UNSUPPORTED must be returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. >> + @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 >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). >> + @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. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +SwitchBSP ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + IN UINTN ProcessorNumber, >> + IN BOOLEAN EnableOldBSP >> + ) >> +{ >> + return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP); >> +} >> + >> +/** >> + This service lets the caller enable or disable an AP from this point onward. >> + This service may only be called from the BSP. >> + >> + This service allows the caller enable or disable an AP from this point onward. >> + The caller can optionally specify the health status of the AP by Health. If >> + an AP is being disabled, then the state of the disabled AP is implementation >> + dependent. If an AP is enabled, then the implementation must guarantee that a >> + complete initialization sequence is performed on the AP, so the AP is in a state >> + that is compatible with an MP operating system. This service may not be supported >> + after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled. >> + >> + If the enable or disable AP operation cannot be completed prior to the return >> + from this service, then EFI_UNSUPPORTED must be returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. >> + @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 >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). >> + @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. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +EnableDisableAP ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + IN UINTN ProcessorNumber, >> + IN BOOLEAN EnableAP, >> + IN UINT32 *HealthFlag OPTIONAL >> + ) >> +{ >> + return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag); >> +} >> + >> +/** >> + This return the handle number for the calling processor. This service may be >> + called from the BSP and APs. >> + >> + This service returns the processor handle number for the calling processor. >> + The returned value is in the range from 0 to the total number of logical >> + processors minus 1. The total number of logical processors can be retrieved >> + with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be >> + called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER >> + is returned. Otherwise, the current processors handle number is returned in >> + ProcessorNumber, and EFI_SUCCESS is returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. >> + @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 >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). >> + >> + @retval EFI_SUCCESS The current processor handle number was returned >> + in ProcessorNumber. >> + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +WhoAmI ( >> + IN EFI_MP_SERVICES_PROTOCOL *This, >> + OUT UINTN *ProcessorNumber >> + ) >> +{ >> + return MpInitLibWhoAmI (ProcessorNumber); >> +} >> + >> +/** >> + Initialize Multi-processor support. >> +**/ >> +VOID >> +InitializeMpSupport ( >> + VOID >> + ) >> +{ >> + EFI_STATUS Status; >> + UINTN NumberOfProcessors; >> + UINTN NumberOfEnabledProcessors; >> + >> + // >> + // Wakeup APs to do initialization >> + // >> + Status = MpInitLibInitialize (); >> + ASSERT_EFI_ERROR (Status); >> + >> + MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors); >> + mNumberOfProcessors = NumberOfProcessors; >> + DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors)); >> + >> + Status = gBS->InstallMultipleProtocolInterfaces ( >> + &mMpServiceHandle, >> + &gEfiMpServiceProtocolGuid, >> + &mMpServicesTemplate, >> + NULL >> + ); >> + ASSERT_EFI_ERROR (Status); >> +} >> diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c >> new file mode 100644 >> index 0000000000..96def89936 >> --- /dev/null >> +++ b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c >> @@ -0,0 +1,159 @@ >> +/** @file Exception.c >> + >> + CPU DXE Module initialization exception instance. >> + >> + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#include "CpuDxe.h" >> +#include >> +#include >> +#include >> + >> +VOID >> +ExceptionEntryStart ( >> + VOID >> + ); >> + >> +VOID >> +ExceptionEntryEnd ( >> + VOID >> + ); >> + >> +/** >> + This function registers and enables the handler specified by InterruptHandler for a processor >> + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the >> + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. >> + The installed handler is called once for each processor interrupt or exception. >> + >> + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts >> + are enabled and FALSE if interrupts are disabled. >> + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called >> + when a processor interrupt occurs. If this parameter is NULL, then the handler >> + will be uninstalled. >> + >> + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. >> + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was >> + previously installed. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not >> + previously installed. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. >> + >> +**/ >> +EFI_STATUS >> +RegisterInterruptHandler ( >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler >> + ) >> +{ >> + return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, InterruptHandler); >> +} >> + >> +/** >> + Update the exception start entry code. >> + >> + @retval EFI_SUCCESS Update the exception start entry code down. >> + @retval EFI_OUT_OF_RESOURCES The start entry code size out of bounds. >> + >> +**/ >> +EFI_STATUS >> +EFIAPI >> +UpdateExceptionStartEntry ( >> + VOID >> + ) >> +{ >> + EFI_PHYSICAL_ADDRESS ExceptionStartEntry; >> + UINTN VectorLength; >> + UINTN MaxLength; >> + UINTN MaxSizeOfVector; >> + >> + VectorLength = (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart; >> + >> + // >> + // A vector is up to 512 bytes. >> + // >> + MaxSizeOfVector = 512; >> + MaxLength = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector; >> + >> + if (VectorLength > MaxLength) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + ExceptionStartEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress); >> + >> + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength); >> + CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, VectorLength); >> + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength); >> + InvalidateDataCache (); >> + >> + // >> + // If PcdCpuExceptionVectorBaseAddress is not used during SEC and PEI stages, the exception >> + // base addres is set to PcdCpuExceptionVectorBaseAddress. >> + // >> + if (CsrRead (LOONGARCH_CSR_EBASE) != ExceptionStartEntry) { >> + SetExceptionBaseAddress (ExceptionStartEntry); >> + } >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + Initialize interrupt handling for DXE phase. >> + >> + @param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance. >> + >> + @return VOID. >> + >> +**/ >> +VOID >> +InitializeExceptions ( >> + IN EFI_CPU_ARCH_PROTOCOL *Cpu >> + ) >> +{ >> + EFI_STATUS Status; >> + EFI_VECTOR_HANDOFF_INFO *VectorInfoList; >> + EFI_VECTOR_HANDOFF_INFO *VectorInfo; >> + BOOLEAN IrqEnabled; >> + >> + VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL; >> + Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList); >> + >> + if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) { >> + VectorInfo = VectorInfoList; >> + } >> + >> + // >> + // Disable interrupts >> + // >> + Cpu->GetInterruptState (Cpu, &IrqEnabled); >> + if (IrqEnabled) { >> + Cpu->DisableInterrupt (Cpu); >> + } >> + >> + // >> + // Update the Exception Start Entry code to point into CpuDxe. >> + // >> + Status = UpdateExceptionStartEntry (); >> + if (EFI_ERROR (Status)) { >> + DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of bounds!\n", __func__); >> + ASSERT_EFI_ERROR (Status); >> + } >> + >> + // >> + // Intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core >> + // >> + Status = InitializeCpuExceptionHandlers (VectorInfo); >> + ASSERT_EFI_ERROR (Status); >> + >> + // >> + // Enable interrupts >> + // >> + DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled = %x\n", IrqEnabled); >> + if (!IrqEnabled) { >> + Status = Cpu->EnableInterrupt (Cpu); >> + } >> + >> + ASSERT_EFI_ERROR (Status); >> +} > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114863): https://edk2.groups.io/g/devel/message/114863 Mute This Topic: https://groups.io/mt/104070187/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-