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>
case EXCP_DSPDIS:
force_sig(TARGET_SIGILL);
break;
+ case EXCP_AdEL:
+ case EXCP_AdES:
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
+ env->CP0_BadVAddr);
+ break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
#define TARGET_FORCE_SHMLBA
#define TARGET_SYSMIPS_FLUSH_CACHE 3
+#define TARGET_SYSMIPS_FIXADE 7
#define TARGET_SYSMIPS_ATOMIC_SET 2001
static inline abi_ulong target_shmlba(CPUMIPSState *env)
#define TARGET_FORCE_SHMLBA
#define TARGET_SYSMIPS_FLUSH_CACHE 3
+#define TARGET_SYSMIPS_FIXADE 7
#define TARGET_SYSMIPS_ATOMIC_SET 2001
static inline abi_ulong target_shmlba(CPUMIPSState *env)
static abi_long do_sysmips(CPUArchState *env, abi_long cmd, abi_long arg1,
abi_long arg2)
{
+ CPUState *cs = env_cpu(env);
+
switch (cmd) {
case TARGET_SYSMIPS_ATOMIC_SET:
return do_sysmips_atomic_set(env, arg1, arg2);
+ case TARGET_SYSMIPS_FIXADE:
+ if (arg1 & ~3) {
+ return -TARGET_EINVAL;
+ }
+ cs->prctl_unalign_sigbus = !(arg1 & 1);
+ return 0;
case TARGET_SYSMIPS_FLUSH_CACHE:
return 0;
default:
static TCGTBCPUState mips_get_tb_cpu_state(CPUState *cs)
{
CPUMIPSState *env = cpu_env(cs);
+ uint32_t flags = env->hflags & MIPS_HFLAG_TB_MASK;
+
+#ifdef CONFIG_USER_ONLY
+ if (!cs->prctl_unalign_sigbus) {
+ flags |= TB_FLAG_MIPS_FIXADE;
+ }
+#endif
return (TCGTBCPUState){
.pc = env->active_tc.PC,
- .flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK |
- MIPS_HFLAG_HWRENA_ULR),
+ .flags = flags,
};
}
#define MIPS_HFLAG_ELPA 0x4000000
#define MIPS_HFLAG_ITC_CACHE 0x8000000 /* CACHE instr. operates on ITC tag */
#define MIPS_HFLAG_ERL 0x10000000 /* error level flag */
+#define MIPS_HFLAG_TB_MASK (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | \
+ MIPS_HFLAG_HWRENA_ULR)
+
+#define TB_FLAG_MIPS_FIXADE 0x40000000
target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUMIPSState *env = cpu_env(cs);
+ uint32_t tb_flags = ctx->base.tb->flags;
ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
ctx->saved_pc = -1;
ctx->CP0_LLAddr_shift = env->CP0_LLAddr_shift;
ctx->cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1;
/* Restore delay slot state from the tb context. */
- ctx->hflags = (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */
+ ctx->hflags = tb_flags & MIPS_HFLAG_TB_MASK;
ctx->ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1;
ctx->ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) ||
(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F));
ctx->default_tcg_memop_mask = (!(ctx->insn_flags & ISA_NANOMIPS32) &&
(ctx->insn_flags & (ISA_MIPS_R6 |
INSN_LOONGSON3A))) ? MO_UNALN : MO_ALIGN;
+ if (tb_flags & TB_FLAG_MIPS_FIXADE) {
+ ctx->default_tcg_memop_mask = MO_UNALN;
+ }
/*
* Execute a branch and its delay slot as a single instruction.