mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
target/riscv: Implement Smdbltrp behavior
When the Smsdbltrp ISA extension is enabled, if a trap happens while MSTATUS.MDT is already set, it will trigger an abort or an NMI is the Smrnmi extension is available. Signed-off-by: Clément Léger <cleger@rivosinc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250110125441.3208676-9-cleger@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
f2efb6e793
commit
00af7d5360
1 changed files with 41 additions and 16 deletions
|
@ -1938,6 +1938,24 @@ static target_ulong promote_load_fault(target_ulong orig_cause)
|
|||
/* if no promotion, return original cause */
|
||||
return orig_cause;
|
||||
}
|
||||
|
||||
static void riscv_do_nmi(CPURISCVState *env, target_ulong cause, bool virt)
|
||||
{
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV, virt);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPP, env->priv);
|
||||
env->mncause = cause;
|
||||
env->mnepc = env->pc;
|
||||
env->pc = env->rnmi_irqvec;
|
||||
|
||||
if (cpu_get_fcfien(env)) {
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
|
||||
}
|
||||
|
||||
/* Trapping to M mode, virt is disabled */
|
||||
riscv_cpu_set_mode(env, PRV_M, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle Traps
|
||||
*
|
||||
|
@ -1977,22 +1995,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
bool nnmi_excep = false;
|
||||
|
||||
if (cpu->cfg.ext_smrnmi && env->rnmip && async) {
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV,
|
||||
env->virt_enabled);
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPP,
|
||||
env->priv);
|
||||
env->mncause = cause | ((target_ulong)1U << (mxlen - 1));
|
||||
env->mnepc = env->pc;
|
||||
env->pc = env->rnmi_irqvec;
|
||||
|
||||
if (cpu_get_fcfien(env)) {
|
||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
|
||||
}
|
||||
|
||||
/* Trapping to M mode, virt is disabled */
|
||||
riscv_cpu_set_mode(env, PRV_M, false);
|
||||
|
||||
riscv_do_nmi(env, cause | ((target_ulong)1U << (mxlen - 1)),
|
||||
env->virt_enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2204,11 +2208,32 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
/* Trapping to M mode, virt is disabled */
|
||||
virt = false;
|
||||
}
|
||||
/*
|
||||
* If the hart encounters an exception while executing in M-mode,
|
||||
* with the mnstatus.NMIE bit clear, the program counter is set to
|
||||
* the RNMI exception trap handler address.
|
||||
*/
|
||||
nnmi_excep = cpu->cfg.ext_smrnmi &&
|
||||
!get_field(env->mnstatus, MNSTATUS_NMIE) &&
|
||||
!async;
|
||||
|
||||
s = env->mstatus;
|
||||
s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
|
||||
s = set_field(s, MSTATUS_MPP, env->priv);
|
||||
s = set_field(s, MSTATUS_MIE, 0);
|
||||
if (cpu->cfg.ext_smdbltrp) {
|
||||
if (env->mstatus & MSTATUS_MDT) {
|
||||
assert(env->priv == PRV_M);
|
||||
if (!cpu->cfg.ext_smrnmi || nnmi_excep) {
|
||||
cpu_abort(CPU(cpu), "M-mode double trap\n");
|
||||
} else {
|
||||
riscv_do_nmi(env, cause, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
s = set_field(s, MSTATUS_MDT, 1);
|
||||
}
|
||||
env->mstatus = s;
|
||||
env->mcause = cause | ((target_ulong)async << (mxlen - 1));
|
||||
if (smode_double_trap) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue