@samitouri / QOSamiQemu / commits / bd8820aa7b

linux-user/mips, target/mips: honor MIPS_FIXADE for unaligned accesses

Linux/MIPS enables software fixups for user-mode unaligned scalar accesses by default through MIPS_FIXADE/TIF_FIXADE. QEMU linux-user did not model that ABI, so MIPS guests took fatal AdEL/AdES exceptions unless translation was forced to use unaligned host accesses. Key MIPS translation blocks on the linux-user unaligned policy, implement sysmips(MIPS_FIXADE) to toggle that policy, and raise SIGBUS/BUS_ADRALN when fixups are disabled. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: James Hilliard <james.hilliard1@gmail.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20260520172313.23777-4-philmd@linaro.org>

James Hilliard committed Apr 8, 2026 at 20:54 UTC bd8820aa7b0b8c03441feeaa790047f6028dbc38
7 files changed +32 -3
linux-user/mips/cpu_loop.c
+5
@@ -161,6 +161,11 @@ done_syscall:
161 case EXCP_DSPDIS:
162 force_sig(TARGET_SIGILL);
163 break;
164 + case EXCP_AdEL:
165 + case EXCP_AdES:
166 + force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
167 + env->CP0_BadVAddr);
168 + break;
169 case EXCP_INTERRUPT:
170 /* just indicate that signals should be handled asap */
171 break;
linux-user/mips/target_syscall.h
+1
@@ -11,6 +11,7 @@
11
12 #define TARGET_FORCE_SHMLBA
13 #define TARGET_SYSMIPS_FLUSH_CACHE 3
14 +#define TARGET_SYSMIPS_FIXADE 7
15 #define TARGET_SYSMIPS_ATOMIC_SET 2001
16
17 static inline abi_ulong target_shmlba(CPUMIPSState *env)
linux-user/mips64/target_syscall.h
+1
@@ -11,6 +11,7 @@
11
12 #define TARGET_FORCE_SHMLBA
13 #define TARGET_SYSMIPS_FLUSH_CACHE 3
14 +#define TARGET_SYSMIPS_FIXADE 7
15 #define TARGET_SYSMIPS_ATOMIC_SET 2001
16
17 static inline abi_ulong target_shmlba(CPUMIPSState *env)
linux-user/syscall.c
+8
@@ -6663,9 +6663,17 @@ static abi_long do_sysmips_atomic_set(CPUArchState *env, abi_ulong addr,
6663 static abi_long do_sysmips(CPUArchState *env, abi_long cmd, abi_long arg1,
6664 abi_long arg2)
6665 {
6666 + CPUState *cs = env_cpu(env);
6667 +
6668 switch (cmd) {
6669 case TARGET_SYSMIPS_ATOMIC_SET:
6670 return do_sysmips_atomic_set(env, arg1, arg2);
6671 + case TARGET_SYSMIPS_FIXADE:
6672 + if (arg1 & ~3) {
6673 + return -TARGET_EINVAL;
6674 + }
6675 + cs->prctl_unalign_sigbus = !(arg1 & 1);
6676 + return 0;
6677 case TARGET_SYSMIPS_FLUSH_CACHE:
6678 return 0;
6679 default:
target/mips/cpu.c
+8 -2
@@ -560,11 +560,17 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc)
560 static TCGTBCPUState mips_get_tb_cpu_state(CPUState *cs)
561 {
562 CPUMIPSState *env = cpu_env(cs);
563 + uint32_t flags = env->hflags & MIPS_HFLAG_TB_MASK;
564 +
565 +#ifdef CONFIG_USER_ONLY
566 + if (!cs->prctl_unalign_sigbus) {
567 + flags |= TB_FLAG_MIPS_FIXADE;
568 + }
569 +#endif
570
571 return (TCGTBCPUState){
572 .pc = env->active_tc.PC,
566 - .flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK |
567 - MIPS_HFLAG_HWRENA_ULR),
573 + .flags = flags,
574 };
575 }
576
target/mips/cpu.h
+4
@@ -1161,6 +1161,10 @@ typedef struct CPUArchState {
1161 #define MIPS_HFLAG_ELPA 0x4000000
1162 #define MIPS_HFLAG_ITC_CACHE 0x8000000 /* CACHE instr. operates on ITC tag */
1163 #define MIPS_HFLAG_ERL 0x10000000 /* error level flag */
1164 +#define MIPS_HFLAG_TB_MASK (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | \
1165 + MIPS_HFLAG_HWRENA_ULR)
1166 +
1167 +#define TB_FLAG_MIPS_FIXADE 0x40000000
1168 target_ulong btarget; /* Jump / branch target */
1169 target_ulong bcond; /* Branch condition (if needed) */
1170
target/mips/tcg/translate.c
+5 -1
@@ -15070,6 +15070,7 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
15070 {
15071 DisasContext *ctx = container_of(dcbase, DisasContext, base);
15072 CPUMIPSState *env = cpu_env(cs);
15073 + uint32_t tb_flags = ctx->base.tb->flags;
15074
15075 ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
15076 ctx->saved_pc = -1;
@@ -15092,7 +15093,7 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
15093 ctx->CP0_LLAddr_shift = env->CP0_LLAddr_shift;
15094 ctx->cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1;
15095 /* Restore delay slot state from the tb context. */
15095 - ctx->hflags = (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */
15096 + ctx->hflags = tb_flags & MIPS_HFLAG_TB_MASK;
15097 ctx->ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1;
15098 ctx->ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) ||
15099 (env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F));
@@ -15112,6 +15113,9 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
15113 ctx->default_tcg_memop_mask = (!(ctx->insn_flags & ISA_NANOMIPS32) &&
15114 (ctx->insn_flags & (ISA_MIPS_R6 |
15115 INSN_LOONGSON3A))) ? MO_UNALN : MO_ALIGN;
15116 + if (tb_flags & TB_FLAG_MIPS_FIXADE) {
15117 + ctx->default_tcg_memop_mask = MO_UNALN;
15118 + }
15119
15120 /*
15121 * Execute a branch and its delay slot as a single instruction.