__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout UefiCpuPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
		
			
				
	
	
		
			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 ();
 | 
						|
}
 |