mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -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 */
|
/* if no promotion, return original cause */
|
||||||
return orig_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
|
* Handle Traps
|
||||||
*
|
*
|
||||||
|
@ -1977,22 +1995,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
bool nnmi_excep = false;
|
bool nnmi_excep = false;
|
||||||
|
|
||||||
if (cpu->cfg.ext_smrnmi && env->rnmip && async) {
|
if (cpu->cfg.ext_smrnmi && env->rnmip && async) {
|
||||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
|
riscv_do_nmi(env, cause | ((target_ulong)1U << (mxlen - 1)),
|
||||||
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV,
|
env->virt_enabled);
|
||||||
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);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2204,11 +2208,32 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
/* Trapping to M mode, virt is disabled */
|
/* Trapping to M mode, virt is disabled */
|
||||||
virt = false;
|
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 = env->mstatus;
|
||||||
s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
|
s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
|
||||||
s = set_field(s, MSTATUS_MPP, env->priv);
|
s = set_field(s, MSTATUS_MPP, env->priv);
|
||||||
s = set_field(s, MSTATUS_MIE, 0);
|
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->mstatus = s;
|
||||||
env->mcause = cause | ((target_ulong)async << (mxlen - 1));
|
env->mcause = cause | ((target_ulong)async << (mxlen - 1));
|
||||||
if (smode_double_trap) {
|
if (smode_double_trap) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue