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
>
>

Reply via email to