Hi Ray, Can you please help to review this patch again? Thanks, Chao 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 (#114852): https://edk2.groups.io/g/devel/message/114852 Mute This Topic: https://groups.io/mt/104068958/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-