public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v1 10/29] UefiCpuPkg: Add CPU exception library for LoongArch
@ 2023-11-03  1:03 Chao Li
  0 siblings, 0 replies; only message in thread
From: Chao Li @ 2023-11-03  1:03 UTC (permalink / raw)
  To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang

Added a new library named LoongArch64CpuExceptionHandlerLib, and
modified the way LoongArch exceptions are expressed.

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>
---
 MdePkg/Include/Protocol/DebugSupport.h        |  76 +++--
 .../DxeCpuExceptionHandlerLib.inf             |  45 +++
 .../DxeCpuExceptionHandlerLib.uni             |  15 +
 .../DxeExceptionLib.c                         | 202 +++++++++++
 .../ExceptionCommon.c                         | 170 ++++++++++
 .../ExceptionCommon.h                         | 111 ++++++
 .../LoongArch64/ArchExceptionHandler.c        | 214 ++++++++++++
 .../LoongArch64/ExceptionHandlerAsm.S         | 320 ++++++++++++++++++
 .../SecPeiCpuExceptionHandlerLib.inf          |  45 +++
 .../SecPeiCpuExceptionHandlerLib.uni          |  15 +
 .../SecPeiExceptionLib.c                      |  90 +++++
 UefiCpuPkg/UefiCpuPkg.dec                     |   6 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   2 +
 13 files changed, 1279 insertions(+), 32 deletions(-)
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
 create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c

diff --git a/MdePkg/Include/Protocol/DebugSupport.h b/MdePkg/Include/Protocol/DebugSupport.h
index 9742663619..ccdddd4828 100644
--- a/MdePkg/Include/Protocol/DebugSupport.h
+++ b/MdePkg/Include/Protocol/DebugSupport.h
@@ -680,33 +680,45 @@ typedef struct {
   UINT32    STVAL;
 } EFI_SYSTEM_CONTEXT_RISCV64;
 
-//
-// LoongArch processor exception types.
-//
-#define EXCEPT_LOONGARCH_INT   0
-#define EXCEPT_LOONGARCH_PIL   1
-#define EXCEPT_LOONGARCH_PIS   2
-#define EXCEPT_LOONGARCH_PIF   3
-#define EXCEPT_LOONGARCH_PME   4
-#define EXCEPT_LOONGARCH_PNR   5
-#define EXCEPT_LOONGARCH_PNX   6
-#define EXCEPT_LOONGARCH_PPI   7
-#define EXCEPT_LOONGARCH_ADE   8
-#define EXCEPT_LOONGARCH_ALE   9
-#define EXCEPT_LOONGARCH_BCE   10
-#define EXCEPT_LOONGARCH_SYS   11
-#define EXCEPT_LOONGARCH_BRK   12
-#define EXCEPT_LOONGARCH_INE   13
-#define EXCEPT_LOONGARCH_IPE   14
-#define EXCEPT_LOONGARCH_FPD   15
-#define EXCEPT_LOONGARCH_SXD   16
-#define EXCEPT_LOONGARCH_ASXD  17
-#define EXCEPT_LOONGARCH_FPE   18
-#define EXCEPT_LOONGARCH_TBR   64 // For code only, there is no such type in the ISA spec, the TLB refill is defined for an independent exception.
-
-//
-// LoongArch processor Interrupt types.
-//
+///
+/// LoongArch processor exception types.
+///
+#define EXCEPT_LOONGARCH_ECODE_SHIFT  16
+#define EXCEPT_LOONGARCH_INT          (0 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIL          (1 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIS          (2 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIF          (3 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PME          (4 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PNR          (5 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PNX          (6 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PPI          (7 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ADE          (8 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ALE          (9 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BCE          (10  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_SYS          (11  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BRK          (12  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_INE          (13  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_IPE          (14  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_FPD          (15  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_SXD          (16  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ASXD         (17  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_FPE          (18  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_WPE          (19  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BTD          (20  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BTE          (21  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_GSPR         (22  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_HVC          (23  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_GCXC         (24  << EXCEPT_LOONGARCH_ECODE_SHIFT)
+
+///
+/// For coding convenience, define the maximum valid
+/// LoongArch exception.
+///
+#define MAX_LOONGARCH_EXCEPTION  64
+
+///
+/// LoongArch processor Interrupt types.
+///
 #define EXCEPT_LOONGARCH_INT_SIP0   0
 #define EXCEPT_LOONGARCH_INT_SIP1   1
 #define EXCEPT_LOONGARCH_INT_IP0    2
@@ -721,11 +733,11 @@ typedef struct {
 #define EXCEPT_LOONGARCH_INT_TIMER  11
 #define EXCEPT_LOONGARCH_INT_IPI    12
 
-//
-// For coding convenience, define the maximum valid
-// LoongArch interrupt.
-//
-#define MAX_LOONGARCH_INTERRUPT  14
+///
+/// For coding convenience, define the maximum valid
+/// LoongArch interrupt.
+///
+#define MAX_LOONGARCH_INTERRUPT  16
 
 typedef struct {
   UINT64    R0;
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
new file mode 100644
index 0000000000..fa38218464
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -0,0 +1,45 @@
+## @file
+#  LoongArch exception library instance for DXE modules.
+#
+#  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeCpuExceptionHandlerLib
+  MODULE_UNI_FILE                = DxeCpuExceptionHandlerLib.uni
+  FILE_GUID                      = 23C5D29F-F54B-091B-BD94-027576ED09FA
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources.LoongArch64]
+  LoongArch64/ArchExceptionHandler.c
+  LoongArch64/ExceptionHandlerAsm.S | GCC
+
+[Sources.common]
+  ExceptionCommon.h
+  ExceptionCommon.c
+  DxeExceptionLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  CpuLib
+  BaseLib
+  SerialPortLib
+  PrintLib
+  PeCoffGetEntryPointLib
+  SynchronizationLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
new file mode 100644
index 0000000000..d884387da3
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU Exception Handler library instance for DXE modules.
+//
+// CPU Exception Handler library instance for DXE modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "CPU Exception Handler library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "CPU Exception Handler library instance for DXE modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
new file mode 100644
index 0000000000..f274f82c51
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
@@ -0,0 +1,202 @@
+/** @file DxeExceptionLib.c
+
+  LoongArch exception library implemenation for DXE modules.
+
+  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include <Protocol/DebugSupport.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 >>= EXCEPT_LOONGARCH_ECODE_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 >>= EXCEPT_LOONGARCH_ECODE_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/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
new file mode 100644
index 0000000000..aa58a4128a
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
@@ -0,0 +1,170 @@
+/** @file DxeExceptionLib.c
+
+  CPU Exception Handler Library common functions.
+
+  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PeCoffGetEntryPointLib.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/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
new file mode 100644
index 0000000000..b19144b196
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
@@ -0,0 +1,111 @@
+/** @file DxeExceptionLib.h
+
+  Common header file for CPU Exception Handler Library.
+
+  Copyright (c) 2023, 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
+
+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
+  );
+
+/**
+  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/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
new file mode 100644
index 0000000000..2b2f75aad0
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
@@ -0,0 +1,214 @@
+/** @file ArchExceptionHandler.c
+
+  LoongArch64 CPU Exception Handler.
+
+  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#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);
+  }
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
new file mode 100644
index 0000000000..88a5f696a7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
@@ -0,0 +1,320 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch64 ASM exception handler
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <Library/CpuLib.h>
+#include <Library/BaseLib.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:
+  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/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
new file mode 100644
index 0000000000..456354ff04
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -0,0 +1,45 @@
+## @file
+#  LoongArch exception library instance for PEI and SEC modules.
+#
+#  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecPeiCpuExceptionHandlerLib
+  MODULE_UNI_FILE                = SecPeiCpuExceptionHandlerLib.uni
+  FILE_GUID                      = 0D69E6CD-1423-F118-C4EF-7AA439BC3E3B
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = CpuExceptionHandlerLib|SEC PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources.LoongArch64]
+  LoongArch64/ArchExceptionHandler.c
+  LoongArch64/ExceptionHandlerAsm.S | GCC
+
+[Sources.common]
+  ExceptionCommon.h
+  ExceptionCommon.c
+  SecPeiExceptionLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  CpuLib
+  BaseLib
+  SerialPortLib
+  PrintLib
+  PeCoffGetEntryPointLib
+  SynchronizationLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
new file mode 100644
index 0000000000..81fd606278
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c
new file mode 100644
index 0000000000..c140450d5b
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c
@@ -0,0 +1,90 @@
+/** @file SecPeiExceptionLib.c
+
+  LoongArch exception library implemenation for PEI and SEC modules.
+
+  Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include <Protocol/DebugSupport.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
+  )
+{
+  //
+  // APs may wake up by IPI IRQ during the SEC or PEI phase, clear the IPI interrupt and return.
+  //
+  if (GetInterruptType (SystemContext) == EXCEPT_LOONGARCH_INT_IPI) {
+    DisableLocalInterrupts (1 << EXCEPT_LOONGARCH_INT_IPI);
+    IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS));
+    return;
+  } else {
+    ExceptionType >>= EXCEPT_LOONGARCH_ECODE_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/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 0b5431dbf7..154b1d06fe 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) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -404,6 +405,11 @@
   #  10 - 57bit mode.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuRiscVMmuMaxSatpMode|10|UINT32|0x60000021
 
+[PcdsFixedAtBuild.LoongArch64, PcdsPatchableInModule.LoongArch64, PcdsDynamic.LoongArch64, PcdsDynamicEx.LoongArch64]
+  ## Contains the pointer to a CPU exception vector base address.
+  # @Prompt The pointer to a CPU exception vector base address.
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress|0x0|UINT64|0x62640000
+
 [PcdsDynamic, PcdsDynamicEx]
   ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA.
   # @Prompt The pointer to a CPU S3 data buffer.
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 8e34a9cd6b..872f20fc36 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -207,6 +207,8 @@
 
 [Components.LOONGARCH64]
   UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
+  UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+  UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
 
 [BuildOptions]
   *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110583): https://edk2.groups.io/g/devel/message/110583
Mute This Topic: https://groups.io/mt/102355710/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-03  1:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-03  1:03 [edk2-devel] [PATCH v1 10/29] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox