ppc currently silently accepts invalid real address access. Catch these and turn them into machine checks. POWER9/10 machine check codes for invalid real address access are implemented.
Signed-off-by: Nicholas Piggin <npig...@gmail.com> --- target/ppc/cpu_init.c | 1 + target/ppc/excp_helper.c | 35 +++++++++++++++++++++++++++++++++++ target/ppc/internal.h | 5 +++++ 3 files changed, 41 insertions(+) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 7bce421a7c..3b23f2d5b6 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7267,6 +7267,7 @@ static const struct TCGCPUOps ppc_tcg_ops = { .cpu_exec_enter = ppc_cpu_exec_enter, .cpu_exec_exit = ppc_cpu_exec_exit, .do_unaligned_access = ppc_cpu_do_unaligned_access, + .do_transaction_failed = ppc_cpu_do_transaction_failed, #endif /* !CONFIG_USER_ONLY */ }; #endif /* CONFIG_TCG */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 12d8a7257b..c9bfa3a827 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1402,7 +1402,9 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) /* machine check exceptions don't have ME set */ new_msr &= ~((target_ulong)1 << MSR_ME); + msr |= env->error_code; break; + case POWERPC_EXCP_DSI: /* Data storage exception */ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); break; @@ -3123,5 +3125,38 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, env->error_code = insn & 0x03FF0000; cpu_loop_exit(cs); } + +void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr vaddr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr) +{ + CPUPPCState *env = cs->env_ptr; + + switch (env->excp_model) { +#if defined(TARGET_PPC64) + case POWERPC_EXCP_970: + case POWERPC_EXCP_POWER7: + case POWERPC_EXCP_POWER8: + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + /* + * TODO: This does not give the correct machine check code but + * it will report a NIP and DAR. + */ + if (access_type == MMU_DATA_LOAD || access_type == MMU_DATA_STORE) { + env->spr[SPR_DAR] = vaddr; + } + break; +#endif + default: + /* TODO: Check behaviour for other CPUs, for now do nothing. */ + return; + } + + cs->exception_index = POWERPC_EXCP_MCHECK; + cpu_loop_exit_restore(cs, retaddr); +} #endif /* CONFIG_TCG */ #endif /* !CONFIG_USER_ONLY */ diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 901bae6d39..57acb3212c 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -296,6 +296,11 @@ bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, G_NORETURN void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); +void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr); #endif FIELD(GER_MSK, XMSK, 0, 4) -- 2.40.1