diff mbox series

[RFC,3/3] target/riscv: add Smdbltrp extension support

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

Commit Message

Clément Léger April 18, 2024, 1:39 p.m. UTC
The Smdbltrp extension allows to generate M-mode targeted double trap
exceptions [1]. Such exceptions are generated if a trap is taken while
mstatus.sdt is set to 1. The specification states that if the Smnrmi
extension is implemented, then the hart enters a critical-error state
and generate a critical-error signal. Since there is no Smrnmi support,
the implementation generates a cpu abort.

Link: https://github.com/riscv/riscv-double-trap/releases/download/v0.56/riscv-double-trap.pdf [1]
Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 target/riscv/cpu.c        |  5 +++++
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_cfg.h    |  1 +
 target/riscv/cpu_helper.c |  6 ++++++
 target/riscv/csr.c        | 12 ++++++++++++
 target/riscv/op_helper.c  |  3 +++
 6 files changed, 28 insertions(+)

Comments

Tommy Wu Aug. 27, 2024, 5:52 a.m. UTC | #1
On Thu, Apr 18, 2024 at 9:40 PM Clément Léger <cleger@rivosinc.com> wrote:
>
> The Smdbltrp extension allows to generate M-mode targeted double trap
> exceptions [1]. Such exceptions are generated if a trap is taken while
> mstatus.sdt is set to 1. The specification states that if the Smnrmi
> extension is implemented, then the hart enters a critical-error state
> and generate a critical-error signal. Since there is no Smrnmi support,
> the implementation generates a cpu abort.
>
> Link: https://github.com/riscv/riscv-double-trap/releases/download/v0.56/riscv-double-trap.pdf [1]
> Signed-off-by: Clément Léger <cleger@rivosinc.com>
> ---
>  target/riscv/cpu.c        |  5 +++++
>  target/riscv/cpu_bits.h   |  1 +
>  target/riscv/cpu_cfg.h    |  1 +
>  target/riscv/cpu_helper.c |  6 ++++++
>  target/riscv/csr.c        | 12 ++++++++++++
>  target/riscv/op_helper.c  |  3 +++
>  6 files changed, 28 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index d159b0c6b6..98f04ecb8c 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -176,6 +176,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>      ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>      ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
>      ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
> +    ISA_EXT_DATA_ENTRY(smdbltrp, PRIV_VERSION_1_12_0, ext_smdbltrp),
>      ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
>      ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
>      ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
> @@ -954,6 +955,9 @@ static void riscv_cpu_reset_hold(Object *obj)
>              env->mstatus_hs = set_field(env->mstatus_hs,
>                                          MSTATUS64_UXL, env->misa_mxl);
>          }
> +        if (riscv_cpu_cfg(env)->ext_smdbltrp) {
> +            env->mstatus = set_field(env->mstatus, MSTATUS_MDT, 1);
> +        }
>      }
>      env->mcause = 0;
>      env->miclaim = MIP_SGEIP;
> @@ -1574,6 +1578,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = {
>  /* These are experimental so mark with 'x-' */
>  const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = {
>      MULTI_EXT_CFG_BOOL("x-ssdbltrp", ext_ssdbltrp, false),
> +    MULTI_EXT_CFG_BOOL("x-smdbltrp", ext_smdbltrp, false),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 494a036f6e..660f2eed5b 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -545,6 +545,7 @@
>  #define MSTATUS_SDT         0x01000000 /* Ssdbltrp extension */
>  #define MSTATUS_GVA         0x4000000000ULL
>  #define MSTATUS_MPV         0x8000000000ULL
> +#define MSTATUS_MDT         0x200000000000ULL /* Smdbltrp extension */

The M-mode-disable-trap (MDT) bit is at bit 42.

Regards,
Tommy Wu

>
>  #define MSTATUS64_UXL       0x0000000300000000ULL
>  #define MSTATUS64_SXL       0x0000000C00000000ULL
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index a149c08167..cf6a802502 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -75,6 +75,7 @@ struct RISCVCPUConfig {
>      bool ext_smstateen;
>      bool ext_sstc;
>      bool ext_ssdbltrp;
> +    bool ext_smdbltrp;
>      bool ext_svadu;
>      bool ext_svinval;
>      bool ext_svnapot;
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 3d747e5bfc..5ce0982f2f 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -1862,6 +1862,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          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 (riscv_cpu_cfg(env)->ext_smdbltrp) {
> +            if (env->mstatus & MSTATUS_MDT)
> +                cpu_abort(CPU(cpu), "M-mode double trap\n");
> +
> +            s = set_field(s, MSTATUS_MDT, 1);
> +        }
>          env->mstatus = s;
>          env->mcause = cause | ~(((target_ulong)-1) >> async);
>          if (smode_double_trap) {
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 1a2e739947..200b06e320 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -1363,6 +1363,7 @@ static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp,
>  static RISCVException write_mstatus(CPURISCVState *env, int csrno,
>                                      target_ulong val)
>  {
> +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
>      uint64_t mstatus = env->mstatus;
>      uint64_t mask = 0;
>      RISCVMXL xl = riscv_cpu_mxl(env);
> @@ -1396,6 +1397,12 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
>          }
>      }
>
> +    if (cfg->ext_smdbltrp) {
> +        mask |= MSTATUS_MDT;
> +        if ((val & MSTATUS_MDT) != 0)
> +            mask &= ~MSTATUS_MIE;
> +    }
> +
>      if (xl != MXL_RV32 || env->debugger) {
>          if (riscv_has_ext(env, RVH)) {
>              mask |= MSTATUS_MPV | MSTATUS_GVA;
> @@ -1434,6 +1441,11 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno,
>      uint64_t valh = (uint64_t)val << 32;
>      uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0;
>
> +    if (riscv_cpu_cfg(env)->ext_smdbltrp) {
> +        mask |= MSTATUS_MDT;
> +        if ((val & MSTATUS_MDT) != 0)
> +            mask |= MSTATUS_MIE;
> +    }
>      env->mstatus = (env->mstatus & ~mask) | (valh & mask);
>
>      return RISCV_EXCP_NONE;
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 468ee58a00..d289d14237 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -354,6 +354,9 @@ target_ulong helper_mret(CPURISCVState *env)
>      mstatus = set_field(mstatus, MSTATUS_MPP,
>                          riscv_has_ext(env, RVU) ? PRV_U : PRV_M);
>      mstatus = set_field(mstatus, MSTATUS_MPV, 0);
> +    if (riscv_cpu_cfg(env)->ext_smdbltrp) {
> +        mstatus = set_field(mstatus, MSTATUS_MDT, 0);
> +    }
>      if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) {
>          mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
>      }
> --
> 2.43.0
>
>
diff mbox series

Patch

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index d159b0c6b6..98f04ecb8c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -176,6 +176,7 @@  const RISCVIsaExtData isa_edata_arr[] = {
     ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
     ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
     ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
+    ISA_EXT_DATA_ENTRY(smdbltrp, PRIV_VERSION_1_12_0, ext_smdbltrp),
     ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
     ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
     ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
@@ -954,6 +955,9 @@  static void riscv_cpu_reset_hold(Object *obj)
             env->mstatus_hs = set_field(env->mstatus_hs,
                                         MSTATUS64_UXL, env->misa_mxl);
         }
+        if (riscv_cpu_cfg(env)->ext_smdbltrp) {
+            env->mstatus = set_field(env->mstatus, MSTATUS_MDT, 1);
+        }
     }
     env->mcause = 0;
     env->miclaim = MIP_SGEIP;
@@ -1574,6 +1578,7 @@  const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = {
 /* These are experimental so mark with 'x-' */
 const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = {
     MULTI_EXT_CFG_BOOL("x-ssdbltrp", ext_ssdbltrp, false),
+    MULTI_EXT_CFG_BOOL("x-smdbltrp", ext_smdbltrp, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 494a036f6e..660f2eed5b 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -545,6 +545,7 @@ 
 #define MSTATUS_SDT         0x01000000 /* Ssdbltrp extension */
 #define MSTATUS_GVA         0x4000000000ULL
 #define MSTATUS_MPV         0x8000000000ULL
+#define MSTATUS_MDT         0x200000000000ULL /* Smdbltrp extension */
 
 #define MSTATUS64_UXL       0x0000000300000000ULL
 #define MSTATUS64_SXL       0x0000000C00000000ULL
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index a149c08167..cf6a802502 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -75,6 +75,7 @@  struct RISCVCPUConfig {
     bool ext_smstateen;
     bool ext_sstc;
     bool ext_ssdbltrp;
+    bool ext_smdbltrp;
     bool ext_svadu;
     bool ext_svinval;
     bool ext_svnapot;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 3d747e5bfc..5ce0982f2f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1862,6 +1862,12 @@  void riscv_cpu_do_interrupt(CPUState *cs)
         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 (riscv_cpu_cfg(env)->ext_smdbltrp) {
+            if (env->mstatus & MSTATUS_MDT)
+                cpu_abort(CPU(cpu), "M-mode double trap\n");
+
+            s = set_field(s, MSTATUS_MDT, 1);
+        }
         env->mstatus = s;
         env->mcause = cause | ~(((target_ulong)-1) >> async);
         if (smode_double_trap) {
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 1a2e739947..200b06e320 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1363,6 +1363,7 @@  static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp,
 static RISCVException write_mstatus(CPURISCVState *env, int csrno,
                                     target_ulong val)
 {
+    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
     uint64_t mstatus = env->mstatus;
     uint64_t mask = 0;
     RISCVMXL xl = riscv_cpu_mxl(env);
@@ -1396,6 +1397,12 @@  static RISCVException write_mstatus(CPURISCVState *env, int csrno,
         }
     }
 
+    if (cfg->ext_smdbltrp) {
+        mask |= MSTATUS_MDT;
+        if ((val & MSTATUS_MDT) != 0)
+            mask &= ~MSTATUS_MIE;
+    }
+
     if (xl != MXL_RV32 || env->debugger) {
         if (riscv_has_ext(env, RVH)) {
             mask |= MSTATUS_MPV | MSTATUS_GVA;
@@ -1434,6 +1441,11 @@  static RISCVException write_mstatush(CPURISCVState *env, int csrno,
     uint64_t valh = (uint64_t)val << 32;
     uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0;
 
+    if (riscv_cpu_cfg(env)->ext_smdbltrp) {
+        mask |= MSTATUS_MDT;
+        if ((val & MSTATUS_MDT) != 0)
+            mask |= MSTATUS_MIE;
+    }
     env->mstatus = (env->mstatus & ~mask) | (valh & mask);
 
     return RISCV_EXCP_NONE;
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 468ee58a00..d289d14237 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -354,6 +354,9 @@  target_ulong helper_mret(CPURISCVState *env)
     mstatus = set_field(mstatus, MSTATUS_MPP,
                         riscv_has_ext(env, RVU) ? PRV_U : PRV_M);
     mstatus = set_field(mstatus, MSTATUS_MPV, 0);
+    if (riscv_cpu_cfg(env)->ext_smdbltrp) {
+        mstatus = set_field(mstatus, MSTATUS_MDT, 0);
+    }
     if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) {
         mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
     }