diff mbox series

[v4,8/9] target/riscv: Implement Smdbltrp behavior

Message ID 20241017145226.365825-9-cleger@rivosinc.com
State New
Headers show
Series target/riscv: Add support for Smdbltrp and Ssdbltrp extensions | expand

Commit Message

Clément Léger Oct. 17, 2024, 2:52 p.m. UTC
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>
---
 target/riscv/cpu_helper.c | 52 +++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 18 deletions(-)

Comments

Alistair Francis Oct. 21, 2024, 1:14 a.m. UTC | #1
On Fri, Oct 18, 2024 at 12:54 AM Clément Léger <cleger@rivosinc.com> wrote:
>
> 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>

Alistair

> ---
>  target/riscv/cpu_helper.c | 52 +++++++++++++++++++++++++--------------
>  1 file changed, 34 insertions(+), 18 deletions(-)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 623a3abbf7..8825572d5e 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -1703,6 +1703,17 @@ static target_ulong riscv_transformed_insn(CPURISCVState *env,
>      return xinsn;
>  }
>
> +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;
> +    riscv_cpu_set_mode(env, PRV_M, false);
> +}
> +
>  /*
>   * Handle Traps
>   *
> @@ -1741,15 +1752,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 << (TARGET_LONG_BITS - 1));
> -        env->mnepc = env->pc;
> -        env->pc = env->rnmi_irqvec;
> -        riscv_cpu_set_mode(env, PRV_M, virt);
> +        riscv_do_nmi(env, cause | ((target_ulong)1U << (TARGET_LONG_BITS - 1)),
> +                     virt);
>          return;
>      }
>
> @@ -1932,11 +1936,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;
>          mxlen = 16 << riscv_cpu_mxl(env);
>          env->mcause = cause | ((target_ulong)async << (mxlen - 1));
> @@ -1950,15 +1975,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          env->mtval = tval;
>          env->mtinst = tinst;
>
> -        /*
> -         * 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;
> -
>          if (nnmi_excep) {
>              env->pc = env->rnmi_excpvec;
>          } else {
> --
> 2.45.2
>
>
diff mbox series

Patch

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 623a3abbf7..8825572d5e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1703,6 +1703,17 @@  static target_ulong riscv_transformed_insn(CPURISCVState *env,
     return xinsn;
 }
 
+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;
+    riscv_cpu_set_mode(env, PRV_M, false);
+}
+
 /*
  * Handle Traps
  *
@@ -1741,15 +1752,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 << (TARGET_LONG_BITS - 1));
-        env->mnepc = env->pc;
-        env->pc = env->rnmi_irqvec;
-        riscv_cpu_set_mode(env, PRV_M, virt);
+        riscv_do_nmi(env, cause | ((target_ulong)1U << (TARGET_LONG_BITS - 1)),
+                     virt);
         return;
     }
 
@@ -1932,11 +1936,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;
         mxlen = 16 << riscv_cpu_mxl(env);
         env->mcause = cause | ((target_ulong)async << (mxlen - 1));
@@ -1950,15 +1975,6 @@  void riscv_cpu_do_interrupt(CPUState *cs)
         env->mtval = tval;
         env->mtinst = tinst;
 
-        /*
-         * 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;
-
         if (nnmi_excep) {
             env->pc = env->rnmi_excpvec;
         } else {