mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
lib: sbi: Introduce trap context
Club the struct sbi_trap_regs and struct sbi_trap_info a new struct sbi_trap_context (aka trap context) which must be saved by low-level trap handler before calling sbi_trap_handler(). To track nested traps, the struct sbi_scratch points to the current trap context and the trap context has pointer to pervious context of previous trap. Signed-off-by: Anup Patel <apatel@ventanamicro.com> Reviewed-by: Samuel Holland <samuel.holland@sifive.com> Tested-by: Samuel Holland <samuel.holland@sifive.com>
This commit is contained in:
@@ -446,14 +446,12 @@ _start_warm:
|
|||||||
|
|
||||||
/* Setup trap handler */
|
/* Setup trap handler */
|
||||||
lla a4, _trap_handler
|
lla a4, _trap_handler
|
||||||
#if __riscv_xlen == 32
|
|
||||||
csrr a5, CSR_MISA
|
csrr a5, CSR_MISA
|
||||||
srli a5, a5, ('H' - 'A')
|
srli a5, a5, ('H' - 'A')
|
||||||
andi a5, a5, 0x1
|
andi a5, a5, 0x1
|
||||||
beq a5, zero, _skip_trap_handler_rv32_hyp
|
beq a5, zero, _skip_trap_handler_hyp
|
||||||
lla a4, _trap_handler_rv32_hyp
|
lla a4, _trap_handler_hyp
|
||||||
_skip_trap_handler_rv32_hyp:
|
_skip_trap_handler_hyp:
|
||||||
#endif
|
|
||||||
csrw CSR_MTVEC, a4
|
csrw CSR_MTVEC, a4
|
||||||
|
|
||||||
/* Initialize SBI runtime */
|
/* Initialize SBI runtime */
|
||||||
@@ -564,10 +562,10 @@ memcmp:
|
|||||||
xor t0, tp, t0
|
xor t0, tp, t0
|
||||||
|
|
||||||
/* Save original SP on exception stack */
|
/* Save original SP on exception stack */
|
||||||
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
|
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_CONTEXT_SIZE)(t0)
|
||||||
|
|
||||||
/* Set SP to exception stack and make room for trap registers */
|
/* Set SP to exception stack and make room for trap context */
|
||||||
add sp, t0, -(SBI_TRAP_REGS_SIZE)
|
add sp, t0, -(SBI_TRAP_CONTEXT_SIZE)
|
||||||
|
|
||||||
/* Restore T0 from scratch space */
|
/* Restore T0 from scratch space */
|
||||||
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||||
@@ -627,6 +625,32 @@ memcmp:
|
|||||||
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro TRAP_SAVE_INFO have_mstatush have_h_extension
|
||||||
|
csrr t0, CSR_MCAUSE
|
||||||
|
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(cause))(sp)
|
||||||
|
csrr t0, CSR_MTVAL
|
||||||
|
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval))(sp)
|
||||||
|
.if \have_h_extension
|
||||||
|
csrr t0, CSR_MTVAL2
|
||||||
|
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval2))(sp)
|
||||||
|
csrr t0, CSR_MTINST
|
||||||
|
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tinst))(sp)
|
||||||
|
.if \have_mstatush
|
||||||
|
csrr t0, CSR_MSTATUSH
|
||||||
|
srli t0, t0, MSTATUSH_GVA_SHIFT
|
||||||
|
.else
|
||||||
|
csrr t0, CSR_MSTATUS
|
||||||
|
srli t0, t0, MSTATUS_GVA_SHIFT
|
||||||
|
.endif
|
||||||
|
and t0, t0, 0x1
|
||||||
|
.else
|
||||||
|
REG_S zero, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval2))(sp)
|
||||||
|
REG_S zero, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tinst))(sp)
|
||||||
|
li t0, 0
|
||||||
|
.endif
|
||||||
|
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(gva))(sp)
|
||||||
|
.endm
|
||||||
|
|
||||||
.macro TRAP_CALL_C_ROUTINE
|
.macro TRAP_CALL_C_ROUTINE
|
||||||
/* Call C routine */
|
/* Call C routine */
|
||||||
add a0, sp, zero
|
add a0, sp, zero
|
||||||
@@ -696,6 +720,8 @@ _trap_handler:
|
|||||||
|
|
||||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||||
|
|
||||||
|
TRAP_SAVE_INFO 0 0
|
||||||
|
|
||||||
TRAP_CALL_C_ROUTINE
|
TRAP_CALL_C_ROUTINE
|
||||||
|
|
||||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||||
@@ -706,27 +732,39 @@ _trap_handler:
|
|||||||
|
|
||||||
mret
|
mret
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.align 3
|
.align 3
|
||||||
.globl _trap_handler_rv32_hyp
|
.globl _trap_handler_hyp
|
||||||
_trap_handler_rv32_hyp:
|
_trap_handler_hyp:
|
||||||
TRAP_SAVE_AND_SETUP_SP_T0
|
TRAP_SAVE_AND_SETUP_SP_T0
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
TRAP_SAVE_MEPC_MSTATUS 1
|
TRAP_SAVE_MEPC_MSTATUS 1
|
||||||
|
#else
|
||||||
|
TRAP_SAVE_MEPC_MSTATUS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
TRAP_SAVE_INFO 1 1
|
||||||
|
#else
|
||||||
|
TRAP_SAVE_INFO 0 1
|
||||||
|
#endif
|
||||||
|
|
||||||
TRAP_CALL_C_ROUTINE
|
TRAP_CALL_C_ROUTINE
|
||||||
|
|
||||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||||
|
#else
|
||||||
|
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
TRAP_RESTORE_A0_T0
|
TRAP_RESTORE_A0_T0
|
||||||
|
|
||||||
mret
|
mret
|
||||||
#endif
|
|
||||||
|
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.align 3
|
.align 3
|
||||||
|
@@ -112,9 +112,15 @@
|
|||||||
/** Size (in bytes) of sbi_trap_info */
|
/** Size (in bytes) of sbi_trap_info */
|
||||||
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
||||||
|
|
||||||
|
/** Size (in bytes) of sbi_trap_context */
|
||||||
|
#define SBI_TRAP_CONTEXT_SIZE (SBI_TRAP_REGS_SIZE + \
|
||||||
|
SBI_TRAP_INFO_SIZE + \
|
||||||
|
__SIZEOF_POINTER__)
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
|
||||||
/** Representation of register state at time of trap/interrupt */
|
/** Representation of register state at time of trap/interrupt */
|
||||||
struct sbi_trap_regs {
|
struct sbi_trap_regs {
|
||||||
@@ -204,6 +210,16 @@ struct sbi_trap_info {
|
|||||||
unsigned long gva;
|
unsigned long gva;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Representation of trap context saved on stack */
|
||||||
|
struct sbi_trap_context {
|
||||||
|
/** Register state */
|
||||||
|
struct sbi_trap_regs regs;
|
||||||
|
/** Trap details */
|
||||||
|
struct sbi_trap_info trap;
|
||||||
|
/** Pointer to previous trap context */
|
||||||
|
struct sbi_trap_context *prev_context;
|
||||||
|
};
|
||||||
|
|
||||||
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -223,7 +239,18 @@ static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
|||||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||||
const struct sbi_trap_info *trap);
|
const struct sbi_trap_info *trap);
|
||||||
|
|
||||||
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
|
static inline struct sbi_trap_context *sbi_trap_get_context(struct sbi_scratch *scratch)
|
||||||
|
{
|
||||||
|
return (scratch) ? (void *)scratch->trap_context : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sbi_trap_set_context(struct sbi_scratch *scratch,
|
||||||
|
struct sbi_trap_context *tcntx)
|
||||||
|
{
|
||||||
|
scratch->trap_context = (unsigned long)tcntx;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -24,18 +24,18 @@
|
|||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
static void __noreturn sbi_trap_error(const char *msg, int rc,
|
static void __noreturn sbi_trap_error(const char *msg, int rc,
|
||||||
ulong mcause, ulong mtval, ulong mtval2,
|
const struct sbi_trap_info *trap,
|
||||||
ulong mtinst, struct sbi_trap_regs *regs)
|
const struct sbi_trap_regs *regs)
|
||||||
{
|
{
|
||||||
u32 hartid = current_hartid();
|
u32 hartid = current_hartid();
|
||||||
|
|
||||||
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
|
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
|
||||||
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
|
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
|
||||||
__func__, hartid, mcause, mtval);
|
__func__, hartid, trap->cause, trap->tval);
|
||||||
if (misa_extension('H')) {
|
if (misa_extension('H')) {
|
||||||
sbi_printf("%s: hart%d: mtval2=0x%" PRILX
|
sbi_printf("%s: hart%d: mtval2=0x%" PRILX
|
||||||
" mtinst=0x%" PRILX "\n",
|
" mtinst=0x%" PRILX "\n",
|
||||||
__func__, hartid, mtval2, mtinst);
|
__func__, hartid, trap->tval2, trap->tinst);
|
||||||
}
|
}
|
||||||
sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
|
sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
|
||||||
__func__, hartid, regs->mepc, regs->mstatus);
|
__func__, hartid, regs->mepc, regs->mstatus);
|
||||||
@@ -258,20 +258,20 @@ static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
|
|||||||
* 6. Stack pointer (SP) is setup for current HART
|
* 6. Stack pointer (SP) is setup for current HART
|
||||||
* 7. Interrupts are disabled in MSTATUS CSR
|
* 7. Interrupts are disabled in MSTATUS CSR
|
||||||
*
|
*
|
||||||
* @param regs pointer to register state
|
* @param tcntx pointer to trap context
|
||||||
*/
|
*/
|
||||||
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
|
||||||
{
|
{
|
||||||
int rc = SBI_ENOTSUPP;
|
int rc = SBI_ENOTSUPP;
|
||||||
const char *msg = "trap handler failed";
|
const char *msg = "trap handler failed";
|
||||||
ulong mcause = csr_read(CSR_MCAUSE);
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
ulong mtval = csr_read(CSR_MTVAL), mtval2 = 0, mtinst = 0;
|
const struct sbi_trap_info *trap = &tcntx->trap;
|
||||||
struct sbi_trap_info trap;
|
struct sbi_trap_regs *regs = &tcntx->regs;
|
||||||
|
ulong mcause = tcntx->trap.cause;
|
||||||
|
|
||||||
if (misa_extension('H')) {
|
/* Update trap context pointer */
|
||||||
mtval2 = csr_read(CSR_MTVAL2);
|
tcntx->prev_context = sbi_trap_get_context(scratch);
|
||||||
mtinst = csr_read(CSR_MTINST);
|
sbi_trap_set_context(scratch, tcntx);
|
||||||
}
|
|
||||||
|
|
||||||
if (mcause & (1UL << (__riscv_xlen - 1))) {
|
if (mcause & (1UL << (__riscv_xlen - 1))) {
|
||||||
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
|
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
|
||||||
@@ -279,32 +279,23 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
|||||||
rc = sbi_trap_aia_irq(regs, mcause);
|
rc = sbi_trap_aia_irq(regs, mcause);
|
||||||
else
|
else
|
||||||
rc = sbi_trap_nonaia_irq(regs, mcause);
|
rc = sbi_trap_nonaia_irq(regs, mcause);
|
||||||
if (rc) {
|
msg = "unhandled local interrupt";
|
||||||
msg = "unhandled local interrupt";
|
goto trap_done;
|
||||||
goto trap_error;
|
|
||||||
}
|
|
||||||
return regs;
|
|
||||||
}
|
}
|
||||||
/* Original trap_info */
|
|
||||||
trap.cause = mcause;
|
|
||||||
trap.tval = mtval;
|
|
||||||
trap.tval2 = mtval2;
|
|
||||||
trap.tinst = mtinst;
|
|
||||||
trap.gva = sbi_regs_gva(regs);
|
|
||||||
|
|
||||||
switch (mcause) {
|
switch (mcause) {
|
||||||
case CAUSE_ILLEGAL_INSTRUCTION:
|
case CAUSE_ILLEGAL_INSTRUCTION:
|
||||||
rc = sbi_illegal_insn_handler(mtval, regs);
|
rc = sbi_illegal_insn_handler(tcntx->trap.tval, regs);
|
||||||
msg = "illegal instruction handler failed";
|
msg = "illegal instruction handler failed";
|
||||||
break;
|
break;
|
||||||
case CAUSE_MISALIGNED_LOAD:
|
case CAUSE_MISALIGNED_LOAD:
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_LOAD);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_LOAD);
|
||||||
rc = sbi_misaligned_load_handler(regs, &trap);
|
rc = sbi_misaligned_load_handler(regs, trap);
|
||||||
msg = "misaligned load handler failed";
|
msg = "misaligned load handler failed";
|
||||||
break;
|
break;
|
||||||
case CAUSE_MISALIGNED_STORE:
|
case CAUSE_MISALIGNED_STORE:
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_STORE);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_STORE);
|
||||||
rc = sbi_misaligned_store_handler(regs, &trap);
|
rc = sbi_misaligned_store_handler(regs, trap);
|
||||||
msg = "misaligned store handler failed";
|
msg = "misaligned store handler failed";
|
||||||
break;
|
break;
|
||||||
case CAUSE_SUPERVISOR_ECALL:
|
case CAUSE_SUPERVISOR_ECALL:
|
||||||
@@ -314,23 +305,24 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
|||||||
break;
|
break;
|
||||||
case CAUSE_LOAD_ACCESS:
|
case CAUSE_LOAD_ACCESS:
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_LOAD);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_LOAD);
|
||||||
rc = sbi_load_access_handler(regs, &trap);
|
rc = sbi_load_access_handler(regs, trap);
|
||||||
msg = "load fault handler failed";
|
msg = "load fault handler failed";
|
||||||
break;
|
break;
|
||||||
case CAUSE_STORE_ACCESS:
|
case CAUSE_STORE_ACCESS:
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_STORE);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_STORE);
|
||||||
rc = sbi_store_access_handler(regs, &trap);
|
rc = sbi_store_access_handler(regs, trap);
|
||||||
msg = "store fault handler failed";
|
msg = "store fault handler failed";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* If the trap came from S or U mode, redirect it there */
|
/* If the trap came from S or U mode, redirect it there */
|
||||||
msg = "trap redirect failed";
|
msg = "trap redirect failed";
|
||||||
rc = sbi_trap_redirect(regs, &trap);
|
rc = sbi_trap_redirect(regs, trap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
trap_error:
|
trap_done:
|
||||||
if (rc)
|
if (rc)
|
||||||
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
|
sbi_trap_error(msg, rc, trap, regs);
|
||||||
return regs;
|
sbi_trap_set_context(scratch, tcntx->prev_context);
|
||||||
|
return tcntx;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user