blob: db949b59bc4714d5c545a2db544041e59be57b18 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/testing/test_framework/ottf_isrs.h"
#include "sw/device/lib/base/csr.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/ibex.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
dif_rv_plic_t ottf_plic;
// Fault reasons from
// https://riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf
static const char *exception_reason[] = {
"Instruction Misaligned",
"Instruction Access",
"Illegal Instruction",
"Breakpoint",
"Load Address Misaligned",
"Load Access Fault",
"Store Address Misaligned",
"Store Access Fault",
"U-mode Ecall",
"S-mode Ecall",
"Reserved",
"M-mode Ecall",
"Instruction Page Fault",
"Load Page Fault",
"Reserved",
"Store Page Fault",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
};
void ottf_generic_fault_print(const char *reason, uint32_t mcause) {
uint32_t mepc = ibex_mepc_read();
uint32_t mtval = ibex_mtval_read();
LOG_ERROR("FAULT: %s. MCAUSE=%08x MEPC=%08x MTVAL=%08x", reason, mcause, mepc,
mtval);
}
static void generic_fault_handler(void) {
uint32_t mcause = ibex_mcause_read();
ottf_generic_fault_print(exception_reason[mcause & kIbexExcMax], mcause);
abort();
}
/**
* The weak `pxCurrentTCB` symbol below enable the OTTF ISRs to be used without
* the OTTF itself. This enables us to maintain one set of default ISRs for
* testing, while also enabling writing tests that do not make use of the OTTF.
* See the `crt_test` in `sw/device/tests/crt_test.c` for an example.
*/
OT_WEAK
void *pxCurrentTCB = NULL;
OT_WEAK
void ottf_exception_handler(void) {
uint32_t mcause = ibex_mcause_read();
switch ((ibex_exc_t)(mcause & kIbexExcMax)) {
case kIbexExcInstrMisaligned:
ottf_instr_misaligned_fault_handler();
break;
case kIbexExcInstrAccessFault:
ottf_instr_access_fault_handler();
break;
case kIbexExcIllegalInstrFault:
ottf_illegal_instr_fault_handler();
break;
case kIbexExcBreakpoint:
ottf_breakpoint_handler();
break;
case kIbexExcLoadAccessFault:
ottf_load_store_fault_handler();
break;
case kIbexExcStoreAccessFault:
ottf_load_store_fault_handler();
break;
case kIbexExcMachineECall:
ottf_machine_ecall_handler();
break;
case kIbexExcUserECall:
ottf_user_ecall_handler();
break;
default:
generic_fault_handler();
}
}
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_instr_misaligned_fault_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_instr_access_fault_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_illegal_instr_fault_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_breakpoint_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_load_store_fault_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_machine_ecall_handler(void);
OT_WEAK
OT_ALIAS("generic_fault_handler")
void ottf_user_ecall_handler(void);
OT_WEAK
void ottf_software_isr(void) {
ottf_generic_fault_print("Software IRQ", ibex_mcause_read());
abort();
}
OT_WEAK
void ottf_timer_isr(void) {
ottf_generic_fault_print("Timer IRQ", ibex_mcause_read());
abort();
}
OT_WEAK
bool ottf_flow_control_isr(void) { return false; }
OT_WEAK
void ottf_external_isr(void) {
const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
dif_rv_plic_irq_id_t plic_irq_id;
CHECK_DIF_OK(dif_rv_plic_irq_claim(&ottf_plic, kPlicTarget, &plic_irq_id));
top_earlgrey_plic_peripheral_t peripheral = (top_earlgrey_plic_peripheral_t)
top_earlgrey_plic_interrupt_for_peripheral[plic_irq_id];
if (peripheral == kTopEarlgreyPlicPeripheralUart0 &&
ottf_flow_control_isr()) {
// Complete the IRQ at PLIC.
CHECK_DIF_OK(
dif_rv_plic_irq_complete(&ottf_plic, kPlicTarget, plic_irq_id));
return;
}
ottf_generic_fault_print("External IRQ", ibex_mcause_read());
abort();
}
static void generic_internal_irq_handler(void) {
ottf_generic_fault_print("Internal IRQ", ibex_mcause_read());
abort();
}
OT_WEAK
OT_ALIAS("generic_internal_irq_handler")
void ottf_external_nmi_handler(void);
OT_WEAK
OT_ALIAS("generic_internal_irq_handler")
void ottf_load_integrity_error_handler(void);
OT_WEAK
void ottf_internal_isr(void) {
uint32_t mcause = ibex_mcause_read();
switch ((ibex_internal_irq_t)(mcause)) {
case kIbexInternalIrqLoadInteg:
ottf_load_integrity_error_handler();
break;
case kIbexInternalIrqNmi:
ottf_external_nmi_handler();
break;
default:
generic_internal_irq_handler();
}
}