Hi Ray,
Can you please help to review this patch again?
Added LoongArch exception handler into CpuExceptionHandlerLib. Adjust the file order in INF of CpuExceptionHandlerLib with alphabetical order. Adjust files order in CpuExceptionHandlerLib INF in alphabetical order. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584 Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Chao Li <lichao@loongson.cn> Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn> --- .../DxeCpuExceptionHandlerLib.inf | 34 +- .../LoongArch/DxeExceptionLib.c | 198 ++++++++++ .../LoongArch/ExceptionCommon.c | 171 ++++++++ .../LoongArch/ExceptionCommon.h | 131 +++++++ .../LoongArch64/ArchExceptionHandler.c | 268 +++++++++++++ .../LoongArch64/ExceptionHandlerAsm.S | 366 ++++++++++++++++++ .../LoongArch/SecPeiExceptionLib.c | 102 +++++ .../SecPeiCpuExceptionHandlerLib.inf | 29 +- UefiCpuPkg/UefiCpuPkg.dec | 5 + 9 files changed, 1283 insertions(+), 21 deletions(-) create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf index fdbebadab9..f5bacbe2bc 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -18,25 +18,32 @@ # # The following information is for reference only and not required by the build tools. # -# VALID_ARCHITECTURES = IA32 X64 +# VALID_ARCHITECTURES = IA32 X64 LOONGARCH64 # [Sources.Ia32] - Ia32/ExceptionHandlerAsm.nasm - Ia32/ExceptionTssEntryAsm.nasm Ia32/ArchExceptionHandler.c Ia32/ArchInterruptDefs.h + Ia32/ExceptionHandlerAsm.nasm + Ia32/ExceptionTssEntryAsm.nasm [Sources.X64] - X64/ExceptionHandlerAsm.nasm X64/ArchExceptionHandler.c X64/ArchInterruptDefs.h + X64/ExceptionHandlerAsm.nasm -[Sources.common] +[Sources.Ia32, Sources.X64] CpuExceptionCommon.h CpuExceptionCommon.c - PeiDxeSmmCpuException.c DxeException.c + PeiDxeSmmCpuException.c + +[Sources.LoongArch64] + LoongArch/DxeExceptionLib.c + LoongArch/ExceptionCommon.h + LoongArch/ExceptionCommon.c + LoongArch/LoongArch64/ArchExceptionHandler.c + LoongArch/LoongArch64/ExceptionHandlerAsm.S | GCC [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard @@ -51,16 +58,19 @@ MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec -[LibraryClasses] +[LibraryClasses.common] BaseLib - SerialPortLib + CpuLib + DebugLib + MemoryAllocationLib + PeCoffGetEntryPointLib PrintLib + SerialPortLib SynchronizationLib - LocalApicLib - PeCoffGetEntryPointLib - MemoryAllocationLib - DebugLib + +[LibraryClasses.Ia32, LibraryClasses.X64] CcExitLib + LocalApicLib [BuildOptions] XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c new file mode 100644 index 0000000000..2c5d202b33 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c @@ -0,0 +1,198 @@ +/** @file DxeExceptionLib.c + + LoongArch exception library implemenation for DXE modules. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Library/BaseLib.h> +#include <Library/CpuExceptionHandlerLib.h> +#include <Library/CpuLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/DebugLib.h> +#include <Library/SerialPortLib.h> +#include <Protocol/DebugSupport.h> +#include <Register/LoongArch64/Csr.h> + +#include "ExceptionCommon.h" + +EFI_EXCEPTION_CALLBACK ExternalInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1] = { 0 }; +EFI_EXCEPTION_CALLBACK ExceptionHandler[MAX_LOONGARCH_EXCEPTION + 1] = { 0 }; + +/** + Registers a function to be called from the processor interrupt or exception handler. + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + EFI_EXCEPTION_TYPE ExceptionType; + + ExceptionType = InterruptType & CSR_ESTAT_EXC; + + if (ExceptionType != 0) { + // + // Exception + // + if (ExceptionType > EXCEPT_LOONGARCH_FPE) { + return EFI_UNSUPPORTED; + } + + ExceptionType >>= CSR_ESTAT_EXC_SHIFT; + + if ((InterruptHandler == NULL) && (ExceptionHandler[InterruptType] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((InterruptHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + ExceptionHandler[ExceptionType] = InterruptHandler; + } else { + // + // Interrupt + // + if (InterruptType > MAX_LOONGARCH_INTERRUPT) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + ExternalInterruptHandler[InterruptType] = InterruptHandler; + } + + return EFI_SUCCESS; +} + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_EXCEPTION_TYPE InterruptType; + + if (ExceptionType == EXCEPT_LOONGARCH_INT) { + // + // Interrupt + // + InterruptType = GetInterruptType (SystemContext); + if (InterruptType == 0xFF) { + ExceptionType = InterruptType; + } else { + if ((ExternalInterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) { + ExternalInterruptHandler[InterruptType](InterruptType, SystemContext); + return; + } + } + } else if (ExceptionType == EXCEPT_LOONGARCH_FPD) { + EnableFloatingPointUnits (); + InitializeFloatingPointUnits (); + return; + } else { + // + // Exception + // + ExceptionType >>= CSR_ESTAT_EXC_SHIFT; + if ((ExceptionHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) { + ExceptionHandler[ExceptionType](ExceptionType, SystemContext); + return; + } + } + + // + // Only the TLB refill exception use the same entry point as normal exceptions. + // + if (CsrRead (LOONGARCH_CSR_TLBRERA) & 0x1) { + ExceptionType = mExceptionKnownNameNum - 1; // Use only to dump the exception context. + } + + DefaultExceptionHandler (ExceptionType, SystemContext); +} + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL. + @retval EFI_UNSUPPORTED This function is not supported. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +/** + Setup separate stacks for certain exception handlers. + If the input Buffer and BufferSize are both NULL, use global variable if possible. + + @param[in] Buffer Point to buffer used to separate exception stack. + @param[in, out] BufferSize On input, it indicates the byte size of Buffer. + If the size is not enough, the return status will + be EFI_BUFFER_TOO_SMALL, and output BufferSize + will be the size it needs. + + @retval EFI_SUCCESS The stacks are assigned successfully. + @retval EFI_UNSUPPORTED This function is not supported. + @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small. +**/ +EFI_STATUS +EFIAPI +InitializeSeparateExceptionStacks ( + IN VOID *Buffer, + IN OUT UINTN *BufferSize + ) +{ + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c new file mode 100644 index 0000000000..801c8393e8 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c @@ -0,0 +1,171 @@ +/** @file DxeExceptionLib.c + + CPU Exception Handler Library common functions. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Library/BaseLib.h> +#include <Library/PeCoffGetEntryPointLib.h> +#include <Library/PrintLib.h> +#include <Library/SerialPortLib.h> +#include <Register/LoongArch64/Csr.h> +#include "ExceptionCommon.h" + +CONST CHAR8 mExceptionReservedStr[] = "Reserved"; +CONST CHAR8 *mExceptionNameStr[] = { + "#INT - Interrupt(CSR.ECFG.VS=0)", + "#PIL - Page invalid exception for Load option", + "#PIS - Page invalid exception for Store operation", + "#PIF - Page invalid exception for Fetch operation", + "#PME - Page modification exception", + "#PNR - Page non-readable exception", + "#PNX - Page non-executable exception", + "#PPI - Page privilege level illegal exception", + "#ADE - Address error exception", + "#ALE - Address alignment fault exception", + "#BCE - Bound check exception", + "#SYS - System call exception", + "#BRK - Beeakpoint exception", + "#INE - Instruction non-defined exception", + "#IPE - Instruction privilege error exception", + "#FPD - Floating-point instruction disable exception", + "#SXD - 128-bit vector (SIMD instructions) expansion instruction disable exception", + "#ASXD - 256-bit vector (Advanced SIMD instructions) expansion instruction disable exception", + "#FPE - Floating-Point error exception", + "#WPE - WatchPoint Exception for Fetch watchpoint or Memory load/store watchpoint", + "#BTD - Binary Translation expansion instruction Disable exception", + "#BTE - Binary Translation related exceptions", + "#GSPR - Guest Sensitive Privileged Resource exception", + "#HVC - HyperVisor Call exception", + "#GCXC - Guest CSR Software/Hardware Change exception", + "#TBR - TLB refill exception" // !!! NOTICE: Because the TLB refill exception is not instructed in ECODE, so the TLB refill exception must be the last one! +}; + +INTN mExceptionKnownNameNum = (sizeof (mExceptionNameStr) / sizeof (CHAR8 *)); + +/** + Get ASCII format string exception name by exception type. + + @param ExceptionType Exception type. + + @return ASCII format string exception name. + +**/ +CONST CHAR8 * +GetExceptionNameStr ( + IN EFI_EXCEPTION_TYPE ExceptionType + ) +{ + if ((UINTN)ExceptionType < mExceptionKnownNameNum) { + return mExceptionNameStr[ExceptionType]; + } else { + return mExceptionReservedStr; + } +} + +/** + Prints a message to the serial port. + + @param Format Format string for the message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + // + // Send the print string to a Serial Port + // + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); +} + +/** + Find and display image base address and return image base and its entry point. + + @param CurrentEra Current instruction pointer. + +**/ +VOID +DumpModuleImageInfo ( + IN UINTN CurrentEra + ) +{ + EFI_STATUS Status; + UINTN Pe32Data; + VOID *PdbPointer; + VOID *EntryPoint; + + Pe32Data = PeCoffSearchImageBase (CurrentEra); + if (Pe32Data == 0) { + InternalPrintMessage ("!!!! Can't find image information. !!!!\n"); + } else { + // + // Find Image Base entry point + // + Status = PeCoffLoaderGetEntryPoint ((VOID *)Pe32Data, &EntryPoint); + if (EFI_ERROR (Status)) { + EntryPoint = NULL; + } + + InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentEra); + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)Pe32Data); + if (PdbPointer != NULL) { + InternalPrintMessage ("%a", PdbPointer); + } else { + InternalPrintMessage ("(No PDB) "); + } + + InternalPrintMessage ( + " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n", + (VOID *)Pe32Data, + EntryPoint + ); + } +} + +/** + Default exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // Initialize the serial port before dumping. + // + SerialPortInitialize (); + // + // Display ExceptionType, CPU information and Image information + // + DumpImageAndCpuContent (ExceptionType, SystemContext); + + // + // Enter a dead loop. + // + CpuDeadLoop (); +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h new file mode 100644 index 0000000000..e326b73e3f --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h @@ -0,0 +1,131 @@ +/** @file DxeExceptionLib.h + + Common header file for CPU Exception Handler Library. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef EXCEPTION_COMMON_H_ +#define EXCEPTION_COMMON_H_ + +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +// +// 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 + +extern INTN mExceptionKnownNameNum; + +/** + Get ASCII format string exception name by exception type. + + @param[in] ExceptionType Exception type. + + @return ASCII format string exception name. + +**/ +CONST CHAR8 * +GetExceptionNameStr ( + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +/** + Prints a message to the serial port. + + @param[in] Format Format string for the message to print. + @param[in] ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +InternalPrintMessage ( + IN CONST CHAR8 *Format, + ... + ); + +/** + Find and display image base address and return image base and its entry point. + + @param[in] CurrentEip Current instruction pointer. + +**/ +VOID +DumpModuleImageInfo ( + IN UINTN CurrentEip + ); + +/** + IPI Interrupt Handler. + + @param InterruptType The type of interrupt that occurred + @param SystemContext A pointer to the system context when the interrupt occurred +**/ +VOID +EFIAPI +IpiInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Default exception handler. + + @param[in] ExceptionType Exception type. + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Display CPU information. + + @param[in] ExceptionType Exception type. + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +DumpImageAndCpuContent ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Get exception types + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + + @return Exception type. + +**/ +EFI_EXCEPTION_TYPE +EFIAPI +GetExceptionType ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Get Common interrupt types + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + + @return Interrupt type. + +**/ +EFI_EXCEPTION_TYPE +EFIAPI +GetInterruptType ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +#endif diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c new file mode 100644 index 0000000000..c0219deba5 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c @@ -0,0 +1,268 @@ +/** @file ArchExceptionHandler.c + + LoongArch64 CPU Exception Handler. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Library/BaseLib.h> +#include <Register/LoongArch64/Csr.h> +#include "ExceptionCommon.h" + +/** + Get Exception Type + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + + @return LoongArch64 exception type. + +**/ +EFI_EXCEPTION_TYPE +EFIAPI +GetExceptionType ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_EXCEPTION_TYPE ExceptionType; + + ExceptionType = (SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC); + return ExceptionType; +} + +/** + Get Interrupt Type + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + + @return LoongArch64 intrrupt type. + +**/ +EFI_EXCEPTION_TYPE +EFIAPI +GetInterruptType ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_EXCEPTION_TYPE InterruptType; + + for (InterruptType = 0; InterruptType <= EXCEPT_LOONGARCH_INT_IPI; InterruptType++) { + if (SystemContext.SystemContextLoongArch64->ESTAT & (1 << InterruptType)) { + // + // 0 - EXCEPT_LOONGARCH_INT_SIP0 + // 1 - EXCEPT_LOONGARCH_INT_SIP1 + // 2 - EXCEPT_LOONGARCH_INT_IP0 + // 3 - EXCEPT_LOONGARCH_INT_IP1 + // 4 - EXCEPT_LOONGARCH_INT_IP2 + // 5 - EXCEPT_LOONGARCH_INT_IP3 + // 6 - EXCEPT_LOONGARCH_INT_IP4 + // 7 - EXCEPT_LOONGARCH_INT_IP5 + // 8 - EXCEPT_LOONGARCH_INT_IP6 + // 9 - EXCEPT_LOONGARCH_INT_IP7 + // 10 - EXCEPT_LOONGARCH_INT_PMC + // 11 - EXCEPT_LOONGARCH_INT_TIMER + // 12 - EXCEPT_LOONGARCH_INT_IPI + // Greater than EXCEPT_LOONGARCH_INI_IPI is currently invalid. + // + return InterruptType; + } + } + + // + // Invalid IRQ + // + return 0xFF; +} + +/** + Display CPU information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +EFIAPI +DumpCpuContext ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + InternalPrintMessage ( + "\n!!!! LoongArch64 Exception Type - %02x(%a) !!!!\n", + ExceptionType, + GetExceptionNameStr (ExceptionType) + ); + + // + // Dump TLB refill ERA and BADV + // + if (ExceptionType == (mExceptionKnownNameNum - 1)) { + InternalPrintMessage ("TLB refill ERA 0x%llx\n", (CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL))); + InternalPrintMessage ("TLB refill BADV 0x%llx\n", CsrRead (LOONGARCH_CSR_TLBRBADV)); + } + + // + // Dump the general registers + // + InternalPrintMessage ( + "Zero - 0x%016lx, RA - 0x%016lx, TP - 0x%016lx, SP - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R0, + SystemContext.SystemContextLoongArch64->R1, + SystemContext.SystemContextLoongArch64->R2, + SystemContext.SystemContextLoongArch64->R3 + ); + InternalPrintMessage ( + " A0 - 0x%016lx, A1 - 0x%016lx, A2 - 0x%016lx, A3 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R4, + SystemContext.SystemContextLoongArch64->R5, + SystemContext.SystemContextLoongArch64->R6, + SystemContext.SystemContextLoongArch64->R7 + ); + InternalPrintMessage ( + " A4 - 0x%016lx, A5 - 0x%016lx, A6 - 0x%016lx, A7 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R8, + SystemContext.SystemContextLoongArch64->R9, + SystemContext.SystemContextLoongArch64->R10, + SystemContext.SystemContextLoongArch64->R11 + ); + InternalPrintMessage ( + " T0 - 0x%016lx, T1 - 0x%016lx, T2 - 0x%016lx, T3 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R12, + SystemContext.SystemContextLoongArch64->R13, + SystemContext.SystemContextLoongArch64->R14, + SystemContext.SystemContextLoongArch64->R15 + ); + InternalPrintMessage ( + " T4 - 0x%016lx, T5 - 0x%016lx, T6 - 0x%016lx, T7 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R16, + SystemContext.SystemContextLoongArch64->R17, + SystemContext.SystemContextLoongArch64->R18, + SystemContext.SystemContextLoongArch64->R19 + ); + InternalPrintMessage ( + " T8 - 0x%016lx, R21 - 0x%016lx, FP - 0x%016lx, S0 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R20, + SystemContext.SystemContextLoongArch64->R21, + SystemContext.SystemContextLoongArch64->R22, + SystemContext.SystemContextLoongArch64->R23 + ); + InternalPrintMessage ( + " S1 - 0x%016lx, S2 - 0x%016lx, S3 - 0x%016lx, S4 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R24, + SystemContext.SystemContextLoongArch64->R25, + SystemContext.SystemContextLoongArch64->R26, + SystemContext.SystemContextLoongArch64->R27 + ); + InternalPrintMessage ( + " S5 - 0x%016lx, S6 - 0x%016lx, S7 - 0x%016lx, S8 - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->R28, + SystemContext.SystemContextLoongArch64->R29, + SystemContext.SystemContextLoongArch64->R30, + SystemContext.SystemContextLoongArch64->R31 + ); + InternalPrintMessage ("\n"); + + // + // Dump the CSR registers + // + InternalPrintMessage ( + "CRMD - 0x%016lx, PRMD - 0x%016lx, EUEN - 0x%016lx, MISC - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->CRMD, + SystemContext.SystemContextLoongArch64->PRMD, + SystemContext.SystemContextLoongArch64->EUEN, + SystemContext.SystemContextLoongArch64->MISC + ); + InternalPrintMessage ( + "ECFG - 0x%016lx, ESTAT - 0x%016lx, ERA - 0x%016lx, BADV - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->ECFG, + SystemContext.SystemContextLoongArch64->ESTAT, + SystemContext.SystemContextLoongArch64->ERA, + SystemContext.SystemContextLoongArch64->BADV + ); + InternalPrintMessage ( + "BADI - 0x%016lx\n", + SystemContext.SystemContextLoongArch64->BADI + ); +} + +/** + Display CPU information. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +DumpImageAndCpuContent ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + DumpCpuContext (ExceptionType, SystemContext); + + if (ExceptionType == (mExceptionKnownNameNum - 1)) { + // + // Dump TLB refill image info + // + DumpModuleImageInfo ((CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL))); + } else { + DumpModuleImageInfo (SystemContext.SystemContextLoongArch64->ERA); + } +} + +/** + IPI Interrupt Handler. + + @param InterruptType The type of interrupt that occurred + @param SystemContext A pointer to the system context when the interrupt occurred +**/ +VOID +EFIAPI +IpiInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN ResumeVector; + UINTN Parameter; + + // + // Clear interrupt. + // + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS)); + + // + // Get the resume vector and parameter if populated. + // + ResumeVector = IoCsrRead64 (LOONGARCH_IOCSR_MBUF0); + Parameter = IoCsrRead64 (LOONGARCH_IOCSR_MBUF3); + + // + // Clean up current processor mailbox 0 and mailbox 3. + // + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0); + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0); + + // + // If mailbox 0 is non-NULL, it means that the BSP or other cores called the IPI to wake + // up the current core and let it use the resume vector stored in mailbox 0. + // + // If both the resume vector and parameter are non-NULL, it means that the IPI was + // called in the BIOS. + // + // The situation where the resume vector is non-NULL and the parameter is NULL has been + // processed after the exception entry is pushed onto the stack. + // + if ((ResumeVector != 0) && (Parameter != 0)) { + SystemContext.SystemContextLoongArch64->ERA = ResumeVector; + // + // Set $a0 as APIC ID and $a1 as parameter value. + // + SystemContext.SystemContextLoongArch64->R4 = CsrRead (LOONGARCH_CSR_CPUNUM); + SystemContext.SystemContextLoongArch64->R5 = Parameter; + } + + MemoryFence (); +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S new file mode 100644 index 0000000000..7c692e01c1 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S @@ -0,0 +1,366 @@ +#------------------------------------------------------------------------------ +# +# LoongArch64 ASM exception handler +# +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#------------------------------------------------------------------------------ + +#include <Library/BaseLib.h> +#include <Library/CpuLib.h> +#include <Register/LoongArch64/Csr.h> + +#define RSIZE 8 // 64 bit mode register size +#define GP_REG_CONTEXT_SIZE 32 * RSIZE // General-purpose registers size +#define FP_REG_CONTEXT_SIZE 34 * RSIZE // Floating-point registers size +#define CSR_REG_CONTEXT_SIZE 9 * RSIZE // CSR registers size + +ASM_GLOBAL ASM_PFX(ExceptionEntry) +ASM_GLOBAL ASM_PFX(ExceptionEntryStart) +ASM_GLOBAL ASM_PFX(ExceptionEntryEnd) + +ASM_PFX(ExceptionEntry): + move $s0, $a0 + bl GetExceptionType // Exception type stored in register a0 + move $a1, $s0 // SystemContxt + bl CommonExceptionHandler + +PopContext: + // + // Not sure if interrupts are turned on during the exception handler, anyway disable interrupts here. + // It will be turned on when the instruction 'ertn' is executed. + // + bl DisableInterrupts + + bl GetExceptionType // Get current exception type, and stored in register a0 + + // Check whether the FPE is changed during interrupt handler, if ture restore it. + ld.d $t1, $sp, (LOONGARCH_CSR_EUEN * RSIZE + GP_REG_CONTEXT_SIZE) + csrrd $t0, LOONGARCH_CSR_EUEN // Current EUEN + andi $t0, $t0, CSR_EUEN_FPEN + andi $t1, $t1, CSR_EUEN_FPEN + li.d $t2, EXCEPT_LOONGARCH_INT + bne $a0, $t2, PopRegs + beq $t0, $t1, PopRegs + beqz $t1, CloseFP + bl EnableFloatingPointUnits + b PopRegs + +CloseFP: + bl DisableFloatingPointUnits + +PopRegs: + // + // Pop CSR reigsters + // + addi.d $sp, $sp, GP_REG_CONTEXT_SIZE + + ld.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE + csrwr $t0, LOONGARCH_CSR_CRMD + ld.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE + csrwr $t0, LOONGARCH_CSR_PRMD + ld.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE + csrwr $t0, LOONGARCH_CSR_ECFG + ld.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE + csrwr $t0, LOONGARCH_CSR_ERA + + addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE // Fource change the stack pointer befor pop the FP registers. + + beqz $t1, PopGP // If the FPE not set, only pop the GP registers. + + // + // Pop FP registers + // + fld.d $fa0, $sp, 0 * RSIZE + fld.d $fa1, $sp, 1 * RSIZE + fld.d $fa2, $sp, 2 * RSIZE + fld.d $fa3, $sp, 3 * RSIZE + fld.d $fa4, $sp, 4 * RSIZE + fld.d $fa5, $sp, 5 * RSIZE + fld.d $fa6, $sp, 6 * RSIZE + fld.d $fa7, $sp, 7 * RSIZE + fld.d $ft0, $sp, 8 * RSIZE + fld.d $ft1, $sp, 9 * RSIZE + fld.d $ft2, $sp, 10 * RSIZE + fld.d $ft3, $sp, 11 * RSIZE + fld.d $ft4, $sp, 12 * RSIZE + fld.d $ft5, $sp, 13 * RSIZE + fld.d $ft6, $sp, 14 * RSIZE + fld.d $ft7, $sp, 15 * RSIZE + fld.d $ft8, $sp, 16 * RSIZE + fld.d $ft9, $sp, 17 * RSIZE + fld.d $ft10, $sp, 18 * RSIZE + fld.d $ft11, $sp, 19 * RSIZE + fld.d $ft12, $sp, 20 * RSIZE + fld.d $ft13, $sp, 21 * RSIZE + fld.d $ft14, $sp, 22 * RSIZE + fld.d $ft15, $sp, 23 * RSIZE + fld.d $fs0, $sp, 24 * RSIZE + fld.d $fs1, $sp, 25 * RSIZE + fld.d $fs2, $sp, 26 * RSIZE + fld.d $fs3, $sp, 27 * RSIZE + fld.d $fs4, $sp, 28 * RSIZE + fld.d $fs5, $sp, 29 * RSIZE + fld.d $fs6, $sp, 30 * RSIZE + fld.d $fs7, $sp, 31 * RSIZE + + ld.d $t0, $sp, 32 * RSIZE + movgr2fcsr $r0, $t0 // Pop the fcsr0 register. + + // + // Pop the fcc0-fcc7 registers. + // + ld.d $t0, $sp, 33 * RSIZE + bstrpick.d $t1, $t0, 7, 0 + movgr2cf $fcc0, $t1 + bstrpick.d $t1, $t0, 15, 8 + movgr2cf $fcc1, $t1 + bstrpick.d $t1, $t0, 23, 16 + movgr2cf $fcc2, $t1 + bstrpick.d $t1, $t0, 31, 24 + movgr2cf $fcc3, $t1 + bstrpick.d $t1, $t0, 39, 32 + movgr2cf $fcc4, $t1 + bstrpick.d $t1, $t0, 47, 40 + movgr2cf $fcc5, $t1 + bstrpick.d $t1, $t0, 55, 48 + movgr2cf $fcc6, $t1 + bstrpick.d $t1, $t0, 63, 56 + movgr2cf $fcc7, $t1 + +PopGP: + // + // Pop GP registers + // + addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE) + ld.d $ra, $sp, 1 * RSIZE + ld.d $tp, $sp, 2 * RSIZE + ld.d $a0, $sp, 4 * RSIZE + ld.d $a1, $sp, 5 * RSIZE + ld.d $a2, $sp, 6 * RSIZE + ld.d $a3, $sp, 7 * RSIZE + ld.d $a4, $sp, 8 * RSIZE + ld.d $a5, $sp, 9 * RSIZE + ld.d $a6, $sp, 10 * RSIZE + ld.d $a7, $sp, 11 * RSIZE + ld.d $t0, $sp, 12 * RSIZE + ld.d $t1, $sp, 13 * RSIZE + ld.d $t2, $sp, 14 * RSIZE + ld.d $t3, $sp, 15 * RSIZE + ld.d $t4, $sp, 16 * RSIZE + ld.d $t5, $sp, 17 * RSIZE + ld.d $t6, $sp, 18 * RSIZE + ld.d $t7, $sp, 19 * RSIZE + ld.d $t8, $sp, 20 * RSIZE + ld.d $r21, $sp, 21 * RSIZE + ld.d $fp, $sp, 22 * RSIZE + ld.d $s0, $sp, 23 * RSIZE + ld.d $s1, $sp, 24 * RSIZE + ld.d $s2, $sp, 25 * RSIZE + ld.d $s3, $sp, 26 * RSIZE + ld.d $s4, $sp, 27 * RSIZE + ld.d $s5, $sp, 28 * RSIZE + ld.d $s6, $sp, 29 * RSIZE + ld.d $s7, $sp, 30 * RSIZE + ld.d $s8, $sp, 31 * RSIZE + ld.d $sp, $sp, 3 * RSIZE + + ertn // Returen from exception. +// +// End of ExceptionEntry +// + +ASM_PFX(ExceptionEntryStart): + // + // Store the old stack pointer in preparation for pushing the exception context onto the new stack. + // + csrwr $sp, LOONGARCH_CSR_KS0 + + csrrd $sp, LOONGARCH_CSR_KS0 + + // + // Push GP registers + // + addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + FP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE) + st.d $zero, $sp, 0 * RSIZE + st.d $ra, $sp, 1 * RSIZE + st.d $tp, $sp, 2 * RSIZE + st.d $a0, $sp, 4 * RSIZE + st.d $a1, $sp, 5 * RSIZE + st.d $a2, $sp, 6 * RSIZE + st.d $a3, $sp, 7 * RSIZE + st.d $a4, $sp, 8 * RSIZE + st.d $a5, $sp, 9 * RSIZE + st.d $a6, $sp, 10 * RSIZE + st.d $a7, $sp, 11 * RSIZE + st.d $t0, $sp, 12 * RSIZE + st.d $t1, $sp, 13 * RSIZE + st.d $t2, $sp, 14 * RSIZE + st.d $t3, $sp, 15 * RSIZE + st.d $t4, $sp, 16 * RSIZE + st.d $t5, $sp, 17 * RSIZE + st.d $t6, $sp, 18 * RSIZE + st.d $t7, $sp, 19 * RSIZE + st.d $t8, $sp, 20 * RSIZE + st.d $r21, $sp, 21 * RSIZE + st.d $fp, $sp, 22 * RSIZE + st.d $s0, $sp, 23 * RSIZE + st.d $s1, $sp, 24 * RSIZE + st.d $s2, $sp, 25 * RSIZE + st.d $s3, $sp, 26 * RSIZE + st.d $s4, $sp, 27 * RSIZE + st.d $s5, $sp, 28 * RSIZE + st.d $s6, $sp, 29 * RSIZE + st.d $s7, $sp, 30 * RSIZE + st.d $s8, $sp, 31 * RSIZE + csrrd $t0, LOONGARCH_CSR_KS0 // Read the old stack pointer. + st.d $t0, $sp, 3 * RSIZE + + // + // Push CSR registers + // + addi.d $sp, $sp, GP_REG_CONTEXT_SIZE + + csrrd $t0, LOONGARCH_CSR_CRMD + st.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE + csrrd $t0, LOONGARCH_CSR_PRMD + st.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE + csrrd $t0, LOONGARCH_CSR_EUEN + st.d $t0, $sp, LOONGARCH_CSR_EUEN * RSIZE + csrrd $t0, LOONGARCH_CSR_MISC + st.d $t0, $sp, LOONGARCH_CSR_MISC * RSIZE + csrrd $t0, LOONGARCH_CSR_ECFG + st.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE + csrrd $t0, LOONGARCH_CSR_ESTAT + st.d $t0, $sp, LOONGARCH_CSR_ESTAT * RSIZE + csrrd $t0, LOONGARCH_CSR_ERA + st.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE + csrrd $t0, LOONGARCH_CSR_BADV + st.d $t0, $sp, LOONGARCH_CSR_BADV * RSIZE + csrrd $t0, LOONGARCH_CSR_BADI + st.d $t0, $sp, LOONGARCH_CSR_BADI * RSIZE + + // + // Push FP registers + // + addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE + + csrrd $t0, LOONGARCH_CSR_EUEN + andi $t0, $t0, CSR_EUEN_FPEN + beqz $t0, PushRegDone + + fst.d $fa0, $sp, 0 * RSIZE + fst.d $fa1, $sp, 1 * RSIZE + fst.d $fa2, $sp, 2 * RSIZE + fst.d $fa3, $sp, 3 * RSIZE + fst.d $fa4, $sp, 4 * RSIZE + fst.d $fa5, $sp, 5 * RSIZE + fst.d $fa6, $sp, 6 * RSIZE + fst.d $fa7, $sp, 7 * RSIZE + fst.d $ft0, $sp, 8 * RSIZE + fst.d $ft1, $sp, 9 * RSIZE + fst.d $ft2, $sp, 10 * RSIZE + fst.d $ft3, $sp, 11 * RSIZE + fst.d $ft4, $sp, 12 * RSIZE + fst.d $ft5, $sp, 13 * RSIZE + fst.d $ft6, $sp, 14 * RSIZE + fst.d $ft7, $sp, 15 * RSIZE + fst.d $ft8, $sp, 16 * RSIZE + fst.d $ft9, $sp, 17 * RSIZE + fst.d $ft10, $sp, 18 * RSIZE + fst.d $ft11, $sp, 19 * RSIZE + fst.d $ft12, $sp, 20 * RSIZE + fst.d $ft13, $sp, 21 * RSIZE + fst.d $ft14, $sp, 22 * RSIZE + fst.d $ft15, $sp, 23 * RSIZE + fst.d $fs0, $sp, 24 * RSIZE + fst.d $fs1, $sp, 25 * RSIZE + fst.d $fs2, $sp, 26 * RSIZE + fst.d $fs3, $sp, 27 * RSIZE + fst.d $fs4, $sp, 28 * RSIZE + fst.d $fs5, $sp, 29 * RSIZE + fst.d $fs6, $sp, 30 * RSIZE + fst.d $fs7, $sp, 31 * RSIZE + + movfcsr2gr $t3, $r0 + st.d $t3, $sp, 32 * RSIZE // Push the FCSR0 register. + + // + // Push the fcc0-fcc7 registers. + // + movcf2gr $t3, $fcc0 + or $t2, $t3, $zero + movcf2gr $t3, $fcc1 + bstrins.d $t2, $t3, 0xf, 0x8 + movcf2gr $t3, $fcc2 + bstrins.d $t2, $t3, 0x17, 0x10 + movcf2gr $t3, $fcc3 + bstrins.d $t2, $t3, 0x1f, 0x18 + movcf2gr $t3, $fcc4 + bstrins.d $t2, $t3, 0x27, 0x20 + movcf2gr $t3, $fcc5 + bstrins.d $t2, $t3, 0x2f, 0x28 + movcf2gr $t3, $fcc6 + bstrins.d $t2, $t3, 0x37, 0x30 + movcf2gr $t3, $fcc7 + bstrins.d $t2, $t3, 0x3f, 0x38 + st.d $t2, $sp, 33 * RSIZE + // + // Push exception context down + // + +PushRegDone: + // + // Process IPI only when mailbox3 is NULL and mailbox0 is no-NULL. + // + li.d $t0, LOONGARCH_IOCSR_MBUF0 + iocsrrd.d $a0, $t0 + beqz $a0, EntryConmmonHanlder + + li.d $t0, LOONGARCH_IOCSR_MBUF3 + iocsrrd.d $t1, $t0 + bnez $t1, EntryConmmonHanlder + + csrrd $t0, LOONGARCH_CSR_ESTAT + srli.d $t0, $t0, 12 + andi $t0, $t0, 0x1 + beqz $t0, EntryConmmonHanlder + + // + // Clean up current processor mailbox 0 and mailbox 3. + // + li.d $t0, LOONGARCH_IOCSR_MBUF0 + iocsrwr.d $zero, $t0 + li.d $t0, LOONGARCH_IOCSR_MBUF3 + iocsrwr.d $zero, $t0 + + // + // Clear IPI interrupt. + // + li.d $t0, LOONGARCH_IOCSR_IPI_STATUS + iocsrrd.w $t1, $t0 + li.d $t0, LOONGARCH_IOCSR_IPI_CLEAR + iocsrwr.w $t1, $t0 + + // + // Only kernel stage BSP calls IPI without parameters. Clean up the PIE and make sure + // global interrupts are turned off for the current processor when jumping to the kernel. + // + csrwr $a0, LOONGARCH_CSR_ERA // Update ERA + li.w $t0, BIT2 // IE + csrxchg $zero, $t0, LOONGARCH_CSR_PRMD // Clean PIE + + // + // Return this exception and jump to kernel using ERA. + // + ertn + +EntryConmmonHanlder: + addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE) + move $a0, $sp + la.abs $ra, ExceptionEntry + jirl $zero, $ra, 0 +ASM_PFX(ExceptionEntryEnd): +.end diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c new file mode 100644 index 0000000000..7588d2050b --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c @@ -0,0 +1,102 @@ +/** @file SecPeiExceptionLib.c + + LoongArch exception library implemenation for PEI and SEC modules. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Library/BaseLib.h> +#include <Library/CpuLib.h> +#include <Library/CpuExceptionHandlerLib.h> +#include <Library/DebugLib.h> +#include <Library/SerialPortLib.h> +#include <Protocol/DebugSupport.h> +#include <Register/LoongArch64/Csr.h> + +#include "ExceptionCommon.h" + +/** + Registers a function to be called from the processor interrupt or exception handler. + + Always return EFI_UNSUPPORTED in the SEC exception initialization module. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_EXCEPTION_TYPE InterruptType; + + if (ExceptionType == EXCEPT_LOONGARCH_INT) { + // + // Interrupt + // + InterruptType = GetInterruptType (SystemContext); + if (InterruptType == EXCEPT_LOONGARCH_INT_IPI) { + // + // APs may wake up via IPI IRQ during the SEC or PEI phase, clear the IPI interrupt and + // perform the remaining work. + // + IpiInterruptHandler (InterruptType, SystemContext); + return; + } else { + ExceptionType = InterruptType; + } + } else { + // + // Exception + // + ExceptionType >>= CSR_ESTAT_EXC_SHIFT; + } + + DefaultExceptionHandler (ExceptionType, SystemContext); +} + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Always return EFI_SUCCESS in the SEC exception initialization module. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized + with default exception handlers. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf index e7b1144f69..6bb194ea77 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -2,6 +2,7 @@ # CPU Exception Handler library instance for SEC/PEI modules. # # Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -18,37 +19,47 @@ # # The following information is for reference only and not required by the build tools. # -# VALID_ARCHITECTURES = IA32 X64 +# VALID_ARCHITECTURES = IA32 X64 LOONGARCH64 # [Sources.Ia32] - Ia32/ExceptionHandlerAsm.nasm - Ia32/ExceptionTssEntryAsm.nasm Ia32/ArchExceptionHandler.c Ia32/ArchInterruptDefs.h + Ia32/ExceptionHandlerAsm.nasm + Ia32/ExceptionTssEntryAsm.nasm [Sources.X64] - X64/SecPeiExceptionHandlerAsm.nasm X64/ArchExceptionHandler.c X64/ArchInterruptDefs.h + X64/SecPeiExceptionHandlerAsm.nasm -[Sources.common] +[Sources.Ia32, Sources.X64] CpuExceptionCommon.h CpuExceptionCommon.c SecPeiCpuException.c +[Sources.LoongArch64] + LoongArch/ExceptionCommon.h + LoongArch/ExceptionCommon.c + LoongArch/SecPeiExceptionLib.c + LoongArch/LoongArch64/ArchExceptionHandler.c + LoongArch/LoongArch64/ExceptionHandlerAsm.S | GCC + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec -[LibraryClasses] +[LibraryClasses.common] BaseLib - SerialPortLib - PrintLib - LocalApicLib + CpuLib PeCoffGetEntryPointLib + PrintLib + SerialPortLib + +[LibraryClasses.Ia32, LibraryClasses.X64] CcExitLib + LocalApicLib [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 571b59b36f..f5febe46ba 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -3,6 +3,7 @@ # # Copyright (c) 2007 - 2023, Intel Corporation. All rights reserved.<BR> # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -385,6 +386,10 @@ # @Prompt Enable performance collecting when processor trace is enabled. gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTracePerformanceCollecting|FALSE|BOOLEAN|0x60000020 + ## This PCD Contains the pointer to a CPU exception vector base address. + # @Prompt The pointer to a CPU exception vector base address. + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress|0x0|UINT64|0x60000022 + [PcdsFixedAtBuild.X64, PcdsPatchableInModule.X64, PcdsDynamic.X64, PcdsDynamicEx.X64] ## Indicate access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock. # MMIO access is always allowed regardless of the value of this PCD.