Implement runtime big-endian data support by reading the MSTATUS UBE/SBE/MBE bits to determine data endianness per privilege level.
The key changes are: - Add riscv_cpu_data_is_big_endian() helper in cpu.h that checks the appropriate MSTATUS endianness bit based on current privilege level (MBE for M-mode, SBE for S-mode, UBE for U-mode). - Update mo_endian() in translate.c to return MO_BE or MO_LE based on a new 'big_endian' field in DisasContext, rather than the previous hardcoded MO_TE. - Update mo_endian_env() in op_helper.c to call the new helper, giving hypervisor load/store helpers correct runtime endianness. - Pack the endianness flag into cs_base bit 32 (alongside misa_ext in bits 0-25) in riscv_get_tb_cpu_state(), ensuring translation blocks are correctly separated by data endianness. Note: instruction fetches continue to use MO_LE unconditionally (from the previous patch), as RISC-V instructions are always little-endian per the ISA specification. Signed-off-by: Djordje Todorovic <[email protected]> --- target/riscv/cpu.h | 28 ++++++++++++++++++++++++++++ target/riscv/internals.h | 9 +-------- target/riscv/tcg/tcg-cpu.c | 9 ++++++++- target/riscv/translate.c | 12 ++++-------- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 35d1f6362c..ef870d05b3 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -703,6 +703,12 @@ FIELD(TB_FLAGS, BCFI_ENABLED, 28, 1) FIELD(TB_FLAGS, PM_PMM, 29, 2) FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1) +/* + * cs_base carries misa_ext (bits 0-25) plus additional flags. + * Bit 32 is used for data endianness since TB_FLAGS has no free bits. + */ +#define TB_CSBASE_BIG_ENDIAN (1ULL << 32) + #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) #else @@ -718,6 +724,28 @@ static inline const RISCVCPUConfig *riscv_cpu_cfg(CPURISCVState *env) return &env_archcpu(env)->cfg; } +/* + * Return true if data accesses are big-endian for the current privilege + * level, based on the MSTATUS MBE/SBE/UBE bits. + */ +static inline bool riscv_cpu_data_is_big_endian(CPURISCVState *env) +{ +#if defined(CONFIG_USER_ONLY) + return false; +#else + switch (env->priv) { + case PRV_M: + return env->mstatus & MSTATUS_MBE; + case PRV_S: + return env->mstatus & MSTATUS_SBE; + case PRV_U: + return env->mstatus & MSTATUS_UBE; + default: + g_assert_not_reached(); + } +#endif +} + #if !defined(CONFIG_USER_ONLY) static inline int cpu_address_mode(CPURISCVState *env) { diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 460346dd6d..e2f0334da8 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -64,14 +64,7 @@ static inline bool mmuidx_2stage(int mmu_idx) 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; + return riscv_cpu_data_is_big_endian(env) ? MO_BE : MO_LE; } /* share data between vector helpers and decode code */ diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 3407191c22..fa42197e98 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -189,10 +189,17 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs) flags = FIELD_DP32(flags, TB_FLAGS, PM_PMM, riscv_pm_get_pmm(env)); flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext); + uint64_t cs_base = env->misa_ext; +#ifndef CONFIG_USER_ONLY + if (riscv_cpu_data_is_big_endian(env)) { + cs_base |= TB_CSBASE_BIG_ENDIAN; + } +#endif + return (TCGTBCPUState){ .pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc, .flags = flags, - .cs_base = env->misa_ext, + .cs_base = cs_base, }; } diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 5df5b73849..d7f1f8e466 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -119,6 +119,8 @@ typedef struct DisasContext { bool fcfi_lp_expected; /* zicfiss extension, if shadow stack was enabled during TB gen */ bool bcfi_enabled; + /* Data endianness from MSTATUS UBE/SBE/MBE */ + bool big_endian; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -128,14 +130,7 @@ static inline bool has_ext(DisasContext *ctx, uint32_t 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; + return ctx->big_endian ? MO_BE : MO_LE; } #ifdef TARGET_RISCV32 @@ -1346,6 +1341,7 @@ 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->big_endian = ctx->base.tb->cs_base & TB_CSBASE_BIG_ENDIAN; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) -- 2.34.1
