Skip to content

Commit 00af7d5

Browse files
clementlegeralistair23
authored andcommitted
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>
1 parent f2efb6e commit 00af7d5

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

target/riscv/cpu_helper.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,24 @@ static target_ulong promote_load_fault(target_ulong orig_cause)
19381938
/* if no promotion, return original cause */
19391939
return orig_cause;
19401940
}
1941+
1942+
static void riscv_do_nmi(CPURISCVState *env, target_ulong cause, bool virt)
1943+
{
1944+
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
1945+
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV, virt);
1946+
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPP, env->priv);
1947+
env->mncause = cause;
1948+
env->mnepc = env->pc;
1949+
env->pc = env->rnmi_irqvec;
1950+
1951+
if (cpu_get_fcfien(env)) {
1952+
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
1953+
}
1954+
1955+
/* Trapping to M mode, virt is disabled */
1956+
riscv_cpu_set_mode(env, PRV_M, false);
1957+
}
1958+
19411959
/*
19421960
* Handle Traps
19431961
*
@@ -1977,22 +1995,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
19771995
bool nnmi_excep = false;
19781996

19791997
if (cpu->cfg.ext_smrnmi && env->rnmip && async) {
1980-
env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, false);
1981-
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPV,
1982-
env->virt_enabled);
1983-
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPP,
1984-
env->priv);
1985-
env->mncause = cause | ((target_ulong)1U << (mxlen - 1));
1986-
env->mnepc = env->pc;
1987-
env->pc = env->rnmi_irqvec;
1988-
1989-
if (cpu_get_fcfien(env)) {
1990-
env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, env->elp);
1991-
}
1992-
1993-
/* Trapping to M mode, virt is disabled */
1994-
riscv_cpu_set_mode(env, PRV_M, false);
1995-
1998+
riscv_do_nmi(env, cause | ((target_ulong)1U << (mxlen - 1)),
1999+
env->virt_enabled);
19962000
return;
19972001
}
19982002

@@ -2204,11 +2208,32 @@ void riscv_cpu_do_interrupt(CPUState *cs)
22042208
/* Trapping to M mode, virt is disabled */
22052209
virt = false;
22062210
}
2211+
/*
2212+
* If the hart encounters an exception while executing in M-mode,
2213+
* with the mnstatus.NMIE bit clear, the program counter is set to
2214+
* the RNMI exception trap handler address.
2215+
*/
2216+
nnmi_excep = cpu->cfg.ext_smrnmi &&
2217+
!get_field(env->mnstatus, MNSTATUS_NMIE) &&
2218+
!async;
22072219

22082220
s = env->mstatus;
22092221
s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
22102222
s = set_field(s, MSTATUS_MPP, env->priv);
22112223
s = set_field(s, MSTATUS_MIE, 0);
2224+
if (cpu->cfg.ext_smdbltrp) {
2225+
if (env->mstatus & MSTATUS_MDT) {
2226+
assert(env->priv == PRV_M);
2227+
if (!cpu->cfg.ext_smrnmi || nnmi_excep) {
2228+
cpu_abort(CPU(cpu), "M-mode double trap\n");
2229+
} else {
2230+
riscv_do_nmi(env, cause, false);
2231+
return;
2232+
}
2233+
}
2234+
2235+
s = set_field(s, MSTATUS_MDT, 1);
2236+
}
22122237
env->mstatus = s;
22132238
env->mcause = cause | ((target_ulong)async << (mxlen - 1));
22142239
if (smode_double_trap) {

0 commit comments

Comments
 (0)