From: Djordje Todorovic <[email protected]>

Make data accesses honour the MSTATUS MBE/SBE/UBE endianness bits
instead of being hardcoded to little-endian. Update mo_endian_env()
to pick the bit corresponding to the current privilege level (MBE
for M, SBE for S, UBE for U). Remove the now unused mo_endian()
helper.

Note, TB_FLAGS has no free bits, so the data endianness is carried
in the extended RISC-V TB flags stored in cs_base. It uses
EXT_TB_FLAGS.BIG_ENDIAN at bit 33, leaving bit 32 for
EXT_TB_FLAGS.ALTFMT. This keys TBs correctly on the current data
endianness.

Instruction fetches remain MO_LE unconditionally; RISC-V instructions
are always little-endian per the ISA specification. Update the
disassembler comment to clarify that BFD_ENDIAN_LITTLE is correct.

Signed-off-by: Djordje Todorovic <[email protected]>
Co-developed-by: Philippe Mathieu-Daudé <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
---
 target/riscv/cpu.h         |  1 +
 target/riscv/internals.h   | 29 +++++++++++++++++++++--------
 target/riscv/cpu.c         |  7 ++-----
 target/riscv/tcg/tcg-cpu.c |  2 ++
 target/riscv/translate.c   | 15 ++-------------
 5 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7d79c7a5a7e..1f3cbbf823f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -706,6 +706,7 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
 
 FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
 FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
+FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
 
 #ifdef TARGET_RISCV32
 #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index 8c24af0d855..2b3bdbbf30a 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -62,16 +62,29 @@ static inline bool mmuidx_2stage(int mmu_idx)
     return mmu_idx & MMU_2STAGE_BIT;
 }
 
+/*
+ * Return the endianness for the current privilege
+ * level, based on the MSTATUS MBE/SBE/UBE bits.
+ */
 static inline MemOp mo_endian_env(CPURISCVState *env)
 {
-    /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
-     */
-    return MO_LE;
+    bool be = false;
+#if !defined(CONFIG_USER_ONLY)
+    switch (env->priv) {
+    case PRV_M:
+        be = env->mstatus & MSTATUS_MBE;
+        break;
+    case PRV_S:
+        be = env->mstatus & MSTATUS_SBE;
+        break;
+    case PRV_U:
+        be = env->mstatus & MSTATUS_UBE;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+#endif
+    return be ? MO_BE : MO_LE;
 }
 
 /* share data between vector helpers and decode code */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 862834b4809..52f143f1cd4 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -830,11 +830,8 @@ static void riscv_cpu_disas_set_info(const CPUState *s, 
disassemble_info *info)
     info->target_info = &cpu->cfg;
 
     /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
+     * RISC-V instructions are always little-endian, regardless of the
+     * data endianness configured via MSTATUS UBE/SBE/MBE bits.
      */
     info->endian = BFD_ENDIAN_LITTLE;
 
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 3e22e7ed53d..45bbf658cad 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -193,6 +193,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
     flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext);
 
     ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, MISA_EXT, env->misa_ext);
+    ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, BIG_ENDIAN,
+                           mo_endian_env(env) == MO_BE);
 
     return (TCGTBCPUState){
         .pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9367f159f90..35c6b37c0b6 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -129,18 +129,6 @@ static inline bool has_ext(DisasContext *ctx, uint32_t ext)
     return ctx->misa_ext & ext;
 }
 
-static inline MemOp mo_endian(DisasContext *ctx)
-{
-    /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
-     */
-    return MO_LE;
-}
-
 #ifdef TARGET_RISCV32
 #define get_xl(ctx)    MXL_RV32
 #elif defined(CONFIG_USER_ONLY)
@@ -1362,7 +1350,8 @@ static void riscv_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
     ctx->zero = tcg_constant_tl(0);
     ctx->virt_inst_excp = false;
     ctx->decoders = cpu->decoders;
-    ctx->mo_endianness = mo_endian(ctx);
+    ctx->mo_endianness = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, BIG_ENDIAN)
+                         ? MO_BE : MO_LE;
 }
 
 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
-- 
2.53.0


Reply via email to