[PATCH v3] target/riscv: write back unmodified value for csrrc/csrrs with rs1 is not x0 but holding zero

Weiwei Li posted 1 patch 2 years, 1 month ago
Test checkpatch passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20220318020724.22424-1-liweiwei@iscas.ac.cn
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Bin Meng <bin.meng@windriver.com>
target/riscv/cpu.c       |  3 ++-
target/riscv/cpu.h       | 13 ++++++++-----
target/riscv/csr.c       | 40 +++++++++++++++++++++++-----------------
target/riscv/gdbstub.c   | 12 ++++++------
target/riscv/op_helper.c | 12 ++++++------
5 files changed, 45 insertions(+), 35 deletions(-)
[PATCH v3] target/riscv: write back unmodified value for csrrc/csrrs with rs1 is not x0 but holding zero
Posted by Weiwei Li 2 years, 1 month ago
For csrrs and csrrc, if rs1 specifies a register other than x0, holding
a zero value, the instruction will still attempt to write the unmodified
value back to the csr and will cause side effects

Signed-off-by: Weiwei Li <liweiwei@iscas.ac.cn>
Signed-off-by: Junqiang Wang <wangjunqiang@iscas.ac.cn>

v3:
* delete change to riscv_csr_predicate_fn, leaving seed CSR as a special
  case handled in helper_csrr
* rebase to riscv-to-apply.next

v2:
* change to explictly pass "bool write_op" argument in riscv_csrrw*, do
  write permission check and write operation depend on it
* extend riscv_csr_predicate_fn to pass "write_op" argument which will
  be checked by seed csr or other future "write-only" csr
---
 target/riscv/cpu.c       |  3 ++-
 target/riscv/cpu.h       | 13 ++++++++-----
 target/riscv/csr.c       | 40 +++++++++++++++++++++++-----------------
 target/riscv/gdbstub.c   | 12 ++++++------
 target/riscv/op_helper.c | 12 ++++++------
 5 files changed, 45 insertions(+), 35 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index cfdfe787de..dfcaa26251 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -314,7 +314,8 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         for (int i = 0; i < ARRAY_SIZE(dump_csrs); ++i) {
             int csrno = dump_csrs[i];
             target_ulong val = 0;
-            RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0);
+            RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0,
+                                                   false);
 
             /*
              * Rely on the smode, hmode, etc, predicates within csr.c
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index fe5f212987..6d8fd72a59 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -624,22 +624,24 @@ void riscv_cpu_update_mask(CPURISCVState *env);
 
 RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
                            target_ulong *ret_value,
-                           target_ulong new_value, target_ulong write_mask);
+                           target_ulong new_value, target_ulong write_mask,
+                           bool write_op);
 RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
                                  target_ulong *ret_value,
                                  target_ulong new_value,
-                                 target_ulong write_mask);
+                                 target_ulong write_mask, bool write_op);
 
 static inline void riscv_csr_write(CPURISCVState *env, int csrno,
                                    target_ulong val)
 {
-    riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
+    riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS),
+                true);
 }
 
 static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
 {
     target_ulong val = 0;
-    riscv_csrrw(env, csrno, &val, 0, 0);
+    riscv_csrrw(env, csrno, &val, 0, 0, false);
     return val;
 }
 
@@ -656,7 +658,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
 
 RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
                                 Int128 *ret_value,
-                                Int128 new_value, Int128 write_mask);
+                                Int128 new_value, Int128 write_mask,
+                                bool write_op);
 
 typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
                                                Int128 *ret_value);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 3709c82c9f..3c61dd69af 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2973,7 +2973,8 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
 static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
                                                int csrno,
                                                bool write_mask,
-                                               RISCVCPU *cpu)
+                                               RISCVCPU *cpu,
+                                               bool write_op)
 {
     /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
     int read_only = get_field(csrno, 0xC00) == 3;
@@ -2996,7 +2997,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
         return RISCV_EXCP_ILLEGAL_INST;
     }
 #endif
-    if (write_mask && read_only) {
+    if (write_op && read_only) {
         return RISCV_EXCP_ILLEGAL_INST;
     }
 
@@ -3020,7 +3021,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
 static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
                                        target_ulong *ret_value,
                                        target_ulong new_value,
-                                       target_ulong write_mask)
+                                       target_ulong write_mask, bool write_op)
 {
     RISCVException ret;
     target_ulong old_value;
@@ -3040,8 +3041,8 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
         return ret;
     }
 
-    /* write value if writable and write mask set, otherwise drop writes */
-    if (write_mask) {
+    /* write value if writable and write_op set, otherwise drop writes */
+    if (write_op) {
         new_value = (old_value & ~write_mask) | (new_value & write_mask);
         if (csr_ops[csrno].write) {
             ret = csr_ops[csrno].write(env, csrno, new_value);
@@ -3061,22 +3062,25 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
 
 RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
                            target_ulong *ret_value,
-                           target_ulong new_value, target_ulong write_mask)
+                           target_ulong new_value, target_ulong write_mask,
+                           bool write_op)
 {
     RISCVCPU *cpu = env_archcpu(env);
 
-    RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu);
+    RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu,
+                                           write_op);
     if (ret != RISCV_EXCP_NONE) {
         return ret;
     }
 
-    return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask);
+    return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask,
+                            write_op);
 }
 
 static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
                                         Int128 *ret_value,
                                         Int128 new_value,
-                                        Int128 write_mask)
+                                        Int128 write_mask, bool write_op)
 {
     RISCVException ret;
     Int128 old_value;
@@ -3087,8 +3091,8 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
         return ret;
     }
 
-    /* write value if writable and write mask set, otherwise drop writes */
-    if (int128_nz(write_mask)) {
+    /* write value if writable and write_op set, otherwise drop writes */
+    if (write_op) {
         new_value = int128_or(int128_and(old_value, int128_not(write_mask)),
                               int128_and(new_value, write_mask));
         if (csr_ops[csrno].write128) {
@@ -3115,18 +3119,20 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
 
 RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
                                 Int128 *ret_value,
-                                Int128 new_value, Int128 write_mask)
+                                Int128 new_value, Int128 write_mask,
+                                bool write_op)
 {
     RISCVException ret;
     RISCVCPU *cpu = env_archcpu(env);
 
-    ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu);
+    ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu, write_op);
     if (ret != RISCV_EXCP_NONE) {
         return ret;
     }
 
     if (csr_ops[csrno].read128) {
-        return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask);
+        return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask,
+                                 write_op);
     }
 
     /*
@@ -3138,7 +3144,7 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
     target_ulong old_value;
     ret = riscv_csrrw_do64(env, csrno, &old_value,
                            int128_getlo(new_value),
-                           int128_getlo(write_mask));
+                           int128_getlo(write_mask), write_op);
     if (ret == RISCV_EXCP_NONE && ret_value) {
         *ret_value = int128_make64(old_value);
     }
@@ -3152,13 +3158,13 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
 RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
                                  target_ulong *ret_value,
                                  target_ulong new_value,
-                                 target_ulong write_mask)
+                                 target_ulong write_mask, bool write_op)
 {
     RISCVException ret;
 #if !defined(CONFIG_USER_ONLY)
     env->debugger = true;
 #endif
-    ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask);
+    ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask, write_op);
 #if !defined(CONFIG_USER_ONLY)
     env->debugger = false;
 #endif
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 9ed049c29e..cdca919ffc 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -124,7 +124,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
          * This also works for CSR_FRM and CSR_FCSR.
          */
         result = riscv_csrrw_debug(env, n - 32, &val,
-                                   0, 0);
+                                   0, 0, false);
         if (result == RISCV_EXCP_NONE) {
             return gdb_get_regl(buf, val);
         }
@@ -147,7 +147,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
          * This also works for CSR_FRM and CSR_FCSR.
          */
         result = riscv_csrrw_debug(env, n - 32, NULL,
-                                   val, -1);
+                                   val, -1, true);
         if (result == RISCV_EXCP_NONE) {
             return sizeof(target_ulong);
         }
@@ -209,7 +209,7 @@ static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n)
     }
 
     target_ulong val = 0;
-    int result = riscv_csrrw_debug(env, csrno, &val, 0, 0);
+    int result = riscv_csrrw_debug(env, csrno, &val, 0, 0, false);
 
     if (result == 0) {
         return gdb_get_regl(buf, val);
@@ -236,7 +236,7 @@ static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n)
     }
 
     target_ulong val = ldtul_p(mem_buf);
-    int result = riscv_csrrw_debug(env, csrno, NULL, val, -1);
+    int result = riscv_csrrw_debug(env, csrno, NULL, val, -1, true);
 
     if (result == 0) {
         return sizeof(target_ulong);
@@ -251,7 +251,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
         target_ulong val = 0;
         int result;
 
-        result = riscv_csrrw_debug(env, n, &val, 0, 0);
+        result = riscv_csrrw_debug(env, n, &val, 0, 0, false);
         if (result == RISCV_EXCP_NONE) {
             return gdb_get_regl(buf, val);
         }
@@ -265,7 +265,7 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
         target_ulong val = ldtul_p(mem_buf);
         int result;
 
-        result = riscv_csrrw_debug(env, n, NULL, val, -1);
+        result = riscv_csrrw_debug(env, n, NULL, val, -1, true);
         if (result == RISCV_EXCP_NONE) {
             return sizeof(target_ulong);
         }
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 1a75ba11e6..e0d708091e 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -40,7 +40,7 @@ void helper_raise_exception(CPURISCVState *env, uint32_t exception)
 target_ulong helper_csrr(CPURISCVState *env, int csr)
 {
     target_ulong val = 0;
-    RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
+    RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0, false);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
@@ -51,7 +51,7 @@ target_ulong helper_csrr(CPURISCVState *env, int csr)
 void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
 {
     target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1;
-    RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask);
+    RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask, true);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
@@ -62,7 +62,7 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr,
                           target_ulong src, target_ulong write_mask)
 {
     target_ulong val = 0;
-    RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
+    RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask, true);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
@@ -75,7 +75,7 @@ target_ulong helper_csrr_i128(CPURISCVState *env, int csr)
     Int128 rv = int128_zero();
     RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
                                           int128_zero(),
-                                          int128_zero());
+                                          int128_zero(), false);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
@@ -90,7 +90,7 @@ void helper_csrw_i128(CPURISCVState *env, int csr,
 {
     RISCVException ret = riscv_csrrw_i128(env, csr, NULL,
                                           int128_make128(srcl, srch),
-                                          UINT128_MAX);
+                                          UINT128_MAX, true);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
@@ -104,7 +104,7 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
     Int128 rv = int128_zero();
     RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
                                           int128_make128(srcl, srch),
-                                          int128_make128(maskl, maskh));
+                                          int128_make128(maskl, maskh), true);
 
     if (ret != RISCV_EXCP_NONE) {
         riscv_raise_exception(env, ret, GETPC());
-- 
2.17.1