aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2023-06-20 23:10:41 +1000
committerCédric Le Goater <clg@kaod.org>2023-06-25 22:41:30 +0200
commit888050cf519eb5995424cf415f4f8f269de96824 (patch)
treed6ff1489fd56e8fc9c586661014eeec74a634f96 /target/ppc
parent6b8a05373bf142fe5fd3839c3675da005bfc9b49 (diff)
target/ppc: Fix instruction loading endianness in alignment interrupt
powerpc ifetch endianness depends on MSR[LE] so it has to byteswap after cpu_ldl_code(). This corrects DSISR bits in alignment interrupts when running in little endian mode. Reviewed-by: Fabiano Rosas <farosas@suse.de> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Cédric Le Goater <clg@kaod.org>
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/excp_helper.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 12d8a7257b..a2801f6e6b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -133,6 +133,26 @@ static void dump_hcall(CPUPPCState *env)
env->nip);
}
+#ifdef CONFIG_TCG
+/* Return true iff byteswap is needed to load instruction */
+static inline bool insn_need_byteswap(CPUArchState *env)
+{
+ /* SYSTEM builds TARGET_BIG_ENDIAN. Need to swap when MSR[LE] is set */
+ return !!(env->msr & ((target_ulong)1 << MSR_LE));
+}
+
+static uint32_t ppc_ldl_code(CPUArchState *env, hwaddr addr)
+{
+ uint32_t insn = cpu_ldl_code(env, addr);
+
+ if (insn_need_byteswap(env)) {
+ insn = bswap32(insn);
+ }
+
+ return insn;
+}
+#endif
+
static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
{
const char *es;
@@ -3104,7 +3124,7 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
/* Restore state and reload the insn we executed, for filling in DSISR. */
cpu_restore_state(cs, retaddr);
- insn = cpu_ldl_code(env, env->nip);
+ insn = ppc_ldl_code(env, env->nip);
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_4xx: