Message ID | 20241217062440.884261-7-frank.chang@sifive.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Add Smrnmi support | expand |
On 12/17/24 3:24 AM, frank.chang@sifive.com wrote: > From: Frank Chang <frank.chang@sifive.com> > > Zicfilp extension introduces the MNPELP (bit 9) in mnstatus. > The MNPELP field holds the previous ELP. > > When a RNMI trap is delivered, the MNPELP is set to ELP and ELP set > to NO_LP_EXPECTED. Upon a mnret, if the mnstatus.MNPP holds the > value y, then ELP is set to the value of MNPELP if yLPE is 1; > otherwise, it is set to NO_LP_EXPECTED. > > Signed-off-by: Frank Chang <frank.chang@sifive.com> > --- Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> > target/riscv/cpu_bits.h | 1 + > target/riscv/cpu_helper.c | 11 ++++++++++- > target/riscv/op_helper.c | 9 +++++++++ > 3 files changed, 20 insertions(+), 1 deletion(-) > > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h > index 17787fd693..be9d0f5c05 100644 > --- a/target/riscv/cpu_bits.h > +++ b/target/riscv/cpu_bits.h > @@ -643,6 +643,7 @@ typedef enum { > /* RNMI mnstatus CSR mask */ > #define MNSTATUS_NMIE 0x00000008 > #define MNSTATUS_MNPV 0x00000080 > +#define MNSTATUS_MNPELP 0x00000200 > #define MNSTATUS_MNPP 0x00001800 > > /* VM modes (satp.mode) privileged ISA 1.10 */ > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index e5ffbbbd83..1fb1e31031 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -1918,6 +1918,10 @@ void riscv_cpu_do_interrupt(CPUState *cs) > 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); > > @@ -2085,7 +2089,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) > /* handle the trap in M-mode */ > /* save elp status */ > if (cpu_get_fcfien(env)) { > - env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp); > + if (nnmi_excep) { > + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, > + env->elp); > + } else { > + env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp); > + } > } > > if (riscv_has_ext(env, RVH)) { > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c > index 63ec53e992..a4b625fcd9 100644 > --- a/target/riscv/op_helper.c > +++ b/target/riscv/op_helper.c > @@ -402,6 +402,15 @@ target_ulong helper_mnret(CPURISCVState *env) > > riscv_cpu_set_mode(env, prev_priv, prev_virt); > > + /* > + * If forward cfi enabled for new priv, restore elp status > + * and clear mnpelp in mnstatus > + */ > + if (cpu_get_fcfien(env)) { > + env->elp = get_field(env->mnstatus, MNSTATUS_MNPELP); > + } > + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, 0); > + > return retpc; > } >
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 17787fd693..be9d0f5c05 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -643,6 +643,7 @@ typedef enum { /* RNMI mnstatus CSR mask */ #define MNSTATUS_NMIE 0x00000008 #define MNSTATUS_MNPV 0x00000080 +#define MNSTATUS_MNPELP 0x00000200 #define MNSTATUS_MNPP 0x00001800 /* VM modes (satp.mode) privileged ISA 1.10 */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index e5ffbbbd83..1fb1e31031 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1918,6 +1918,10 @@ void riscv_cpu_do_interrupt(CPUState *cs) 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); @@ -2085,7 +2089,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* handle the trap in M-mode */ /* save elp status */ if (cpu_get_fcfien(env)) { - env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp); + if (nnmi_excep) { + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, + env->elp); + } else { + env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp); + } } if (riscv_has_ext(env, RVH)) { diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 63ec53e992..a4b625fcd9 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -402,6 +402,15 @@ target_ulong helper_mnret(CPURISCVState *env) riscv_cpu_set_mode(env, prev_priv, prev_virt); + /* + * If forward cfi enabled for new priv, restore elp status + * and clear mnpelp in mnstatus + */ + if (cpu_get_fcfien(env)) { + env->elp = get_field(env->mnstatus, MNSTATUS_MNPELP); + } + env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP, 0); + return retpc; }