On Thu, May 28, 2026 at 6:16 AM Philippe Mathieu-Daudé <[email protected]> wrote: > > 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]>
Reviewed-by: Alistair Francis <[email protected]> Alistair > --- > 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 > >
