target/riscv: Implement runtime data endianness via MSTATUS bits

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 <djordje.todorovic@htecgroup.com>
Co-developed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-3-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Djordje Todorovic
2026-05-27 22:13:38 +02:00
committed by Alistair Francis
parent 11c2c6e025
commit 56db2b7eac
5 changed files with 28 additions and 26 deletions

View File

@@ -831,11 +831,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;

View File

@@ -714,6 +714,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)

View File

@@ -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 */

View File

@@ -194,6 +194,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,

View File

@@ -130,18 +130,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)
@@ -1365,7 +1353,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)