diff --git a/MdePkg/Include/Protocol/DebugSupport.h b/MdePkg/Include/Protocol/DebugSupport.h index 2b0ae2d1577b..9742663619c5 100644 --- a/MdePkg/Include/Protocol/DebugSupport.h +++ b/MdePkg/Include/Protocol/DebugSupport.h @@ -613,11 +613,34 @@ typedef struct { #define EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT 7 #define EXCEPT_RISCV_ENV_CALL_FROM_UMODE 8 #define EXCEPT_RISCV_ENV_CALL_FROM_SMODE 9 -#define EXCEPT_RISCV_ENV_CALL_FROM_HMODE 10 +#define EXCEPT_RISCV_ENV_CALL_FROM_VS_MODE 10 #define EXCEPT_RISCV_ENV_CALL_FROM_MMODE 11 - -#define EXCEPT_RISCV_SOFTWARE_INT 0x0 -#define EXCEPT_RISCV_TIMER_INT 0x1 +#define EXCEPT_RISCV_INST_ACCESS_PAGE_FAULT 12 +#define EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT 13 +#define EXCEPT_RISCV_14 14 +#define EXCEPT_RISCV_STORE_ACCESS_PAGE_FAULT 15 +#define EXCEPT_RISCV_16 16 +#define EXCEPT_RISCV_17 17 +#define EXCEPT_RISCV_18 18 +#define EXCEPT_RISCV_19 19 +#define EXCEPT_RISCV_INST_GUEST_PAGE_FAULT 20 +#define EXCEPT_RISCV_LOAD_GUEST_PAGE_FAULT 21 +#define EXCEPT_RISCV_VIRTUAL_INSTRUCTION 22 +#define EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT 23 +#define EXCEPT_RISCV_MAX_EXCEPTIONS (EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT) + +/// +/// RISC-V processor exception types for interrupts. +/// +#define EXCEPT_RISCV_IS_IRQ(x) ((x & 0x8000000000000000UL) != 0) +#define EXCEPT_RISCV_IRQ_INDEX(x) (x & 0x7FFFFFFFFFFFFFFFUL) +#define EXCEPT_RISCV_IRQ_0 0x8000000000000000UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_SMODE 0x8000000000000001UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_VSMODE 0x8000000000000002UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_MMODE 0x8000000000000003UL +#define EXCEPT_RISCV_IRQ_4 0x8000000000000004UL +#define EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE 0x8000000000000005UL +#define EXCEPT_RISCV_MAX_IRQS (EXCEPT_RISCV_IRQ_INDEX(EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE)) typedef struct { UINT64 X0; @@ -652,6 +675,9 @@ typedef struct { UINT64 X29; UINT64 X30; UINT64 X31; + UINT64 SEPC; + UINT32 SSTATUS; + UINT32 STVAL; } EFI_SYSTEM_CONTEXT_RISCV64; // diff --git a/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c b/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c index 287e7e133048..fa957ba5e3e9 100644 --- a/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c +++ b/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c @@ -278,7 +278,11 @@ TimerDriverInitialize ( // // Install interrupt handler for RISC-V Timer. // - Status = mCpu->RegisterInterruptHandler (mCpu, EXCEPT_RISCV_TIMER_INT, TimerInterruptHandler); + Status = mCpu->RegisterInterruptHandler ( + mCpu, + EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE, + TimerInterruptHandler + ); ASSERT_EFI_ERROR (Status); // diff --git a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c index f1ee7d236aec..bce089feb0da 100644 --- a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c +++ b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.c @@ -11,11 +11,168 @@ #include #include #include +#include +#include #include - #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 (); } diff --git a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.h b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.h index 30f47e87552b..9b7e1304dd3b 100644 --- a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.h +++ b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/CpuExceptionHandlerLib.h @@ -59,7 +59,7 @@ SupervisorModeTrap ( #define SMODE_TRAP_REGS_t6 31 #define SMODE_TRAP_REGS_sepc 32 #define SMODE_TRAP_REGS_sstatus 33 -#define SMODE_TRAP_REGS_sie 34 +#define SMODE_TRAP_REGS_stval 34 #define SMODE_TRAP_REGS_last 35 #define SMODE_TRAP_REGS_OFFSET(x) ((SMODE_TRAP_REGS_##x) * __SIZEOF_POINTER__) @@ -68,7 +68,7 @@ SupervisorModeTrap ( #pragma pack(1) typedef struct { // - // Below are follow the format of EFI_SYSTEM_CONTEXT + // Below follow the format of EFI_SYSTEM_CONTEXT. // UINT64 zero; UINT64 ra; @@ -102,14 +102,9 @@ typedef struct { UINT64 t4; UINT64 t5; UINT64 t6; - // - // Below are the additional information to - // EFI_SYSTEM_CONTEXT, private to supervisor mode trap - // and not public to EFI environment. - // UINT64 sepc; UINT64 sstatus; - UINT64 sie; + UINT64 stval; } SMODE_TRAP_REGISTERS; #pragma pack() diff --git a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/SupervisorTrapHandler.S b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/SupervisorTrapHandler.S index 649c4c5becf4..45070b5cda04 100644 --- a/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/SupervisorTrapHandler.S +++ b/UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/SupervisorTrapHandler.S @@ -20,14 +20,14 @@ SupervisorModeTrap: sd t0, SMODE_TRAP_REGS_OFFSET(t0)(sp) csrr t0, CSR_SSTATUS - and t0, t0, (SSTATUS_SIE | SSTATUS_SPIE) sd t0, SMODE_TRAP_REGS_OFFSET(sstatus)(sp) csrr t0, CSR_SEPC sd t0, SMODE_TRAP_REGS_OFFSET(sepc)(sp) - csrr t0, CSR_SIE - sd t0, SMODE_TRAP_REGS_OFFSET(sie)(sp) + csrr t0, CSR_STVAL + sd t0, SMODE_TRAP_REGS_OFFSET(stval)(sp) ld t0, SMODE_TRAP_REGS_OFFSET(t0)(sp) + sd zero, SMODE_TRAP_REGS_OFFSET(zero)(sp) sd ra, SMODE_TRAP_REGS_OFFSET(ra)(sp) sd gp, SMODE_TRAP_REGS_OFFSET(gp)(sp) sd tp, SMODE_TRAP_REGS_OFFSET(tp)(sp) @@ -59,6 +59,7 @@ SupervisorModeTrap: sd t6, SMODE_TRAP_REGS_OFFSET(t6)(sp) /* Call to Supervisor mode trap handler in CpuExceptionHandlerLib.c */ + mv a0, sp call RiscVSupervisorModeTrapHandler /* Restore all general regisers except SP */ @@ -66,6 +67,7 @@ SupervisorModeTrap: ld gp, SMODE_TRAP_REGS_OFFSET(gp)(sp) ld tp, SMODE_TRAP_REGS_OFFSET(tp)(sp) ld t2, SMODE_TRAP_REGS_OFFSET(t2)(sp) + ld t1, SMODE_TRAP_REGS_OFFSET(t1)(sp) ld s0, SMODE_TRAP_REGS_OFFSET(s0)(sp) ld s1, SMODE_TRAP_REGS_OFFSET(s1)(sp) ld a0, SMODE_TRAP_REGS_OFFSET(a0)(sp) @@ -93,13 +95,10 @@ SupervisorModeTrap: ld t0, SMODE_TRAP_REGS_OFFSET(sepc)(sp) csrw CSR_SEPC, t0 - ld t0, SMODE_TRAP_REGS_OFFSET(sie)(sp) - csrw CSR_SIE, t0 - csrr t0, CSR_SSTATUS - ld t1, SMODE_TRAP_REGS_OFFSET(sstatus)(sp) - or t0, t0, t1 + ld t0, SMODE_TRAP_REGS_OFFSET(sstatus)(sp) csrw CSR_SSTATUS, t0 - ld t1, SMODE_TRAP_REGS_OFFSET(t1)(sp) + ld t0, SMODE_TRAP_REGS_OFFSET(stval)(sp) + csrw CSR_STVAL, t0 ld t0, SMODE_TRAP_REGS_OFFSET(t0)(sp) addi sp, sp, SMODE_TRAP_REGS_SIZE sret