From 7750468c37e04bbf261056a4e96f06accd1517ce Mon Sep 17 00:00:00 2001 From: Chao Li Date: Fri, 8 Mar 2024 16:24:12 +0800 Subject: UefiCpuPkg: Add CPU exception library for LoongArch Added LoongArch exception handler into CpuExceptionHandlerLib. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4734 Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Signed-off-by: Chao Li Co-authored-by: Baoqi Zhang Acked-by: Gerd Hoffmann Reviewed-by: Ray Ni --- .../DxeCpuExceptionHandlerLib.inf | 23 +- .../LoongArch/DxeExceptionLib.c | 198 +++++++++++ .../LoongArch/ExceptionCommon.c | 171 ++++++++++ .../LoongArch/ExceptionCommon.h | 131 ++++++++ .../LoongArch/LoongArch64/ArchExceptionHandler.c | 268 +++++++++++++++ .../LoongArch/LoongArch64/ExceptionHandlerAsm.S | 366 +++++++++++++++++++++ .../LoongArch/SecPeiExceptionLib.c | 102 ++++++ .../SecPeiCpuExceptionHandlerLib.inf | 23 +- 8 files changed, 1273 insertions(+), 9 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 aabcabff0f..9fcba009d6 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -2,6 +2,7 @@ # CPU Exception Handler library instance for DXE modules. # # Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -18,7 +19,7 @@ # # 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] @@ -32,12 +33,19 @@ X64/ArchInterruptDefs.h X64/ExceptionHandlerAsm.nasm -[Sources.common] +[Sources.Ia32, Sources.X64] CpuExceptionCommon.h CpuExceptionCommon.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 gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList @@ -51,16 +59,21 @@ MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec -[LibraryClasses] +[LibraryClasses.common] BaseLib - CcExitLib DebugLib - LocalApicLib MemoryAllocationLib PeCoffGetEntryPointLib PrintLib SerialPortLib SynchronizationLib +[LibraryClasses.Ia32, LibraryClasses.X64] + CcExitLib + LocalApicLib + +[LibraryClasses.LoongArch64] + CpuLib + [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..eed5644552 --- /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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 >>= CSR_ESTAT_EXC_SHIFT, convert to ECODE + // + ExceptionType >>= CSR_ESTAT_EXC_SHIFT; + + if (ExceptionType > EXCEPT_LOONGARCH_FPE) { + return EFI_UNSUPPORTED; + } + + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#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.
+ + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#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.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#------------------------------------------------------------------------------ + +#include +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +#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 f8e597d86d..64de252dcd 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.
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -19,6 +20,7 @@ # 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] @@ -32,24 +34,37 @@ 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 - CcExitLib - LocalApicLib PeCoffGetEntryPointLib PrintLib SerialPortLib +[LibraryClasses.Ia32, LibraryClasses.X64] + CcExitLib + LocalApicLib + +[LibraryClasses.LoongArch64] + CpuLib + [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList -- cgit v1.2.3