Hi Ray, Can you please help to review this patch again? Thanks, Chao On 2024/1/26 14:29, Chao Li wrote: > 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 > Cc: Ray Ni > Cc: Rahul Kumar > Cc: Gerd Hoffmann > Signed-off-by: Chao Li > Co-authored-by: Baoqi Zhang > --- > .../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.
> + > + 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 > + // > + 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.
> + > + 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 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.
> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> # 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.
> # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
> +# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> # > # 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. -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114849): https://edk2.groups.io/g/devel/message/114849 Mute This Topic: https://groups.io/mt/104068938/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-