|
@@ -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 ();
|
|
|
}
|