Add a big_endian field to RISCVCPUConfig and wire it into the CPU
reset path. When cfg.big_endian is set, riscv_cpu_reset_hold()
writes 1 into the MSTATUS MBE/SBE/UBE fields using set_field();
otherwise it writes 0. This makes the reset value deterministic on
both cold and warm reset.

This models fixed-endian harts, not mixed-endian implementations where
the guest can toggle MBE/SBE/UBE at runtime. The MBE/SBE/UBE bits are
not included in the writable mask of any mstatus/mstatush/sstatus CSR
write path (unchanged by this series), so the value chosen at reset is
effectively hardwired per section 3.1.6.5 of the RISC-V Privileged
Specification.

The user-facing property and documentation are added in a later patch,
once the full endianness support is in place.

Also update the disassembler comment to clarify that BFD_ENDIAN_LITTLE
is correct because RISC-V instructions are always little-endian per the
ISA specification.

Signed-off-by: Djordje Todorovic <[email protected]>
---
 target/riscv/cpu.c                | 14 +++++++++-----
 target/riscv/cpu_cfg_fields.h.inc |  1 +
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ce15a17c37..42d1b3662c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -720,6 +720,13 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType 
type)
             env->mstatus = set_field(env->mstatus, MSTATUS_MDT, 1);
         }
     }
+    /*
+     * Model fixed-endian harts: MBE/SBE/UBE are initialized from the
+     * CPU configuration and are intentionally not writable via status CSRs.
+     */
+    env->mstatus = set_field(env->mstatus, MSTATUS_MBE, cpu->cfg.big_endian);
+    env->mstatus = set_field(env->mstatus, MSTATUS_SBE, cpu->cfg.big_endian);
+    env->mstatus = set_field(env->mstatus, MSTATUS_UBE, cpu->cfg.big_endian);
     env->mcause = 0;
     env->miclaim = MIP_SGEIP;
     env->pc = env->resetvec;
@@ -807,11 +814,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/cpu_cfg_fields.h.inc 
b/target/riscv/cpu_cfg_fields.h.inc
index 734fa079f2..9eb47af0a7 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -157,6 +157,7 @@ BOOL_FIELD(ext_xmipscmov)
 BOOL_FIELD(ext_xmipslsp)
 BOOL_FIELD(ext_xlrbr)
 
+BOOL_FIELD(big_endian)
 BOOL_FIELD(mmu)
 BOOL_FIELD(pmp)
 BOOL_FIELD(debug)
-- 
2.34.1

Reply via email to