summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c')
-rw-r--r--UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c238
1 files changed, 215 insertions, 23 deletions
diff --git a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c
index f1ee7d236a..bce089feb0 100644
--- a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c
+++ b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c
@@ -11,11 +11,168 @@
#include <Library/CpuExceptionHandlerLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PrintLib.h>
#include <Register/RiscV64/RiscVEncoding.h>
-
#include "CpuExceptionHandlerLib.h"
-STATIC EFI_CPU_INTERRUPT_HANDLER mInterruptHandlers[2];
+//
+// Define the maximum message length
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+STATIC EFI_CPU_INTERRUPT_HANDLER mExceptionHandlers[EXCEPT_RISCV_MAX_EXCEPTIONS + 1];
+STATIC EFI_CPU_INTERRUPT_HANDLER mIrqHandlers[EXCEPT_RISCV_MAX_IRQS + 1];
+
+STATIC CONST CHAR8 mExceptionOrIrqUnknown[] = "Unknown";
+STATIC CONST CHAR8 *mExceptionNameStr[EXCEPT_RISCV_MAX_EXCEPTIONS + 1] = {
+ "EXCEPT_RISCV_INST_MISALIGNED",
+ "EXCEPT_RISCV_INST_ACCESS_FAULT",
+ "EXCEPT_RISCV_ILLEGAL_INST",
+ "EXCEPT_RISCV_BREAKPOINT",
+ "EXCEPT_RISCV_LOAD_ADDRESS_MISALIGNED",
+ "EXCEPT_RISCV_LOAD_ACCESS_FAULT",
+ "EXCEPT_RISCV_STORE_AMO_ADDRESS_MISALIGNED",
+ "EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT",
+ "EXCEPT_RISCV_ENV_CALL_FROM_UMODE",
+ "EXCEPT_RISCV_ENV_CALL_FROM_SMODE",
+ "EXCEPT_RISCV_ENV_CALL_FROM_VS_MODE",
+ "EXCEPT_RISCV_ENV_CALL_FROM_MMODE",
+ "EXCEPT_RISCV_INST_ACCESS_PAGE_FAULT",
+ "EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT",
+ "EXCEPT_RISCV_14",
+ "EXCEPT_RISCV_STORE_ACCESS_PAGE_FAULT",
+ "EXCEPT_RISCV_16",
+ "EXCEPT_RISCV_17",
+ "EXCEPT_RISCV_18",
+ "EXCEPT_RISCV_19",
+ "EXCEPT_RISCV_INST_GUEST_PAGE_FAULT",
+ "EXCEPT_RISCV_LOAD_GUEST_PAGE_FAULT",
+ "EXCEPT_RISCV_VIRTUAL_INSTRUCTION",
+ "EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT"
+};
+
+STATIC CONST CHAR8 *mIrqNameStr[EXCEPT_RISCV_MAX_IRQS + 1] = {
+ "EXCEPT_RISCV_IRQ_0",
+ "EXCEPT_RISCV_IRQ_SOFT_FROM_SMODE",
+ "EXCEPT_RISCV_IRQ_SOFT_FROM_VSMODE",
+ "EXCEPT_RISCV_IRQ_SOFT_FROM_MMODE",
+ "EXCEPT_RISCV_IRQ_4",
+ "EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE",
+};
+
+/**
+ 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.
+
+**/
+STATIC
+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));
+}
+
+/**
+ Get ASCII format string exception name by exception type.
+
+ @param ExceptionType Exception type.
+
+ @return ASCII format string exception name.
+**/
+STATIC
+CONST CHAR8 *
+GetExceptionNameStr (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ if (EXCEPT_RISCV_IS_IRQ (ExceptionType)) {
+ if (EXCEPT_RISCV_IRQ_INDEX (ExceptionType) > EXCEPT_RISCV_MAX_IRQS) {
+ return mExceptionOrIrqUnknown;
+ }
+
+ return mIrqNameStr[EXCEPT_RISCV_IRQ_INDEX (ExceptionType)];
+ }
+
+ if (ExceptionType > EXCEPT_RISCV_MAX_EXCEPTIONS) {
+ return mExceptionOrIrqUnknown;
+ }
+
+ return mExceptionNameStr[ExceptionType];
+}
+
+/**
+ Display CPU information. This can be called by 3rd-party handlers
+ set by RegisterCpuInterruptHandler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Printed;
+ SMODE_TRAP_REGISTERS *Regs;
+
+ Printed = 0;
+ Regs = (SMODE_TRAP_REGISTERS *)SystemContext.SystemContextRiscV64;
+
+ InternalPrintMessage (
+ "!!!! RISCV64 Exception Type - %016x(%a) !!!!\n",
+ ExceptionType,
+ GetExceptionNameStr (ExceptionType)
+ );
+
+ DEBUG_CODE_BEGIN ();
+
+ #define REGS() \
+ REG (t0); REG (t1); REG (t2); REG (t3); REG (t4); REG (t5); REG (t6); \
+ REG (s0); REG (s1); REG (s2); REG (s3); REG (s4); REG (s5); REG (s6); \
+ REG (s7); REG (s8); REG (s9); REG (s10); REG (s11); \
+ REG (a0); REG (a1); REG (a2); REG (a3); REG (a4); REG (a5); REG (a6); \
+ REG (a7); \
+ REG (zero); REG (ra); REG (sp); REG (gp); REG (tp); \
+ REG (sepc); REG (sstatus); REG (stval);
+
+ #define REG(x) do { \
+ InternalPrintMessage ("%7a = 0x%017lx%c", #x, Regs->x, \
+ (++Printed % 2) ? L'\t' : L'\n'); \
+ } while (0);
+
+ REGS ();
+ if (Printed % 2 != 0) {
+ InternalPrintMessage ("\n");
+ }
+
+ #undef REG
+ #undef REGS
+
+ DEBUG_CODE_END ();
+}
/**
Initializes all CPU exceptions entries and provides the default exception handlers.
@@ -47,34 +204,59 @@ InitializeCpuExceptionHandlers (
Registers a function to be called from the processor interrupt 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.
+ interrupt or exception type specified by ExceptionType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by ExceptionType is uninstalled.
The installed handler is called once for each processor interrupt or exception.
NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
- @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] ExceptionType Defines which interrupt or exception to hook.
@param[in] 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
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for ExceptionType was
previously installed.
- @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for ExceptionType was not
previously installed.
- @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ @retval EFI_UNSUPPORTED The interrupt specified by ExceptionType is not supported,
or this function is not supported.
**/
EFI_STATUS
EFIAPI
RegisterCpuInterruptHandler (
- IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
)
{
- DEBUG ((DEBUG_INFO, "%a: Type:%x Handler: %x\n", __FUNCTION__, InterruptType, InterruptHandler));
- mInterruptHandlers[InterruptType] = InterruptHandler;
+ DEBUG ((DEBUG_INFO, "%a: Type:%x Handler: %x\n", __FUNCTION__, ExceptionType, InterruptHandler));
+ if (EXCEPT_RISCV_IS_IRQ (ExceptionType)) {
+ if (EXCEPT_RISCV_IRQ_INDEX (ExceptionType) > EXCEPT_RISCV_MAX_IRQS) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mIrqHandlers[EXCEPT_RISCV_IRQ_INDEX (ExceptionType)] != NULL) {
+ return EFI_ALREADY_STARTED;
+ } else if (InterruptHandler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mIrqHandlers[EXCEPT_RISCV_IRQ_INDEX (ExceptionType)] = InterruptHandler;
+ } else {
+ if (ExceptionType > EXCEPT_RISCV_MAX_EXCEPTIONS) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mExceptionHandlers[ExceptionType] != NULL) {
+ return EFI_ALREADY_STARTED;
+ } else if (InterruptHandler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mExceptionHandlers[ExceptionType] = InterruptHandler;
+ }
+
return EFI_SUCCESS;
}
@@ -113,21 +295,31 @@ RiscVSupervisorModeTrapHandler (
SMODE_TRAP_REGISTERS *SmodeTrapReg
)
{
- UINTN SCause;
+ EFI_EXCEPTION_TYPE ExceptionType;
EFI_SYSTEM_CONTEXT RiscVSystemContext;
+ UINTN IrqIndex;
RiscVSystemContext.SystemContextRiscV64 = (EFI_SYSTEM_CONTEXT_RISCV64 *)SmodeTrapReg;
- //
- // Check scasue register.
- //
- SCause = (UINTN)RiscVGetSupervisorTrapCause ();
- if ((SCause & (1UL << (sizeof (UINTN) * 8- 1))) != 0) {
- //
- // This is interrupt event.
- //
- SCause &= ~(1UL << (sizeof (UINTN) * 8- 1));
- if ((SCause == IRQ_S_TIMER) && (mInterruptHandlers[EXCEPT_RISCV_TIMER_INT] != NULL)) {
- mInterruptHandlers[EXCEPT_RISCV_TIMER_INT](EXCEPT_RISCV_TIMER_INT, RiscVSystemContext);
+ ExceptionType = (UINTN)RiscVGetSupervisorTrapCause ();
+
+ if (EXCEPT_RISCV_IS_IRQ (ExceptionType)) {
+ IrqIndex = EXCEPT_RISCV_IRQ_INDEX (ExceptionType);
+
+ if ((IrqIndex <= EXCEPT_RISCV_MAX_IRQS) &&
+ (mIrqHandlers[IrqIndex] != NULL))
+ {
+ mIrqHandlers[IrqIndex](ExceptionType, RiscVSystemContext);
+ return;
+ }
+ } else {
+ if ((ExceptionType <= EXCEPT_RISCV_MAX_EXCEPTIONS) &&
+ (mExceptionHandlers[ExceptionType] != 0))
+ {
+ mExceptionHandlers[ExceptionType](ExceptionType, RiscVSystemContext);
+ return;
}
}
+
+ DumpCpuContext (ExceptionType, RiscVSystemContext);
+ CpuDeadLoop ();
}