From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id D1FBF7803CF for ; Wed, 31 Jan 2024 05:33:56 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=tPvgwGIuoG3pt3eeduFrXqPsUkQ0CFqJwIBQy0qQ0zA=; c=relaxed/simple; d=groups.io; h=Message-ID:Date:MIME-Version:User-Agent:Subject:From:To:Cc:Reply-To:References:In-Reply-To:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type; s=20140610; t=1706679235; v=1; b=NcRiQXKWA3GW5fkNIJz0uRzQlLw9UOuDqie/pk1BSNGVRGwtxTVu0knstl4GDCCT0ky1NL21 8+wztHPl3uy38gmYbkVfdPhZVMpNFsWx0JcWuPuTvyhWY/tdsQ8z9LX4xj+zlJ75/URUICln8eE QVf89mEVVoN401lahZH20aso= X-Received: by 127.0.0.2 with SMTP id pIt1YY7687511xTLBxQTFzQu; Tue, 30 Jan 2024 21:33:55 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.8242.1706679232844445490 for ; Tue, 30 Jan 2024 21:33:53 -0800 X-Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8DxaOi+27llc8kIAA--.6963S3; Wed, 31 Jan 2024 13:33:50 +0800 (CST) X-Received: from [10.40.24.149] (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8AxzxOj27llgpgpAA--.40401S4; Wed, 31 Jan 2024 13:33:49 +0800 (CST) Message-ID: <88147892-342c-468f-8af7-08ee6148d3dc@loongson.cn> Date: Wed, 31 Jan 2024 13:33:49 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [edk2-devel] [PATCH v8 16/37] UefiCpuPkg: Add CpuDxe driver for LoongArch64 From: "Chao Li" To: devel@edk2.groups.io, Ray Ni , Laszlo Ersek Cc: Eric Dong , Rahul Kumar , Gerd Hoffmann , Baoqi Zhang , Dongyan Qian Reply-To: devel@edk2.groups.io,lichao@loongson.cn References: <20240126062715.3099433-1-lichao@loongson.cn> <17ADD1DCBDD4B7FE.11113@groups.io> <17AF511F29808828.16460@groups.io> In-Reply-To: <17AF511F29808828.16460@groups.io> X-CM-TRANSID: AQAAf8AxzxOj27llgpgpAA--.40401S4 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQANCGW4s2EJfwAJs0 X-Coremail-Antispam: 1Uk129KBj9fXoWDJFy3Gr4Uur43tF4xKr13WrX_yoW7CF4fGo WSya98tw48Kr4S9a93Ar1kG3y3WFn5Zr4fXr4Fqas5KF1vqF1rKrW293W5J3s3JrW8WFZ8 GryxXas5JFZIyFyrl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn8Aqx4xG62kEwI0EY4vaYxAvb48xYxn0WfASr-VFAUDa7-sFnT9fnUUI cSsGvfJTRUUUbxkYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20x vaj40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2xF0cIa020Ex4CE44I27w Aqx4xG62kEwI0EY4vaYxAvb48xMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E87Iv67AK xVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IY64vIr41l7480Y4vEI4kI2Ix0rV Aqx4xJMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAF wI0_JrI_JrWlx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc4 0Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r4j6ryUMIIF0xvE2Ix0cI8IcVCY1x0267AK xVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr 1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU8xR67UU UUU== Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: HO8A7UI7IqJfB0E9h8pADf4Fx7686176AA= Content-Type: multipart/alternative; boundary="------------SDdemIxU9y6oq6guqSJarTYQ" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=NcRiQXKW; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io --------------SDdemIxU9y6oq6guqSJarTYQ Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Hi Ray and Laszlo, I would very much like to be merged into stable202302, the soft feature=20 deadline is 2024-02-05, so could you please hlep to review this patch as=20 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=3D4584 >> >> 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.<= BR> >> # Copyright (c) 2017, AMD Incorporated. All rights reserved.
>> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rig= hts reserved.
>> # >> # SPDX-License-Identifier: BSD-2-Clause-Patent >> # >> @@ -22,17 +23,16 @@ >> MdeModulePkg/MdeModulePkg.dec >> UefiCpuPkg/UefiCpuPkg.dec >> =20 >> -[LibraryClasses] >> +[LibraryClasses.common] >> BaseLib >> BaseMemoryLib >> CpuLib >> + CacheMaintenanceLib >> DebugLib >> DxeServicesTableLib >> MemoryAllocationLib >> - MtrrLib >> UefiBootServicesTableLib >> UefiDriverEntryPoint >> - LocalApicLib >> UefiLib >> CpuExceptionHandlerLib >> HobLib >> @@ -41,7 +41,14 @@ >> TimerLib >> PeCoffGetEntryPointLib >> =20 >> -[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 >> =20 >> +[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 righ= ts reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#include "CpuDxe.h" >> +#include "CpuMp.h" >> +#include >> +#include >> +#include >> +#include >> + >> +UINT64 mTimerPeriod =3D 0; >> + >> +/** >> + IPI Interrupt Handler. >> + >> + @param InterruptType The type of interrupt that occurred >> + @param SystemContext A pointer to the system context when the inte= rrupt occurred >> +**/ >> +VOID >> +EFIAPI >> +IpiInterruptHandler ( >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_SYSTEM_CONTEXT SystemContext >> + ); >> + >> +// >> +// Globals used to initialize the protocol >> +// >> +EFI_HANDLE mCpuHandle =3D NULL; >> +EFI_CPU_ARCH_PROTOCOL gCpu =3D { >> + CpuFlushCpuDataCache, >> + CpuEnableInterrupt, >> + CpuDisableInterrupt, >> + CpuGetInterruptState, >> + CpuInit, >> + CpuRegisterInterruptHandler, >> + CpuGetTimerValue, >> + CpuSetMemoryAttributes, >> + 0, // NumberOfTimers >> + 4, // DmaBufferAlignment >> +}; >> + >> +/** >> + This function flushes the range of addresses from Start to Start+Leng= th >> + from the processor's data cache. If Start is not aligned to a cache l= ine >> + boundary, then the bytes before Start to the preceding cache line bou= ndary >> + are also flushed. If Start+Length is not aligned to a cache line boun= dary, >> + then the bytes past Start+Length to the end of the next cache line bo= undary >> + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate= must be >> + supported. If the data cache is fully coherent with all DMA operation= s, 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 proces= sor's data cache. This >> + function may flush more bytes than Length sp= ecifies depending upon >> + the granularity of the flush operation that = the processor supports. >> + @param FlushType Specifies the type of flush operation to per= form. >> + >> + @retval EFI_SUCCESS The address range from Start to Start+L= ength was flushed from >> + the processor's data cache. >> + @retval EFI_INVALID_PARAMETER The processor does not support the cach= e 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)L= ength); >> + 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 processo= r. >> + @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 ret= urns 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 interru= pt state. Set to TRUE if >> + interrupts are enabled and FALSE if interrup= ts 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 =3D=3D NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + *State =3D GetInterruptState (); >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + This function generates an INIT on the processor. If this function su= cceeds, then the >> + processor will be reset, and control will not be returned to the call= er. If InitType is >> + not supported by this processor, or the processor cannot programmatic= ally generate an >> + INIT without help from external hardware, then EFI_UNSUPPORTED is ret= urned. If an error >> + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is retur= ned. >> + >> + @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 call= ed >> + 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 ha= ndler >> + for InterruptType was previously insta= lled. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handle= r for >> + InterruptType was not previously insta= lled. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptTy= pe >> + 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 fre= quency. >> + >> + @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 pa= sses >> + in femtoseconds (10-15) for each increm= ent >> + 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 GetTimerVal= ue() >> + can be calculated with the formula >> + (TimerValue2 - TimerValue1) * TimerPeri= od. >> + This parameter is optional and may be N= ULL. >> + >> + @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 th= e 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 =3D=3D NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + if (TimerIndex !=3D 0) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + *TimerValue =3D AsmReadStableCounter (); >> + >> + if (TimerPeriod !=3D NULL) { >> + if (mTimerPeriod =3D=3D 0) { >> + // >> + // Read time stamp counter before and after delay of 100 microsec= onds >> + // >> + BeginValue =3D AsmReadStableCounter (); >> + MicroSecondDelay (100); >> + EndValue =3D AsmReadStableCounter (); >> + // >> + // Calculate the actual frequency >> + // >> + mTimerPeriod =3D DivU64x64Remainder ( >> + MultU64x32 ( >> + 1000 * 1000 * 1000, >> + 100 >> + ), >> + EndValue - BeginValue, >> + NULL >> + ); >> + } >> + >> + *TimerPeriod =3D 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 A= ttributes. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param BaseAddress The physical address that is the start addre= ss 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 me= mory 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 modifi= ed. >> + @retval EFI_INVALID_PARAMETER Length is zero. >> + @retval EFI_OUT_OF_RESOURCES There are not enough system resources t= o modify the attributes of >> + the memory resource range. >> + @retval EFI_UNSUPPORTED The processor does not support one or m= ore bytes of the memory >> + resource range specified by BaseAddress= and Length. >> + The bit mask of attributes is not suppo= rt for the memory resource >> + range specified by BaseAddress and Leng= th. >> + >> +**/ >> +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 =3D Length; >> + Status =3D EFI_SUCCESS; >> + >> + if ((BaseAddress & (EFI_PAGE_SIZE - 1)) !=3D 0) { >> + // >> + // Minimum granularity is SIZE_4KB. >> + // >> + DEBUG (( >> + DEBUG_INFO, >> + "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SI= ZE_4KB\n", >> + BaseAddress, >> + Length, >> + EfiAttributes >> + )); >> + >> + Status =3D EFI_UNSUPPORTED; >> + >> + return Status; >> + } >> + >> + // >> + // Convert the 'Attribute' into LoongArch Attribute >> + // >> + LoongArchAttributes =3D EfiAttributeConverse (EfiAttributes); >> + >> + // >> + // Get the region starting from 'BaseAddress' and its 'Attribute' >> + // >> + RegionBaseAddress =3D BaseAddress; >> + Status =3D GetMemoryRegionAttributes ( >> + RegionBaseAddress, >> + &RegionLength, >> + &RegionLoongArchAttributes >> + ); >> + >> + // >> + // Data & Instruction Caches are flushed when we set new memory attri= butes. >> + // So, we only set the attributes if the new region is different. >> + // >> + if ((Status =3D=3D EFI_NOT_FOUND) || (RegionLoongArchAttributes !=3D = LoongArchAttributes) || >> + ((BaseAddress + Length) > (RegionBaseAddress + RegionLength))) >> + { >> + Status =3D SetMemoryRegionAttributes (BaseAddress, Length, EfiAttri= butes, 0x0); >> + } >> + >> + ASSERT_EFI_ERROR (Status); >> + >> + return Status; >> +} >> + >> +/** >> + Callback function for idle events. >> + >> + @param Event Event whose notification function is be= ing invoked. >> + @param Context The pointer to the notification functio= n'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 =3D gBS->InstallMultipleProtocolInterfaces ( >> + &mCpuHandle, >> + &gEfiCpuArchProtocolGuid, >> + &gCpu, >> + NULL >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + Status =3D gCpu.RegisterInterruptHandler ( >> + &gCpu, >> + EXCEPT_LOONGARCH_INT_IPI, >> + IpiInterruptHandler >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + // >> + // Setup a callback for idle events >> + // >> + Status =3D 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 righ= ts 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+Leng= th >> + from the processor's data cache. If Start is not aligned to a cache l= ine >> + boundary, then the bytes before Start to the preceding cache line bou= ndary >> + are also flushed. If Start+Length is not aligned to a cache line boun= dary, >> + then the bytes past Start+Length to the end of the next cache line bo= undary >> + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate= must be >> + supported. If the data cache is fully coherent with all DMA operation= s, 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 proces= sor's data cache. This >> + function may flush more bytes than Length sp= ecifies depending upon >> + the granularity of the flush operation that = the processor supports. >> + @param FlushType Specifies the type of flush operation to per= form. >> + >> + @retval EFI_SUCCESS The address range from Start to Start+L= ength was flushed from >> + the processor's data cache. >> + @retval EFI_UNSUPPORTEDT The processor does not support the cach= e flush type specified >> + by FlushType. >> + @retval EFI_DEVICE_ERROR The address range from Start to Start+L= ength 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 processo= r. >> + @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 ret= urns 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 interru= pt state. Set to TRUE if >> + interrupts are enabled and FALSE if interrup= ts 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 su= cceeds, then the >> + processor will be reset, and control will not be returned to the call= er. If InitType is >> + not supported by this processor, or the processor cannot programmatic= ally generate an >> + INIT without help from external hardware, then EFI_UNSUPPORTED is ret= urned. If an error >> + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is retur= ned. >> + >> + @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 call= ed >> + 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 ha= ndler >> + for InterruptType was previously insta= lled. >> + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handle= r for >> + InterruptType was not previously insta= lled. >> + @retval EFI_UNSUPPORTED The interrupt specified by InterruptTy= pe >> + 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 fre= quency. >> + >> + @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 pa= sses >> + in femtoseconds (10-15) for each increm= ent >> + 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 GetTimerVal= ue() >> + can be calculated with the formula >> + (TimerValue2 - TimerValue1) * TimerPeri= od. >> + This parameter is optional and may be N= ULL. >> + >> + @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 th= e 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 Interrup= tHandler for a processor >> + interrupt or exception type specified by InterruptType. If InterruptH= andler is NULL, then the >> + handler for the processor interrupt or exception type specified by In= terruptType is uninstalled. >> + The installed handler is called once for each processor interrupt or = exception. >> + >> + @param InterruptType A pointer to the processor's current interru= pt state. Set to TRUE if interrupts >> + are enabled and FALSE if interrupts are disa= bled. >> + @param InterruptHandler A pointer to a function of type EFI_CPU_INTE= RRUPT_HANDLER that is called >> + when a processor interrupt occurs. If this p= arameter 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 han= dler 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 InterruptTyp= e 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 A= ttributes. >> + >> + @param This The EFI_CPU_ARCH_PROTOCOL instance. >> + @param BaseAddress The physical address that is the start addre= ss 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 me= mory 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 modifi= ed. >> + @retval EFI_INVALID_PARAMETER Length is zero. >> + @retval EFI_OUT_OF_RESOURCES There are not enough system resources t= o modify the attributes of >> + the memory resource range. >> + @retval EFI_UNSUPPORTED The processor does not support one or m= ore bytes of the memory >> + resource range specified by BaseAddress= and Length. >> + The bit mask of attributes is not suppo= rt for the memory resource >> + range specified by BaseAddress and Leng= th. >> + >> +**/ >> +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/L= oongArch64/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 righ= ts reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#include "CpuDxe.h" >> +#include "CpuMp.h" >> + >> +EFI_HANDLE mMpServiceHandle =3D NULL; >> +UINTN mNumberOfProcessors =3D 1; >> + >> +EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate =3D { >> + GetNumberOfProcessors, >> + GetProcessorInfo, >> + StartupAllAPs, >> + StartupThisAP, >> + SwitchBSP, >> + EnableDisableAP, >> + WhoAmI >> +}; >> + >> +/** >> + This service retrieves the number of logical processor in the platfor= m >> + and the number of those logical processors that are enabled on this b= oot. >> + 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 ins= tant >> + this call is made. >> + >> + Because MP Service Protocol provides services to enable and disable p= rocessors >> + 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 return= ed. >> + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then >> + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of pro= cessors >> + is returned in NumberOfProcessors, the number of currently enabled pr= ocessor >> + is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned= . >> + >> + @param[in] This A pointer to the EFI_MP_SERVI= CES_PROTOCOL >> + instance. >> + @param[out] NumberOfProcessors Pointer to the total number o= f logical >> + processors in the system, inc= luding the BSP >> + and disabled APs. >> + @param[out] NumberOfEnabledProcessors Pointer to the number of enab= led logical >> + processors that exist in syst= em, 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 =3D=3D NULL) || (NumberOfEnabledProcessors = =3D=3D NULL)) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + return MpInitLibGetNumberOfProcessors ( >> + NumberOfProcessors, >> + NumberOfEnabledProcessors >> + ); >> +} >> + >> +/** >> + Gets detailed MP-related information on the requested processor at th= e >> + instant this call is made. This service may only be called from the B= SP. >> + >> + This service retrieves detailed MP-related information about any proc= essor >> + 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 no= t provided >> + by this service. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PR= OTOCOL >> + instance. >> + @param[in] ProcessorNumber The handle number of processor. >> + @param[out] ProcessorInfoBuffer A pointer to the buffer where infor= mation for >> + the requested processor is deposite= d. >> + >> + @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 specifi= ed 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, ProcessorInfoBuffe= r, 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 us= e 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 retur= ned >> + immediately and Procedure is not started on any AP. >> + >> + If SingleThread is TRUE, all the enabled APs execute the function spe= cified by >> + Procedure one by one, in ascending order of processor handle number. = Otherwise, >> + all the enabled APs execute the function specified by Procedure simul= taneously. >> + >> + If WaitEvent is NULL, execution is in blocking mode. The BSP waits un= til 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_R= EADY_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 e= nabled APs >> + are always available for further calls to EFI_MP_SERVICES_PROTOCOL.St= artupAllAPs() >> + and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not= NULL, its >> + content points to the list of processor handle numbers in which Proce= dure 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 othe= rwise >> + 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 followin= g >> + 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 paramet= er WaitEvent >> + is not NULL, then StartupAllAPs() executes in non-blocking mode.= It requests >> + the function specified by Procedure to be started on all the ena= bled 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 expir= es, the MP >> + Service signals WaitEvent by calling the EFI SignalEvent() funct= ion. If >> + FailedCpuList is not NULL, its content is available when WaitEve= nt is >> + signaled. If all APs returned from Procedure prior to the timeou= t, then >> + FailedCpuList is set to NULL. If not all APs return from Procedu= re before >> + the timeout, then FailedCpuList is filled in with the list of th= e failed >> + APs. The buffer is allocated by MP Service Protocol using Alloca= tePool(). >> + It is the caller's responsibility to free the buffer with FreePo= ol() service. >> + -# This invocation of SignalEvent() function informs the caller tha= t invoked >> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs= completed >> + the specified task or a timeout occurred. The contents of Failed= CpuList >> + can be examined to determine which APs did not complete the spec= ified 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 r= un on >> + enabled APs of the system. See ty= pe >> + EFI_AP_PROCEDURE. >> + @param[in] SingleThread If TRUE, then all the enabled APs= execute >> + the function specified by Procedu= re one by >> + one, in ascending order of proces= sor handle >> + number. If FALSE, then all the e= nabled APs >> + execute the function specified by= Procedure >> + simultaneously. >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until al= l APs finish >> + or TimeoutInMicroseconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on all th= e enabled >> + APs, and go on executing immediat= ely. If >> + all return from Procedure, or Tim= eoutInMicroseconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + APs to return from Procedure, eit= her for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + all APs return from Procedure, th= en Procedure >> + on the failed APs is terminated. = All enabled >> + APs are available for next functi= on assigned >> + by EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs() >> + or EFI_MP_SERVICES_PROTOCOL.Start= upThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re for >> + all APs. >> + @param[out] FailedCpuList If NULL, this parameter is ignore= d. Otherwise, >> + if all APs finish successfully, t= hen its >> + content is set to NULL. If not al= l APs >> + finish before timeout expires, th= en its >> + content is set to address of the = buffer >> + holding handle numbers of the fai= led APs. >> + The buffer is allocated by MP Ser= vice Protocol, >> + and it's the caller's responsibil= ity to >> + free the buffer with FreePool() s= ervice. >> + In blocking mode, it is ready for= consumption >> + when the call returns. In non-blo= cking mode, >> + it is ready when WaitEvent is sig= naled. The >> + list of failed CPU is terminated = by >> + END_OF_CPU_LIST. >> + >> + @retval EFI_SUCCESS In blocking mode, all APs have finish= ed before >> + the timeout expired. >> + @retval EFI_SUCCESS In non-blocking mode, function has be= en dispatched >> + to all enabled APs. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT 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-p= rovided >> + function. The caller can request the BSP to either wait for the compl= etion >> + of the AP or just proceed with the next task by using the EFI event m= echanism. >> + 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 spec= ified by >> + Procedure passing in the argument specified by ProcedureArgument. If= WaitEvent >> + is NULL, execution is in blocking mode. The BSP waits until the AP fi= nishes or >> + TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocki= ng mode. >> + BSP proceeds to the next task without waiting for the AP. If a non-bl= ocking mode >> + is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is si= gnaled, >> + 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.StartupAll= APs() 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 r= un 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 log= ical >> + processors minus 1. The total num= ber of >> + logical processors can be retriev= ed by >> + EFI_MP_SERVICES_PROTOCOL.GetNumbe= rOfProcessors(). >> + @param[in] WaitEvent The event created by the caller w= ith CreateEvent() >> + service. If it is NULL, then exe= cute in >> + blocking mode. BSP waits until th= is AP finish >> + or TimeoutInMicroSeconds expires.= If it's >> + not NULL, then execute in non-blo= cking mode. >> + BSP requests the function specifi= ed by >> + Procedure to be started on this A= P, >> + and go on executing immediately. = If this AP >> + return from Procedure or TimeoutI= nMicroSeconds >> + expires, this event is signaled. = The BSP >> + can use the CheckEvent() or WaitF= orEvent() >> + services to check the state of ev= ent. Type >> + EFI_EVENT is defined in CreateEve= nt() in >> + the Unified Extensible Firmware I= nterface >> + Specification. >> + @param[in] TimeoutInMicroseconds Indicates the time limit in micro= seconds for >> + this AP to finish this Procedure,= either for >> + blocking or non-blocking mode. Ze= ro means >> + infinity. If the timeout expires= before >> + this AP returns from Procedure, t= hen Procedure >> + on the AP is terminated. The >> + AP is available for next function= assigned >> + by EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs() >> + or EFI_MP_SERVICES_PROTOCOL.Start= upThisAP(). >> + If the timeout expires in blockin= g mode, >> + BSP returns EFI_TIMEOUT. If the = timeout >> + expires in non-blocking mode, Wai= tEvent >> + is signaled with SignalEvent(). >> + @param[in] ProcedureArgument The parameter passed into Procedu= re on the >> + specified AP. >> + @param[out] Finished If NULL, this parameter is ignore= d. In >> + blocking mode, this parameter is = ignored. >> + In non-blocking mode, if AP retur= ns from >> + Procedure before the timeout expi= res, 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 finish= ed before >> + the timeout expires. >> + @retval EFI_SUCCESS In non-blocking mode, the function ha= s been >> + dispatched to specified AP. >> + @retval EFI_UNSUPPORTED A non-blocking mode request was made = after the >> + UEFI event EFI_EVENT_GROUP_READY_TO_B= OOT 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 specifi= ed 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 b= e 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 o= ver the >> + execution of the old BSP and continue seamlessly from where the old o= ne 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_PROTOCO= L instance. >> + @param[in] ProcessorNumber The handle number of AP that is to becom= e the new >> + BSP. The range is from 0 to the total nu= mber of >> + logical processors minus 1. The total nu= mber of >> + logical processors can be retrieved by >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProc= essors(). >> + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed= as an >> + enabled AP. Otherwise, it will be disabl= ed. >> + >> + @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 specifi= ed 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 poin= t onward. >> + The caller can optionally specify the health status of the AP by Heal= th. If >> + an AP is being disabled, then the state of the disabled AP is impleme= ntation >> + dependent. If an AP is enabled, then the implementation must guarante= e 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 th= e return >> + from this service, then EFI_UNSUPPORTED must be returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCO= L 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 nu= mber of >> + logical processors can be retrieved by >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProc= essors(). >> + @param[in] EnableAP Specifies the new state for the processo= r for >> + enabled, FALSE for disabled. >> + @param[in] HealthFlag If not NULL, a pointer to a value that s= pecifies >> + the new health status of the AP. This fl= ag >> + corresponds to StatusFlag defined in >> + EFI_MP_SERVICES_PROTOCOL.GetProcessorInf= o(). Only >> + the PROCESSOR_HEALTH_STATUS_BIT is used.= All other >> + bits are ignored. If it is NULL, this p= arameter >> + is ignored. >> + >> + @retval EFI_SUCCESS The specified AP was enabled or disab= led 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 su= pported. >> + @retval EFI_DEVICE_ERROR The calling processor is an AP. >> + @retval EFI_NOT_FOUND Processor with the handle specified b= y 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, HealthFla= g); >> +} >> + >> +/** >> + This return the handle number for the calling processor. This servic= e may be >> + called from the BSP and APs. >> + >> + This service returns the processor handle number for the calling proc= essor. >> + The returned value is in the range from 0 to the total number of logi= cal >> + processors minus 1. The total number of logical processors can be ret= rieved >> + with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service m= ay be >> + called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INV= ALID_PARAMETER >> + is returned. Otherwise, the current processors handle number is retur= ned in >> + ProcessorNumber, and EFI_SUCCESS is returned. >> + >> + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCO= L 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 nu= mber of >> + logical processors can be retrieved by >> + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProc= essors(). >> + >> + @retval EFI_SUCCESS The current processor handle number w= as 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 =3D MpInitLibInitialize (); >> + ASSERT_EFI_ERROR (Status); >> + >> + MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabled= Processors); >> + mNumberOfProcessors =3D NumberOfProcessors; >> + DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors)); >> + >> + Status =3D gBS->InstallMultipleProtocolInterfaces ( >> + &mMpServiceHandle, >> + &gEfiMpServiceProtocolGuid, >> + &mMpServicesTemplate, >> + NULL >> + ); >> + ASSERT_EFI_ERROR (Status); >> +} >> diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuD= xe/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 righ= ts 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 Interrup= tHandler for a processor >> + interrupt or exception type specified by InterruptType. If InterruptH= andler is NULL, then the >> + handler for the processor interrupt or exception type specified by In= terruptType is uninstalled. >> + The installed handler is called once for each processor interrupt or = exception. >> + >> + @param InterruptType A pointer to the processor's current interru= pt state. Set to TRUE if interrupts >> + are enabled and FALSE if interrupts are disa= bled. >> + @param InterruptHandler A pointer to a function of type EFI_CPU_INTE= RRUPT_HANDLER that is called >> + when a processor interrupt occurs. If this p= arameter 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 han= dler 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 InterruptTyp= e is not supported. >> + >> +**/ >> +EFI_STATUS >> +RegisterInterruptHandler ( >> + IN EFI_EXCEPTION_TYPE InterruptType, >> + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler >> + ) >> +{ >> + return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, Interr= uptHandler); >> +} >> + >> +/** >> + Update the exception start entry code. >> + >> + @retval EFI_SUCCESS Update the exception start entry code d= own. >> + @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 =3D (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStar= t; >> + >> + // >> + // A vector is up to 512 bytes. >> + // >> + MaxSizeOfVector =3D 512; >> + MaxLength =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUP= T) * MaxSizeOfVector; >> + >> + if (VectorLength > MaxLength) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + ExceptionStartEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress); >> + >> + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorL= ength); >> + CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, Ve= ctorLength); >> + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorL= ength); >> + InvalidateDataCache (); >> + >> + // >> + // If PcdCpuExceptionVectorBaseAddress is not used during SEC and PEI= stages, the exception >> + // base addres is set to PcdCpuExceptionVectorBaseAddress. >> + // >> + if (CsrRead (LOONGARCH_CSR_EBASE) !=3D 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 =3D (EFI_VECTOR_HANDOFF_INFO *)NULL; >> + Status =3D EfiGetSystemConfigurationTable (&gEfiVectorHandoffTabl= eGuid, (VOID **)&VectorInfoList); >> + >> + if ((Status =3D=3D EFI_SUCCESS) && (VectorInfoList !=3D NULL)) { >> + VectorInfo =3D VectorInfoList; >> + } >> + >> + // >> + // Disable interrupts >> + // >> + Cpu->GetInterruptState (Cpu, &IrqEnabled); >> + if (IrqEnabled) { >> + Cpu->DisableInterrupt (Cpu); >> + } >> + >> + // >> + // Update the Exception Start Entry code to point into CpuDxe. >> + // >> + Status =3D UpdateExceptionStartEntry (); >> + if (EFI_ERROR (Status)) { >> + DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of b= ounds!\n", __func__); >> + ASSERT_EFI_ERROR (Status); >> + } >> + >> + // >> + // Intialize the CpuExceptionHandlerLib so we take over the exception= vector table from the DXE Core >> + // >> + Status =3D InitializeCpuExceptionHandlers (VectorInfo); >> + ASSERT_EFI_ERROR (Status); >> + >> + // >> + // Enable interrupts >> + // >> + DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled =3D %x\n", I= rqEnabled); >> + if (!IrqEnabled) { >> + Status =3D Cpu->EnableInterrupt (Cpu); >> + } >> + >> + ASSERT_EFI_ERROR (Status); >> +} >=20 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#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] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --------------SDdemIxU9y6oq6guqSJarTYQ Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

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.cg=
i?id=3D4584

Cc: Eric Dong <er=
ic.dong@intel.com>
Cc: Ray Ni <ray.n=
i@intel.com>
Cc: Rahul Kumar <=
;rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <krax=
el@redhat.com>
Signed-off-by: Chao Li <lic=
hao@loongson.cn>
Co-authored-by: Baoqi Zhang <=
;zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian &l=
t;qiandongyan@loongson.cn>
---
 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.<B=
R>
 #  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights=
 reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -22,17 +23,16 @@
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
=20
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
   BaseMemoryLib
   CpuLib
+  CacheMaintenanceLib
   DebugLib
   DxeServicesTableLib
   MemoryAllocationLib
-  MtrrLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
-  LocalApicLib
   UefiLib
   CpuExceptionHandlerLib
   HobLib
@@ -41,7 +41,14 @@
   TimerLib
   PeCoffGetEntryPointLib
=20
-[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
=20
+[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/Loo=
ngArch64/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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+#include <Guid/IdleLoopEvent.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/TimerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+UINT64  mTimerPeriod =3D 0;
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interru=
pt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE             mCpuHandle =3D NULL;
+EFI_CPU_ARCH_PROTOCOL  gCpu       =3D {
+  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 bounda=
ry
+  are also flushed. If Start+Length is not aligned to a cache line boundar=
y,
+  then the bytes past Start+Length to the end of the next cache line bound=
ary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate mu=
st 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 sup=
port
+  flushing a range of the data cache, then the entire data cache can be fl=
ushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from th=
e 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 speci=
fies depending upon
+                           the granularity of the flush operation that the=
 processor supports.
+  @param  FlushType        Specifies the type of flush operation to perfor=
m.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Leng=
th was flushed from
+                                the processor's data cache.
+  @retval EFI_INVALID_PARAMETER The processor does not support the cache f=
lush 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)Leng=
th);
+      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 pro=
cessor.
+
+**/
+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 pr=
ocessor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  DisableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the processor's current interrupt state a return=
s it in
+  State. If interrupts are currently enabled, then TRUE is returned. If in=
terrupts
+  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 wa=
s 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 =3D=3D NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *State =3D GetInterruptState ();
+  return EFI_SUCCESS;
+}
+
+/**
+  This function generates an INIT on the processor. If this function succe=
eds, 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 programmaticall=
y generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is return=
ed. 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 ret=
urn 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 nul=
l
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handl=
er
+                                 for InterruptType was previously installe=
d.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler f=
or
+                                 InterruptType was not previously installe=
d.
+  @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 freque=
ncy.
+
+  @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 passe=
s
+                                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 ti=
mers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the t=
imer.
+  @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 =3D=3D NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (TimerIndex !=3D 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerValue =3D AsmReadStableCounter ();
+
+  if (TimerPeriod !=3D NULL) {
+    if (mTimerPeriod =3D=3D 0) {
+      //
+      // Read time stamp counter before and after delay of 100 microsecond=
s
+      //
+      BeginValue =3D AsmReadStableCounter ();
+      MicroSecondDelay (100);
+      EndValue =3D AsmReadStableCounter ();
+      //
+      // Calculate the actual frequency
+      //
+      mTimerPeriod =3D DivU64x64Remainder (
+                       MultU64x32 (
+                         1000 * 1000 * 1000,
+                         100
+                         ),
+                       EndValue - BeginValue,
+                       NULL
+                       );
+    }
+
+    *TimerPeriod =3D 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 Attr=
ibutes.
+
+  @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 memor=
y region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory reg=
ion.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource ran=
ge 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 m=
odify 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 an=
d 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 =3D Length;
+  Status       =3D EFI_SUCCESS;
+
+  if ((BaseAddress & (EFI_PAGE_SIZE - 1)) !=3D 0) {
+    //
+    // Minimum granularity is SIZE_4KB.
+    //
+    DEBUG ((
+      DEBUG_INFO,
+      "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_=
4KB\n",
+      BaseAddress,
+      Length,
+      EfiAttributes
+      ));
+
+    Status =3D EFI_UNSUPPORTED;
+
+    return Status;
+  }
+
+  //
+  // Convert the 'Attribute' into LoongArch Attribute
+  //
+  LoongArchAttributes =3D EfiAttributeConverse (EfiAttributes);
+
+  //
+  // Get the region starting from 'BaseAddress' and its 'Attribute'
+  //
+  RegionBaseAddress =3D BaseAddress;
+  Status            =3D GetMemoryRegionAttributes (
+                        RegionBaseAddress,
+                        &RegionLength,
+                        &RegionLoongArchAttributes
+                        );
+
+  //
+  // Data & Instruction Caches are flushed when we set new memory attr=
ibutes.
+  // So, we only set the attributes if the new region is different.
+  //
+  if ((Status =3D=3D EFI_NOT_FOUND) || (RegionLoongArchAttributes !=3D Loo=
ngArchAttributes) ||
+      ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
+  {
+    Status =3D SetMemoryRegionAttributes (BaseAddress, Length, EfiAttribut=
es, 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 =3D gBS->InstallMultipleProtocolInterfaces (
+                  &mCpuHandle,
+                  &gEfiCpuArchProtocolGuid,
+                  &gCpu,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status =3D gCpu.RegisterInterruptHandler (
+                  &gCpu,
+                  EXCEPT_LOONGARCH_INT_IPI,
+                  IpiInterruptHandler
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Setup a callback for idle events
+  //
+  Status =3D 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/Loo=
ngArch64/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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.h>
+
+//
+// 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 bounda=
ry
+  are also flushed. If Start+Length is not aligned to a cache line boundar=
y,
+  then the bytes past Start+Length to the end of the next cache line bound=
ary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate mu=
st 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 sup=
port
+  flushing a range of the data cache, then the entire data cache can be fl=
ushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from th=
e 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 speci=
fies depending upon
+                           the granularity of the flush operation that the=
 processor supports.
+  @param  FlushType        Specifies the type of flush operation to perfor=
m.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Leng=
th was flushed from
+                                the processor's data cache.
+  @retval EFI_UNSUPPORTEDT      The processor does not support the cache f=
lush type specified
+                                by FlushType.
+  @retval EFI_DEVICE_ERROR      The address range from Start to Start+Leng=
th 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 pro=
cessor.
+
+**/
+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 pr=
ocessor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function retrieves the processor's current interrupt state a return=
s it in
+  State. If interrupts are currently enabled, then TRUE is returned. If in=
terrupts
+  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 wa=
s 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 succe=
eds, 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 programmaticall=
y generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is return=
ed. 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 ret=
urn 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 nul=
l
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handl=
er
+                                 for InterruptType was previously installe=
d.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler f=
or
+                                 InterruptType was not previously installe=
d.
+  @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 freque=
ncy.
+
+  @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 passe=
s
+                                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 ti=
mers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the t=
imer.
+  @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 InterruptHa=
ndler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHand=
ler is NULL, then the
+  handler for the processor interrupt or exception type specified by Inter=
ruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exc=
eption.
+
+  @param  InterruptType    A pointer to the processor's current interrupt =
state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disable=
d.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRU=
PT_HANDLER that is called
+                           when a processor interrupt occurs. If this para=
meter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt wa=
s successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handle=
r for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo=
r InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType i=
s 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 Attr=
ibutes.
+
+  @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 memor=
y region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory reg=
ion.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource ran=
ge 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 m=
odify 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 an=
d 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/Loon=
gArch64/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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+
+EFI_HANDLE  mMpServiceHandle    =3D NULL;
+UINTN       mNumberOfProcessors =3D 1;
+
+EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate =3D {
+  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 instan=
t
+      this call is made.
+
+  Because MP Service Protocol provides services to enable and disable proc=
essors
+  dynamically, the number of enabled logical processors may vary during th=
e
+  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 proces=
sors
+  is returned in NumberOfProcessors, the number of currently enabled proce=
ssor
+  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 l=
ogical
+                                          processors in the system, includ=
ing the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled=
 logical
+                                          processors that exist in system,=
 including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and ena=
bled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
+  @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 =3D=3D NULL) || (NumberOfEnabledProcessors =3D=
=3D 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 process=
or
+  on the platform. Note the following:
+    - The processor information may change during the course of a boot ses=
sion.
+    - 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 p=
rovided
+  by this service.
+
+  @param[in]  This                  A pointer to the EFI_MP_SERVICES_PROTO=
COL
+                                    instance.
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where informat=
ion for
+                                    the requested processor is deposited.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified =
by
+                                  ProcessorNumber does not exist in the pl=
atform.
+
+**/
+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 sup=
ports
+  both blocking and non-blocking requests. The non-blocking requests use E=
FI
+  events so the BSP can detect when the APs have finished. This service ma=
y only
+  be called from the BSP.
+
+  This function is used to dispatch all the enabled APs to the function sp=
ecified
+  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 specif=
ied by
+  Procedure one by one, in ascending order of processor handle number. Oth=
erwise,
+  all the enabled APs execute the function specified by Procedure simultan=
eously.
+
+  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_READ=
Y_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 enab=
led APs
+  are always available for further calls to EFI_MP_SERVICES_PROTOCOL.Start=
upAllAPs()
+  and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NU=
LL, its
+  content points to the list of processor handle numbers in which Procedur=
e was
+  terminated.
+
+  Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PR=
OTOCOL.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 gua=
rantee
+  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 ex=
clusive
+  code. EFI services and protocols may not be called by APs unless otherwi=
se
+  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-blo=
cking
+       mode creates WaitEvent by calling the EFI CreateEvent() service.  T=
he 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 enable=
d 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 f=
ailed
+       APs. The buffer is allocated by MP Service Protocol using AllocateP=
ool().
+       It is the caller's responsibility to free the buffer with FreePool(=
) service.
+    -# This invocation of SignalEvent() function informs the caller that i=
nvoked
+       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs co=
mpleted
+       the specified task or a timeout occurred. The contents of FailedCpu=
List
+       can be examined to determine which APs did not complete the specifi=
ed task
+       prior to the timeout.
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PRO=
TOCOL
+                                      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 ex=
ecute
+                                      the function specified by Procedure =
one by
+                                      one, in ascending order of processor=
 handle
+                                      number.  If FALSE, then all the enab=
led APs
+                                      execute the function specified by Pr=
ocedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with=
 CreateEvent()
+                                      service.  If it is NULL, then execut=
e in
+                                      blocking mode. BSP waits until all A=
Ps finish
+                                      or TimeoutInMicroseconds expires.  I=
f it's
+                                      not NULL, then execute in non-blocki=
ng mode.
+                                      BSP requests the function specified =
by
+                                      Procedure to be started on all the e=
nabled
+                                      APs, and go on executing immediately=
. If
+                                      all return from Procedure, or Timeou=
tInMicroseconds
+                                      expires, this event is signaled. The=
 BSP
+                                      can use the CheckEvent() or WaitForE=
vent()
+                                      services to check the state of event=
.  Type
+                                      EFI_EVENT is defined in CreateEvent(=
) in
+                                      the Unified Extensible Firmware Inte=
rface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microsec=
onds for
+                                      APs to return from Procedure, either=
 for
+                                      blocking or non-blocking mode. Zero =
means
+                                      infinity.  If the timeout expires be=
fore
+                                      all APs return from Procedure, then =
Procedure
+                                      on the failed APs is terminated. All=
 enabled
+                                      APs are available for next function =
assigned
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupA=
llAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupT=
hisAP().
+                                      If the timeout expires in blocking m=
ode,
+                                      BSP returns EFI_TIMEOUT.  If the tim=
eout
+                                      expires in non-blocking mode, WaitEv=
ent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure =
for
+                                      all APs.
+  @param[out] FailedCpuList           If NULL, this parameter is ignored. =
Otherwise,
+                                      if all APs finish successfully, then=
 its
+                                      content is set to NULL. If not all A=
Ps
+                                      finish before timeout expires, then =
its
+                                      content is set to address of the buf=
fer
+                                      holding handle numbers of the failed=
 APs.
+                                      The buffer is allocated by MP Servic=
e Protocol,
+                                      and it's the caller's responsibility=
 to
+                                      free the buffer with FreePool() serv=
ice.
+                                      In blocking mode, it is ready for co=
nsumption
+                                      when the call returns. In non-blocki=
ng mode,
+                                      it is ready when WaitEvent is signal=
ed.  The
+                                      list of failed CPU is terminated by
+                                      END_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished =
before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been =
dispatched
+                                  to all enabled APs.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made aft=
er the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT=
 was
+                                  signaled.
+  @retval EFI_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 be=
fore
+                                  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-prov=
ided
+  function. The caller can request the BSP to either wait for the completi=
on
+  of the AP or just proceed with the next task by using the EFI event mech=
anism.
+  See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blo=
cking
+  execution support.  This service may only be called from the BSP.
+
+  This function is used to dispatch one enabled AP to the function specifi=
ed by
+  Procedure passing in the argument specified by ProcedureArgument.  If Wa=
itEvent
+  is NULL, execution is in blocking mode. The BSP waits until the AP finis=
hes or
+  TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking =
mode.
+  BSP proceeds to the next task without waiting for the AP. If a non-block=
ing mode
+  is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signa=
led,
+  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_PRO=
TOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run =
on the
+                                      designated AP of the system. See typ=
e
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The ran=
ge is
+                                      from 0 to the total number of logica=
l
+                                      processors minus 1. The total number=
 of
+                                      logical processors can be retrieved =
by
+                                      EFI_MP_SERVICES_PROTOCOL.GetNumberOf=
Processors().
+  @param[in]  WaitEvent               The event created by the caller with=
 CreateEvent()
+                                      service.  If it is NULL, then execut=
e in
+                                      blocking mode. BSP waits until this =
AP finish
+                                      or TimeoutInMicroSeconds expires.  I=
f it's
+                                      not NULL, then execute in non-blocki=
ng mode.
+                                      BSP requests the function specified =
by
+                                      Procedure to be started on this AP,
+                                      and go on executing immediately. If =
this AP
+                                      return from Procedure or TimeoutInMi=
croSeconds
+                                      expires, this event is signaled. The=
 BSP
+                                      can use the CheckEvent() or WaitForE=
vent()
+                                      services to check the state of event=
.  Type
+                                      EFI_EVENT is defined in CreateEvent(=
) in
+                                      the Unified Extensible Firmware Inte=
rface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microsec=
onds for
+                                      this AP to finish this Procedure, ei=
ther for
+                                      blocking or non-blocking mode. Zero =
means
+                                      infinity.  If the timeout expires be=
fore
+                                      this AP returns from Procedure, then=
 Procedure
+                                      on the AP is terminated. The
+                                      AP is available for next function as=
signed
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupA=
llAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupT=
hisAP().
+                                      If the timeout expires in blocking m=
ode,
+                                      BSP returns EFI_TIMEOUT.  If the tim=
eout
+                                      expires in non-blocking mode, WaitEv=
ent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure =
on the
+                                      specified AP.
+  @param[out] Finished                If NULL, this parameter is ignored. =
 In
+                                      blocking mode, this parameter is ign=
ored.
+                                      In non-blocking mode, if AP returns =
from
+                                      Procedure before the timeout expires=
, its
+                                      content is set to TRUE. Otherwise, t=
he
+                                      value is set to FALSE. The caller ca=
n
+                                      determine if the AP returned from Pr=
ocedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished =
before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has b=
een
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made aft=
er the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT=
 was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired be=
fore
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_FOUND           The processor with the handle specified =
by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or dis=
abled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+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 onw=
ard.
+  This service changes the BSP for all purposes.   This call can only be p=
erformed
+  by the current BSP.
+
+  This service switches the requested AP to be the BSP from that point onw=
ard.
+  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_GR=
OUP_READY_TO_BOOT
+  is signaled.
+
+  If the BSP cannot be switched prior to the return from this service, the=
n
+  EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL i=
nstance.
+  @param[in] ProcessorNumber   The handle number of AP that is to become t=
he new
+                               BSP. The range is from 0 to the total numbe=
r of
+                               logical processors minus 1. The total numbe=
r of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess=
ors().
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as=
 an
+                               enabled AP. Otherwise, it will be disabled.
+
+  @retval EFI_SUCCESS             BSP successfully switched.
+  @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed pr=
ior to
+                                  this service returning.
+  @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           The processor with the handle specified =
by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BS=
P or
+                                  a disabled AP.
+  @retval EFI_NOT_READY           The specified AP is busy.
+
+**/
+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 onw=
ard.
+  This service may only be called from the BSP.
+
+  This service allows the caller enable or disable an AP from this point o=
nward.
+  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 implementa=
tion
+  dependent. If an AP is enabled, then the implementation must guarantee t=
hat 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 r=
eturn
+  from this service, then EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL i=
nstance.
+  @param[in] ProcessorNumber   The handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total numbe=
r of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess=
ors().
+  @param[in] EnableAP          Specifies the new state for the processor f=
or
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that spec=
ifies
+                               the new health status of the AP. This flag
+                               corresponds to StatusFlag defined in
+                               EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo()=
. Only
+                               the PROCESSOR_HEALTH_STATUS_BIT is used. Al=
l other
+                               bits are ignored.  If it is NULL, this para=
meter
+                               is ignored.
+
+  @retval EFI_SUCCESS             The specified AP was enabled or disabled=
 successfully.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be co=
mpleted
+                                  prior to this service returning.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not suppo=
rted.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           Processor with the handle specified by P=
rocessorNumber
+                                  does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
+
+**/
+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 m=
ay be
+  called from the BSP and APs.
+
+  This service returns the processor handle number for the calling process=
or.
+  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 retrie=
ved
+  with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may =
be
+  called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALI=
D_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 i=
nstance.
+  @param[out] ProcessorNumber  Pointer to the handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total numbe=
r of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess=
ors().
+
+  @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 =3D MpInitLibInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEn=
abledProcessors);
+  mNumberOfProcessors =3D NumberOfProcessors;
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
+
+  Status =3D 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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include <Guid/VectorHandoffTable.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+VOID
+ExceptionEntryStart (
+  VOID
+  );
+
+VOID
+ExceptionEntryEnd (
+  VOID
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHa=
ndler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHand=
ler is NULL, then the
+  handler for the processor interrupt or exception type specified by Inter=
ruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exc=
eption.
+
+  @param  InterruptType    A pointer to the processor's current interrupt =
state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disable=
d.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRU=
PT_HANDLER that is called
+                           when a processor interrupt occurs. If this para=
meter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt wa=
s successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handle=
r for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo=
r InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType i=
s not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, Interrupt=
Handler);
+}
+
+/**
+  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 =3D (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart;
+
+  //
+  // A vector is up to 512 bytes.
+  //
+  MaxSizeOfVector =3D 512;
+  MaxLength       =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) =
* MaxSizeOfVector;
+
+  if (VectorLength > MaxLength) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ExceptionStartEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress);
+
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLeng=
th);
+  CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, Vecto=
rLength);
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLeng=
th);
+  InvalidateDataCache ();
+
+  //
+  // If PcdCpuExceptionVectorBaseAddress is not used during SEC and PEI st=
ages, the exception
+  // base addres is set to PcdCpuExceptionVectorBaseAddress.
+  //
+  if (CsrRead (LOONGARCH_CSR_EBASE) !=3D 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 =3D (EFI_VECTOR_HANDOFF_INFO *)NULL;
+  Status     =3D EfiGetSystemConfigurationTable (&gEfiVectorHandoffTab=
leGuid, (VOID **)&VectorInfoList);
+
+  if ((Status =3D=3D EFI_SUCCESS) && (VectorInfoList !=3D NULL)) {
+    VectorInfo =3D VectorInfoList;
+  }
+
+  //
+  // Disable interrupts
+  //
+  Cpu->GetInterruptState (Cpu, &IrqEnabled);
+  if (IrqEnabled) {
+    Cpu->DisableInterrupt (Cpu);
+  }
+
+  //
+  // Update the Exception Start Entry code to point into CpuDxe.
+  //
+  Status =3D UpdateExceptionStartEntry ();
+  if (EFI_ERROR (Status)) {
+    DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of boun=
ds!\n", __func__);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Intialize the CpuExceptionHandlerLib so we take over the exception ve=
ctor table from the DXE Core
+  //
+  Status =3D InitializeCpuExceptionHandlers (VectorInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Enable interrupts
+  //
+  DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled =3D %x\n", IrqE=
nabled);
+  if (!IrqEnabled) {
+    Status =3D Cpu->EnableInterrupt (Cpu);
+  }
+
+  ASSERT_EFI_ERROR (Status);
+}
=20
_._,_._,_

Groups.io Links:

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

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

_._,_._,_
--------------SDdemIxU9y6oq6guqSJarTYQ--