On 22/10/26 15:06, Anton Johansson via qemu development wrote:
mstatus and mstatus_hs are uint64_t but accessed through

   tcg_gen_[ld|st]_tl(..., offsetof(mstatus))

which on a big-endian host running riscv32 incorrectly accesses the
top 32 bits rather than the lower bits.

  mstatus and mstatus_hs are uint64_t, but mark_fs_dirty() and
  mark_vs_dirty() update them with tcg_gen_[ld|st]_tl().
  On big-endian hosts with 32-bit target_ulong, this modifies
  the upper half instead of the lower one, so the FS/VS dirty
  bits are never set. Use 64-bit accesses instead.

Cc: [email protected]
Fixes: 284d697c74e ("target/riscv: Merge m/vsstatus and m/vsstatush into one uint64_t unit") Fixes: 8e1ee1fb571 ("target/riscv: rvv-1.0: add translation-time vector context status")
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>

Widen the operations to 64 bit so the lower bits are modified.

Signed-off-by: Anton Johansson <[email protected]>
---
  target/riscv/tcg/translate.c | 32 ++++++++++++++++----------------
  1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
index ede9c2563f..79b0f444ef 100644
--- a/target/riscv/tcg/translate.c
+++ b/target/riscv/tcg/translate.c
@@ -693,7 +693,7 @@ static TCGv get_address_indexed(DisasContext *ctx, int rs1, 
TCGv offs)
   */
  static void mark_fs_dirty(DisasContext *ctx)
  {
-    TCGv tmp;
+    TCGv_i64 tmp;
if (!has_ext(ctx, RVF)) {
          return;
@@ -703,15 +703,15 @@ static void mark_fs_dirty(DisasContext *ctx)
          /* Remember the state change for the rest of the TB. */
          ctx->mstatus_fs = EXT_STATUS_DIRTY;
- tmp = tcg_temp_new();
-        tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
-        tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
-        tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
+        tmp = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
+        tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
+        tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
if (ctx->virt_enabled) {
-            tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
-            tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
-            tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
+            tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
+            tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
+            tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
          }
      }
  }

Wondering about being safe (or catching other bad uses)

#define TCG_ENV_OFS_(f)     offsetof(CPUArchState, f)
#define TCG_ENV_SIZE_(f)    sizeof_field(CPUArchState, f)

#define tcg_gen_ld_env_tl(ret, f)                               \
    do {                                                        \
        QEMU_BUILD_BUG_ON(TCG_ENV_SIZE_(f) !=                   \
                          sizeof(target_ulong));                \
        tcg_gen_ld_tl(ret, tcg_env, TCG_ENV_OFS_(f));           \
    } while (0)

#define tcg_gen_ld_env_i64(ret, f)                              \
    do {                                                        \
        QEMU_BUILD_BUG_ON(TCG_ENV_SIZE_(f) != 8);               \
        tcg_gen_ld_i64(ret, tcg_env, TCG_ENV_OFS_(f));          \
    } while (0)

or even using _Generic:

#define TCG_ENV_FIELD_(f)   (((CPUArchState *)0)->f)
#define TCG_ENV_OFS_(f)     offsetof(CPUArchState, f)

#define tcg_gen_st_env_i32(arg, f)                              \
    _Generic(TCG_ENV_FIELD_(f),                                 \
             bool:     tcg_gen_st8_i32,                         \
             uint8_t:  tcg_gen_st8_i32,                         \
             int8_t:   tcg_gen_st8_i32,                         \
             uint16_t: tcg_gen_st16_i32,                        \
             int16_t:  tcg_gen_st16_i32,                        \
             uint32_t: tcg_gen_st_i32,                          \
             int32_t:  tcg_gen_st_i32)                          \
        (arg, tcg_env, TCG_ENV_OFS_(f))

#define tcg_gen_st_env_i64(arg, f)                              \
    _Generic(TCG_ENV_FIELD_(f),                                 \
             uint64_t: tcg_gen_st_i64,                          \
             int64_t:  tcg_gen_st_i64)                          \
        (arg, tcg_env, TCG_ENV_OFS_(f))

#if TARGET_LONG_BITS == 32
# define tcg_gen_ld_env_tl  tcg_gen_ld_env_i32
# define tcg_gen_st_env_tl  tcg_gen_st_env_i32
#else
# define tcg_gen_ld_env_tl  tcg_gen_ld_env_i64
# define tcg_gen_st_env_tl  tcg_gen_st_env_i64
#endif

Then replacing (a cheap replacement that can be done with coccinelle
spatch):

@@ -704,14 +757,14 @@ static void mark_fs_dirty(DisasContext *ctx)
         ctx->mstatus_fs = EXT_STATUS_DIRTY;

         tmp = tcg_temp_new();
-        tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
+        tcg_gen_ld_env_tl(tmp, mstatus);
         tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
-        tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
+        tcg_gen_st_env_tl(tmp, mstatus);

         if (ctx->virt_enabled) {
- tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
+            tcg_gen_ld_env_tl(tmp, mstatus_hs);
             tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
- tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
+            tcg_gen_st_env_tl(tmp, mstatus_hs);
         }
     }

triggers:

FAILED: [code=1] libqemu-riscv32-softmmu.a.p/target_riscv_tcg_translate.c.o
../target/riscv/tcg/translate.c:760:9: error: controlling expression type 'uint64_t' (aka 'unsigned long long') not compatible with any generic association type
  760 |         tcg_gen_ld_env_tl(tmp, mstatus);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:86:29: note: expanded from macro 'tcg_gen_ld_env_tl'
   86 | # define tcg_gen_ld_env_tl  tcg_gen_ld_env_i32
      |                             ^
../target/riscv/tcg/translate.c:45:14: note: expanded from macro 'tcg_gen_ld_env_i32'
   45 |     _Generic(TCG_ENV_FIELD_(f),                                 \
      |              ^~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:41:29: note: expanded from macro 'TCG_ENV_FIELD_'
   41 | #define TCG_ENV_FIELD_(f)   (((CPURISCVState *)0)->f)
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:762:9: error: controlling expression type 'uint64_t' (aka 'unsigned long long') not compatible with any generic association type
  762 |         tcg_gen_st_env_tl(tmp, mstatus);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:87:29: note: expanded from macro 'tcg_gen_st_env_tl'
   87 | # define tcg_gen_st_env_tl  tcg_gen_st_env_i32
      |                             ^
../target/riscv/tcg/translate.c:69:14: note: expanded from macro 'tcg_gen_st_env_i32'
   69 |     _Generic(TCG_ENV_FIELD_(f),                                 \
      |              ^~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:41:29: note: expanded from macro 'TCG_ENV_FIELD_'
   41 | #define TCG_ENV_FIELD_(f)   (((CPURISCVState *)0)->f)
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:765:13: error: controlling expression type 'uint64_t' (aka 'unsigned long long') not compatible with any generic association type
  765 |             tcg_gen_ld_env_tl(tmp, mstatus_hs);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:86:29: note: expanded from macro 'tcg_gen_ld_env_tl'
   86 | # define tcg_gen_ld_env_tl  tcg_gen_ld_env_i32
      |                             ^
../target/riscv/tcg/translate.c:45:14: note: expanded from macro 'tcg_gen_ld_env_i32'
   45 |     _Generic(TCG_ENV_FIELD_(f),                                 \
      |              ^~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:41:29: note: expanded from macro 'TCG_ENV_FIELD_'
   41 | #define TCG_ENV_FIELD_(f)   (((CPURISCVState *)0)->f)
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:767:13: error: controlling expression type 'uint64_t' (aka 'unsigned long long') not compatible with any generic association type
  767 |             tcg_gen_st_env_tl(tmp, mstatus_hs);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:87:29: note: expanded from macro 'tcg_gen_st_env_tl'
   87 | # define tcg_gen_st_env_tl  tcg_gen_st_env_i32
      |                             ^
../target/riscv/tcg/translate.c:69:14: note: expanded from macro 'tcg_gen_st_env_i32'
   69 |     _Generic(TCG_ENV_FIELD_(f),                                 \
      |              ^~~~~~~~~~~~~~~~~
../target/riscv/tcg/translate.c:41:29: note: expanded from macro 'TCG_ENV_FIELD_'
   41 | #define TCG_ENV_FIELD_(f)   (((CPURISCVState *)0)->f)
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~
4 errors generated.


Reply via email to