diff options
author | Clément Léger <cleger@rivosinc.com> | 2025-01-10 13:54:39 +0100 |
---|---|---|
committer | Alistair Francis <alistair.francis@wdc.com> | 2025-01-19 09:44:35 +1000 |
commit | 00af7d53601b70f1353dabd1c87ffa260aafd27e (patch) | |
tree | 854053ae0f2637336647dde46d699175a7c8030c | |
parent | f2efb6e793094425ca0b9ee6bafafd7e11eaa666 (diff) | |
download | qemu-00af7d53601b70f1353dabd1c87ffa260aafd27e.zip qemu-00af7d53601b70f1353dabd1c87ffa260aafd27e.tar.gz qemu-00af7d53601b70f1353dabd1c87ffa260aafd27e.tar.bz2 |
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>
-rw-r--r-- | target/riscv/cpu_helper.c | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 539ba32..e1dfc4e 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -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) { |