[PATCH 2/2] target/riscv: fix RV32 stateen CSR handling

Bruno Sa posted 2 patches 2 days, 1 hour ago
[PATCH 2/2] target/riscv: fix RV32 stateen CSR handling
Posted by Bruno Sa 2 days, 1 hour ago
The RV32 stateen CSRs are split between the low-half CSR and the
corresponding xH CSR, but the current implementation still handles some
upper-half bits through the low-half write paths and also accepts the
xH CSRs on RV64.

Fix this by:
- rejecting mstateen*h and hstateen*h accesses on RV64
- keeping the RV64-only writable bits in the low-half write paths
- handling the RV32 upper-half writable bits in write_mstateen0h() and
  write_hstateen0h()
- dropping unsupported writable bits from write_sstateen0()

Signed-off-by: Bruno Sa <bruno.vilaca.sa@gmail.com>
---
 target/riscv/csr.c | 112 +++++++++++++++++++++++++++++++--------------
 1 file changed, 77 insertions(+), 35 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d322bdbd47..015deca6dc 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -497,6 +497,15 @@ static RISCVException mstateen(CPURISCVState *env, int csrno)
     return any(env, csrno);
 }
 
+static RISCVException mstateen_32(CPURISCVState *env, int csrno)
+{
+    if (riscv_cpu_mxl(env) != MXL_RV32) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    return mstateen(env, csrno);
+}
+
 static RISCVException hstateen_pred(CPURISCVState *env, int csrno, int base)
 {
     if (!riscv_cpu_cfg(env)->ext_smstateen) {
@@ -528,6 +537,10 @@ static RISCVException hstateen(CPURISCVState *env, int csrno)
 
 static RISCVException hstateenh(CPURISCVState *env, int csrno)
 {
+    if (riscv_cpu_mxl(env) != MXL_RV32) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
     return hstateen_pred(env, csrno, CSR_HSTATEEN0H);
 }
 
@@ -3403,25 +3416,27 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
         wr_mask |= SMSTATEEN0_FCSR;
     }
 
-    if (env->priv_ver >= PRIV_VERSION_1_13_0) {
-        wr_mask |= SMSTATEEN0_P1P13;
-    }
+    if (riscv_cpu_mxl(env) == MXL_RV64) {
+        if (env->priv_ver >= PRIV_VERSION_1_13_0) {
+            wr_mask |= SMSTATEEN0_P1P13;
+        }
 
-    if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
-        wr_mask |= SMSTATEEN0_SVSLCT;
-    }
+        if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
+            wr_mask |= SMSTATEEN0_SVSLCT;
+        }
 
-    /*
-     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
-     * implemented. However, that information is with MachineState and we can't
-     * figure that out in csr.c. Just enable if Smaia is available.
-     */
-    if (riscv_cpu_cfg(env)->ext_smaia) {
-        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
-    }
+        /*
+         * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
+         * implemented. However, that information is with MachineState and we can't
+         * figure that out in csr.c. Just enable if Smaia is available.
+         */
+        if (riscv_cpu_cfg(env)->ext_smaia) {
+            wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
+        }
 
-    if (riscv_cpu_cfg(env)->ext_ssctr) {
-        wr_mask |= SMSTATEEN0_CTR;
+        if (riscv_cpu_cfg(env)->ext_ssctr) {
+            wr_mask |= SMSTATEEN0_CTR;
+        }
     }
 
     return write_mstateen(env, csrno, wr_mask, new_val);
@@ -3463,6 +3478,19 @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno,
         wr_mask |= SMSTATEEN0_P1P13;
     }
 
+    if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
+        wr_mask |= SMSTATEEN0_SVSLCT;
+    }
+
+    /*
+     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
+     * implemented. However, that information is with MachineState and we can't
+     * figure that out in csr.c. Just enable if Smaia is available.
+     */
+    if (riscv_cpu_cfg(env)->ext_smaia) {
+        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
+    }
+
     if (riscv_cpu_cfg(env)->ext_ssctr) {
         wr_mask |= SMSTATEEN0_CTR;
     }
@@ -3507,22 +3535,23 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
     if (!riscv_has_ext(env, RVF)) {
         wr_mask |= SMSTATEEN0_FCSR;
     }
+    if (riscv_cpu_mxl(env) == MXL_RV64) {
+        if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
+            wr_mask |= SMSTATEEN0_SVSLCT;
+        }
 
-    if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
-        wr_mask |= SMSTATEEN0_SVSLCT;
-    }
-
-    /*
-     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
-     * implemented. However, that information is with MachineState and we can't
-     * figure that out in csr.c. Just enable if Ssaia is available.
-     */
-    if (riscv_cpu_cfg(env)->ext_ssaia) {
-        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
-    }
+        /*
+         * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
+         * implemented. However, that information is with MachineState and we can't
+         * figure that out in csr.c. Just enable if Ssaia is available.
+         */
+        if (riscv_cpu_cfg(env)->ext_ssaia) {
+            wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
+        }
 
-    if (riscv_cpu_cfg(env)->ext_ssctr) {
-        wr_mask |= SMSTATEEN0_CTR;
+        if (riscv_cpu_cfg(env)->ext_ssctr) {
+            wr_mask |= SMSTATEEN0_CTR;
+        }
     }
 
     return write_hstateen(env, csrno, wr_mask, new_val);
@@ -3564,6 +3593,19 @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno,
 {
     uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
 
+    if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
+        wr_mask |= SMSTATEEN0_SVSLCT;
+    }
+
+    /*
+     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
+     * implemented. However, that information is with MachineState and we can't
+     * figure that out in csr.c. Just enable if Ssaia is available.
+     */
+    if (riscv_cpu_cfg(env)->ext_ssaia) {
+        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
+    }
+
     if (riscv_cpu_cfg(env)->ext_ssctr) {
         wr_mask |= SMSTATEEN0_CTR;
     }
@@ -3613,7 +3655,7 @@ static RISCVException write_sstateen(CPURISCVState *env, int csrno,
 static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
                                       target_ulong new_val)
 {
-    uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+    uint64_t wr_mask = 0;
 
     if (!riscv_has_ext(env, RVF)) {
         wr_mask |= SMSTATEEN0_FCSR;
@@ -5861,25 +5903,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* Smstateen extension CSRs */
     [CSR_MSTATEEN0] = { "mstateen0", mstateen, read_mstateen, write_mstateen0,
                         .min_priv_ver = PRIV_VERSION_1_12_0 },
-    [CSR_MSTATEEN0H] = { "mstateen0h", mstateen, read_mstateenh,
+    [CSR_MSTATEEN0H] = { "mstateen0h", mstateen_32, read_mstateenh,
                           write_mstateen0h,
                          .min_priv_ver = PRIV_VERSION_1_12_0 },
     [CSR_MSTATEEN1] = { "mstateen1", mstateen, read_mstateen,
                         write_mstateen_1_3,
                         .min_priv_ver = PRIV_VERSION_1_12_0 },
-    [CSR_MSTATEEN1H] = { "mstateen1h", mstateen, read_mstateenh,
+    [CSR_MSTATEEN1H] = { "mstateen1h", mstateen_32, read_mstateenh,
                          write_mstateenh_1_3,
                          .min_priv_ver = PRIV_VERSION_1_12_0 },
     [CSR_MSTATEEN2] = { "mstateen2", mstateen, read_mstateen,
                         write_mstateen_1_3,
                         .min_priv_ver = PRIV_VERSION_1_12_0 },
-    [CSR_MSTATEEN2H] = { "mstateen2h", mstateen, read_mstateenh,
+    [CSR_MSTATEEN2H] = { "mstateen2h", mstateen_32, read_mstateenh,
                          write_mstateenh_1_3,
                          .min_priv_ver = PRIV_VERSION_1_12_0 },
     [CSR_MSTATEEN3] = { "mstateen3", mstateen, read_mstateen,
                         write_mstateen_1_3,
                         .min_priv_ver = PRIV_VERSION_1_12_0 },
-    [CSR_MSTATEEN3H] = { "mstateen3h", mstateen, read_mstateenh,
+    [CSR_MSTATEEN3H] = { "mstateen3h", mstateen_32, read_mstateenh,
                          write_mstateenh_1_3,
                          .min_priv_ver = PRIV_VERSION_1_12_0 },
     [CSR_HSTATEEN0] = { "hstateen0", hstateen, read_hstateen, write_hstateen0,
-- 
2.43.0
Re: [PATCH 2/2] target/riscv: fix RV32 stateen CSR handling
Posted by Alistair Francis 1 day, 15 hours ago
On Fri, Apr 10, 2026 at 3:27 AM Bruno Sa <bruno.vilaca.sa@gmail.com> wrote:
>
> The RV32 stateen CSRs are split between the low-half CSR and the
> corresponding xH CSR, but the current implementation still handles some
> upper-half bits through the low-half write paths and also accepts the
> xH CSRs on RV64.
>
> Fix this by:
> - rejecting mstateen*h and hstateen*h accesses on RV64
> - keeping the RV64-only writable bits in the low-half write paths
> - handling the RV32 upper-half writable bits in write_mstateen0h() and
>   write_hstateen0h()
> - dropping unsupported writable bits from write_sstateen0()
>
> Signed-off-by: Bruno Sa <bruno.vilaca.sa@gmail.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/csr.c | 112 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 77 insertions(+), 35 deletions(-)
>
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index d322bdbd47..015deca6dc 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -497,6 +497,15 @@ static RISCVException mstateen(CPURISCVState *env, int csrno)
>      return any(env, csrno);
>  }
>
> +static RISCVException mstateen_32(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_cpu_mxl(env) != MXL_RV32) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return mstateen(env, csrno);
> +}
> +
>  static RISCVException hstateen_pred(CPURISCVState *env, int csrno, int base)
>  {
>      if (!riscv_cpu_cfg(env)->ext_smstateen) {
> @@ -528,6 +537,10 @@ static RISCVException hstateen(CPURISCVState *env, int csrno)
>
>  static RISCVException hstateenh(CPURISCVState *env, int csrno)
>  {
> +    if (riscv_cpu_mxl(env) != MXL_RV32) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
>      return hstateen_pred(env, csrno, CSR_HSTATEEN0H);
>  }
>
> @@ -3403,25 +3416,27 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
>          wr_mask |= SMSTATEEN0_FCSR;
>      }
>
> -    if (env->priv_ver >= PRIV_VERSION_1_13_0) {
> -        wr_mask |= SMSTATEEN0_P1P13;
> -    }
> +    if (riscv_cpu_mxl(env) == MXL_RV64) {
> +        if (env->priv_ver >= PRIV_VERSION_1_13_0) {
> +            wr_mask |= SMSTATEEN0_P1P13;
> +        }
>
> -    if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
> -        wr_mask |= SMSTATEEN0_SVSLCT;
> -    }
> +        if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
> +            wr_mask |= SMSTATEEN0_SVSLCT;
> +        }
>
> -    /*
> -     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> -     * implemented. However, that information is with MachineState and we can't
> -     * figure that out in csr.c. Just enable if Smaia is available.
> -     */
> -    if (riscv_cpu_cfg(env)->ext_smaia) {
> -        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> -    }
> +        /*
> +         * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> +         * implemented. However, that information is with MachineState and we can't
> +         * figure that out in csr.c. Just enable if Smaia is available.
> +         */
> +        if (riscv_cpu_cfg(env)->ext_smaia) {
> +            wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> +        }
>
> -    if (riscv_cpu_cfg(env)->ext_ssctr) {
> -        wr_mask |= SMSTATEEN0_CTR;
> +        if (riscv_cpu_cfg(env)->ext_ssctr) {
> +            wr_mask |= SMSTATEEN0_CTR;
> +        }
>      }
>
>      return write_mstateen(env, csrno, wr_mask, new_val);
> @@ -3463,6 +3478,19 @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno,
>          wr_mask |= SMSTATEEN0_P1P13;
>      }
>
> +    if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
> +        wr_mask |= SMSTATEEN0_SVSLCT;
> +    }
> +
> +    /*
> +     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> +     * implemented. However, that information is with MachineState and we can't
> +     * figure that out in csr.c. Just enable if Smaia is available.
> +     */
> +    if (riscv_cpu_cfg(env)->ext_smaia) {
> +        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> +    }
> +
>      if (riscv_cpu_cfg(env)->ext_ssctr) {
>          wr_mask |= SMSTATEEN0_CTR;
>      }
> @@ -3507,22 +3535,23 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
>      if (!riscv_has_ext(env, RVF)) {
>          wr_mask |= SMSTATEEN0_FCSR;
>      }
> +    if (riscv_cpu_mxl(env) == MXL_RV64) {
> +        if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
> +            wr_mask |= SMSTATEEN0_SVSLCT;
> +        }
>
> -    if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
> -        wr_mask |= SMSTATEEN0_SVSLCT;
> -    }
> -
> -    /*
> -     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> -     * implemented. However, that information is with MachineState and we can't
> -     * figure that out in csr.c. Just enable if Ssaia is available.
> -     */
> -    if (riscv_cpu_cfg(env)->ext_ssaia) {
> -        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> -    }
> +        /*
> +         * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> +         * implemented. However, that information is with MachineState and we can't
> +         * figure that out in csr.c. Just enable if Ssaia is available.
> +         */
> +        if (riscv_cpu_cfg(env)->ext_ssaia) {
> +            wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> +        }
>
> -    if (riscv_cpu_cfg(env)->ext_ssctr) {
> -        wr_mask |= SMSTATEEN0_CTR;
> +        if (riscv_cpu_cfg(env)->ext_ssctr) {
> +            wr_mask |= SMSTATEEN0_CTR;
> +        }
>      }
>
>      return write_hstateen(env, csrno, wr_mask, new_val);
> @@ -3564,6 +3593,19 @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno,
>  {
>      uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>
> +    if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
> +        wr_mask |= SMSTATEEN0_SVSLCT;
> +    }
> +
> +    /*
> +     * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
> +     * implemented. However, that information is with MachineState and we can't
> +     * figure that out in csr.c. Just enable if Ssaia is available.
> +     */
> +    if (riscv_cpu_cfg(env)->ext_ssaia) {
> +        wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
> +    }
> +
>      if (riscv_cpu_cfg(env)->ext_ssctr) {
>          wr_mask |= SMSTATEEN0_CTR;
>      }
> @@ -3613,7 +3655,7 @@ static RISCVException write_sstateen(CPURISCVState *env, int csrno,
>  static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
>                                        target_ulong new_val)
>  {
> -    uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +    uint64_t wr_mask = 0;
>
>      if (!riscv_has_ext(env, RVF)) {
>          wr_mask |= SMSTATEEN0_FCSR;
> @@ -5861,25 +5903,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* Smstateen extension CSRs */
>      [CSR_MSTATEEN0] = { "mstateen0", mstateen, read_mstateen, write_mstateen0,
>                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> -    [CSR_MSTATEEN0H] = { "mstateen0h", mstateen, read_mstateenh,
> +    [CSR_MSTATEEN0H] = { "mstateen0h", mstateen_32, read_mstateenh,
>                            write_mstateen0h,
>                           .min_priv_ver = PRIV_VERSION_1_12_0 },
>      [CSR_MSTATEEN1] = { "mstateen1", mstateen, read_mstateen,
>                          write_mstateen_1_3,
>                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> -    [CSR_MSTATEEN1H] = { "mstateen1h", mstateen, read_mstateenh,
> +    [CSR_MSTATEEN1H] = { "mstateen1h", mstateen_32, read_mstateenh,
>                           write_mstateenh_1_3,
>                           .min_priv_ver = PRIV_VERSION_1_12_0 },
>      [CSR_MSTATEEN2] = { "mstateen2", mstateen, read_mstateen,
>                          write_mstateen_1_3,
>                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> -    [CSR_MSTATEEN2H] = { "mstateen2h", mstateen, read_mstateenh,
> +    [CSR_MSTATEEN2H] = { "mstateen2h", mstateen_32, read_mstateenh,
>                           write_mstateenh_1_3,
>                           .min_priv_ver = PRIV_VERSION_1_12_0 },
>      [CSR_MSTATEEN3] = { "mstateen3", mstateen, read_mstateen,
>                          write_mstateen_1_3,
>                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> -    [CSR_MSTATEEN3H] = { "mstateen3h", mstateen, read_mstateenh,
> +    [CSR_MSTATEEN3H] = { "mstateen3h", mstateen_32, read_mstateenh,
>                           write_mstateenh_1_3,
>                           .min_priv_ver = PRIV_VERSION_1_12_0 },
>      [CSR_HSTATEEN0] = { "hstateen0", hstateen, read_hstateen, write_hstateen0,
> --
> 2.43.0
>
>