From nobody Fri Oct 18 05:21:57 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+114542+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+114542+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1706250580; cv=none; d=zohomail.com; s=zohoarc; b=BYVdBJQcOZ3IzYoSdoTXBMfx7rHQ8vRJT0VYG79bmp1NuXaBNAkt+F/7Xr89h3UHE43/7BAh7avLFlws68jS8RzzLCqu2XB9Bsk8tc1ynFUN6nKbfqx7yObJR03+ea4HKiu+hLpgBFT1VpnWCdrU3DPDAPXVzHldfhE40uQuuxk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706250580; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=vN9SIMSSBLlr9NBNmHqJiq3yxvICsk2NmQkfKiUF4b8=; b=iZfraRLH0Lj/oq+8iqPvAE4yP1KtMb9VfdDCx9sCQoZRnfTKHdvQs/BLo+MJGu265BN6nKObz5UougaGrG2VoTJFwGJKUVxpOjVkiopuT3GzZpy/vzEZf+3aONmpPeZt910+UryrZIwYE3eep6kDFbv8euA2+MFY6/Em6dCZZwE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+114542+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 17062505806851.8994987576908215; Thu, 25 Jan 2024 22:29:40 -0800 (PST) Return-Path: DKIM-Signature: a=rsa-sha256; bh=wIk8QDTbiLAVDSU4iHzI8cT/gtY+9Jd8njTRAZ+Q43U=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1706250580; v=1; b=KlryY30O8J0wWeMFtK6NmBTyOlzpZlqujKycmYZq72EHH8HzgUSIBs/bxmm5DtLepiQk3gpR 0tjCPItz2r7+RDn60eVHA0rO2vHgN0OhqgPgjYfudHSln2WDMgQAJ2T7dgrHVtEpsEiFGR4eZcZ IovgZAlyQm/vDE+H5gs66+Gw= X-Received: by 127.0.0.2 with SMTP id AvipYY1788612xd06HTq6lop; Thu, 25 Jan 2024 22:29:40 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web10.10137.1706250577992269008 for ; Thu, 25 Jan 2024 22:29:39 -0800 X-Received: from loongson.cn (unknown [10.2.9.245]) by gateway (Coremail) with SMTP id _____8Cx2uhOUbNlMh4GAA--.2189S3; Fri, 26 Jan 2024 14:29:34 +0800 (CST) X-Received: from code-server.gen (unknown [10.2.9.245]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Bx7c5NUbNlkXIbAA--.52917S2; Fri, 26 Jan 2024 14:29:33 +0800 (CST) From: "Chao Li" To: devel@edk2.groups.io Cc: Eric Dong , Ray Ni , Rahul Kumar , Gerd Hoffmann , Baoqi Zhang , Dongyan Qian Subject: [edk2-devel] [PATCH v8 16/37] UefiCpuPkg: Add CpuDxe driver for LoongArch64 Date: Fri, 26 Jan 2024 14:29:32 +0800 Message-Id: <20240126062932.3101824-1-lichao@loongson.cn> In-Reply-To: <20240126062715.3099433-1-lichao@loongson.cn> References: <20240126062715.3099433-1-lichao@loongson.cn> MIME-Version: 1.0 X-CM-TRANSID: AQAAf8Bx7c5NUbNlkXIbAA--.52917S2 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQAICGWyG+ALOQBQsP X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== 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 Reply-To: devel@edk2.groups.io,lichao@loongson.cn List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: 5jmuTefMKpkijONk68emoouGx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1706250582367100001 Content-Type: text/plain; charset="utf-8" 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.
# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -22,17 +23,16 @@ MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec =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.
+ + 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 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 null + 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 passes + in femtoseconds (10-15) for each increment + of TimerValue. If TimerValue does not + increment at a predictable rate, then 0 is + returned. The amount of time that has + passed between two calls to GetTimerValue() + can be calculated with the formula + (TimerValue2 - TimerValue1) * TimerPeriod. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS - If the CPU timer count was returned. + @retval EFI_UNSUPPORTED - If the CPU does not have any readable 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 microseconds + // + 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 attribut= es. + // 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef CPU_DXE_H_ +#define CPU_DXE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// For coding convenience, define the maximum valid +// LoongArch exception. +// Since UEFI V2.11, it will be present in DebugSupport.h. +// +#define MAX_LOONGARCH_EXCEPTION 64 + +/* + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line 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 null + 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 passes + in femtoseconds (10-15) for each increment + of TimerValue. If TimerValue does not + increment at a predictable rate, then 0 is + returned. The amount of time that has + passed between two calls to GetTimerValue() + can be calculated with the formula + (TimerValue2 - TimerValue1) * TimerPeriod. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS - If the CPU timer count was returned. + @retval EFI_UNSUPPORTED - If the CPU does not have any readable 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.
+ + 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 instant + 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 the + course of a boot session. + + If this service is called from an AP, then EFI_DEVICE_ERROR is returned. + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of 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 type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The ran= ge is + from 0 to the total number of logical + processors minus 1. The total number= of + logical processors can be retrieved = by + EFI_MP_SERVICES_PROTOCOL.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 can + 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, 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 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, &NumberOfEnabledPro= cessors); + 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.
+ + 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 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 (&gEfiVectorHandoffTableGu= id, (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 2.27.0 -=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 (#114542): https://edk2.groups.io/g/devel/message/114542 Mute This Topic: https://groups.io/mt/103971655/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-