mirror of https://github.com/acidanthera/audk.git
326 lines
10 KiB
C
326 lines
10 KiB
C
/** @file
|
|
RISC-V Exception Handler library implementation.
|
|
|
|
Copyright (c) 2016 - 2022, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <PiPei.h>
|
|
#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"
|
|
|
|
//
|
|
// 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.
|
|
|
|
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
|
|
)
|
|
{
|
|
RiscVSetSupervisorStvec ((UINT64)SupervisorModeTrap);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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 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] 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 ExceptionType was
|
|
previously installed.
|
|
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for ExceptionType was not
|
|
previously installed.
|
|
@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 ExceptionType,
|
|
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "%a: Type:%x Handler: %x\n", __func__, 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;
|
|
}
|
|
|
|
/**
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Supervisor mode trap handler.
|
|
|
|
@param[in] SmodeTrapReg Registers before trap occurred.
|
|
|
|
**/
|
|
VOID
|
|
RiscVSupervisorModeTrapHandler (
|
|
SMODE_TRAP_REGISTERS *SmodeTrapReg
|
|
)
|
|
{
|
|
EFI_EXCEPTION_TYPE ExceptionType;
|
|
EFI_SYSTEM_CONTEXT RiscVSystemContext;
|
|
UINTN IrqIndex;
|
|
|
|
RiscVSystemContext.SystemContextRiscV64 = (EFI_SYSTEM_CONTEXT_RISCV64 *)SmodeTrapReg;
|
|
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 ();
|
|
}
|