mirror of
https://github.com/Fishwaldo/opensbi.git
synced 2025-03-15 19:31:32 +00:00
lib: Redirect illegal instruction trap to S-mode when not handled
Currently, we fail with error SBI_ENOTSUPP when we are not able to handle illegal instruction trap. Instead, we should just redirect illegal instruction trap to S-mode when not handled. This redirection of illegal instruction trap will help lazy save/restore of floating point registers to work correctly in Linux kernel. Signed-off-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
parent
56e41f7a8d
commit
5959312a5c
4 changed files with 56 additions and 6 deletions
|
@ -19,12 +19,15 @@
|
|||
#define MSTATUS_HIE 0x00000004
|
||||
#define MSTATUS_MIE 0x00000008
|
||||
#define MSTATUS_UPIE 0x00000010
|
||||
#define MSTATUS_SPIE 0x00000020
|
||||
#define MSTATUS_SPIE_SHIFT 5
|
||||
#define MSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
|
||||
#define MSTATUS_HPIE 0x00000040
|
||||
#define MSTATUS_MPIE 0x00000080
|
||||
#define MSTATUS_SPP 0x00000100
|
||||
#define MSTATUS_SPP_SHIFT 8
|
||||
#define MSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
|
||||
#define MSTATUS_HPP 0x00000600
|
||||
#define MSTATUS_MPP 0x00001800
|
||||
#define MSTATUS_MPP_SHIFT 11
|
||||
#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT)
|
||||
#define MSTATUS_FS 0x00006000
|
||||
#define MSTATUS_XS 0x00018000
|
||||
#define MSTATUS_MPRV 0x00020000
|
||||
|
|
|
@ -51,6 +51,10 @@ struct sbi_trap_regs {
|
|||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch,
|
||||
ulong epc, ulong cause, ulong tval);
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@ static int truly_illegal_insn(ulong insn,
|
|||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
/* For now, always fails */
|
||||
return SBI_ENOTSUPP;
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
|
||||
}
|
||||
|
||||
static int system_opcode_insn(ulong insn,
|
||||
|
@ -132,7 +131,8 @@ int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
|
|||
insn = get_insn(regs->mepc, &mstatus);
|
||||
}
|
||||
if ((insn & 3) != 3)
|
||||
return SBI_ENOTSUPP;
|
||||
return truly_illegal_insn(insn, hartid, mcause,
|
||||
regs, scratch);
|
||||
}
|
||||
|
||||
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
|
||||
|
|
|
@ -66,6 +66,49 @@ static void __attribute__((noreturn)) sbi_trap_error(const char *msg,
|
|||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch,
|
||||
ulong epc, ulong cause, ulong tval)
|
||||
{
|
||||
ulong new_mstatus, prev_mode;
|
||||
|
||||
/* Sanity check on previous mode */
|
||||
prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* Update S-mode exception info */
|
||||
csr_write(stval, tval);
|
||||
csr_write(sepc, epc);
|
||||
csr_write(scause, cause);
|
||||
|
||||
/* Set MEPC to S-mode exception vector base */
|
||||
regs->mepc = csr_read(stvec);
|
||||
|
||||
/* Initial value of new MSTATUS */
|
||||
new_mstatus = regs->mstatus;
|
||||
|
||||
/* Clear MPP, SPP, SPIE, and SIE */
|
||||
new_mstatus &= ~(MSTATUS_MPP |
|
||||
MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
|
||||
|
||||
/* Set SPP */
|
||||
if (prev_mode == PRV_S)
|
||||
new_mstatus |= (1UL << MSTATUS_SPP_SHIFT);
|
||||
|
||||
/* Set SPIE */
|
||||
if (regs->mstatus & MSTATUS_SIE)
|
||||
new_mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
|
||||
|
||||
/* Set MPP */
|
||||
new_mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
|
||||
|
||||
/* Set new value in MSTATUS */
|
||||
regs->mstatus = new_mstatus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue