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
