From af85fc7c76d144511ff61b70b68cf45a3831b694 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Wed, 1 Jul 2026 20:50:05 +0200 Subject: [PATCH] ppc: flush QEMU JIT after 68k cache changes OS3.x/WarpOS can patch PPC code and page tables from the m68k side in shared RAM. QEMU does not see those writes through the PPC softmmu, so stale translation blocks can survive until the m68k/PPC handoff deadlocks. Import the optional ppc_cpu_flush_jit hook, mark QEMU PPC code cache state dirty on 68040 instruction-cache and MMU ATC flushes, and consume one coalesced flush at the next m68k-to-PPC handoff. Skip the flush while the m68k is halted so PPC-only OS4 execution is not forced to retranslate continuously. --- cpummu.cpp | 6 ++++++ include/uae/ppc.h | 2 ++ newcpu.cpp | 5 +++++ ppc/ppc.cpp | 27 +++++++++++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/cpummu.cpp b/cpummu.cpp index 4e6d4f8d..6a371ed6 100644 --- a/cpummu.cpp +++ b/cpummu.cpp @@ -32,6 +32,9 @@ #include "newcpu.h" #include "cpummu.h" #include "debug.h" +#ifdef WITH_PPC +#include "uae/ppc.h" +#endif #define MMUDUMP 1 @@ -1403,6 +1406,9 @@ void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra) mmu_flush_atc(addr, super, glob); } flush_internals(); +#ifdef WITH_PPC + uae_ppc_mark_code_cache_dirty(); +#endif #ifdef USE_JIT flush_icache(0); #endif diff --git a/include/uae/ppc.h b/include/uae/ppc.h index e1e9982b..621f3d8a 100644 --- a/include/uae/ppc.h +++ b/include/uae/ppc.h @@ -47,6 +47,7 @@ void uae_ppc_wakeup_main(void); void uae_ppc_execute_quick(void); void uae_ppc_execute_check(void); +void uae_ppc_mark_code_cache_dirty(void); void uae_ppc_spinlock_reset(void); void uae_ppc_spinlock_get(void); void uae_ppc_spinlock_release(void); @@ -108,6 +109,7 @@ void PPCCALL ppc_cpu_stop(void); void PPCCALL ppc_cpu_atomic_raise_ext_exception(void); void PPCCALL ppc_cpu_atomic_cancel_ext_exception(void); void PPCCALL ppc_cpu_map_memory(PPCMemoryRegion *regions, int count); +void PPCCALL ppc_cpu_flush_jit(void); void PPCCALL ppc_cpu_set_pc(int cpu, uint32_t value); void PPCCALL ppc_cpu_run_continuous(void); void PPCCALL ppc_cpu_run_single(int count); diff --git a/newcpu.cpp b/newcpu.cpp index ea536cb1..445f1a42 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -1779,6 +1779,11 @@ void flush_cpu_caches_040(uae_u16 opcode) bool pushinv = (regs.cacr & 0x01000000) == 0; // 68060 DPI flush_cpu_caches_040_2(cache, scope, addr, push, pushinv); +#ifdef WITH_PPC + if (cache & 2) { + uae_ppc_mark_code_cache_dirty(); + } +#endif mmu_flush_cache(); } diff --git a/ppc/ppc.cpp b/ppc/ppc.cpp index 4ec0953b..bbb787ce 100644 --- a/ppc/ppc.cpp +++ b/ppc/ppc.cpp @@ -6,6 +6,7 @@ #include "threaddep/thread.h" #include "machdep/rpt.h" #include "memory.h" +#include "newcpu.h" #include "cpuboard.h" #include "debug.h" #include "custom.h" @@ -41,6 +42,7 @@ static volatile int spinlock_cnt; #endif static volatile bool ppc_spinlock_waiting; +static volatile bool qemu_ppc_jit_flush_pending; #ifdef WIN32_SPINLOCK #define CRITICAL_SECTION_SPIN_COUNT 5000 @@ -157,6 +159,7 @@ typedef void (PPCCALL *ppc_cpu_pause_function)(int pause); typedef bool (PPCCALL *ppc_cpu_check_state_function)(int state); typedef void (PPCCALL *ppc_cpu_set_state_function)(int state); typedef void (PPCCALL *ppc_cpu_reset_function)(void); +typedef void (PPCCALL *ppc_cpu_flush_jit_function)(void); /* Function pointers to active PPC implementation */ @@ -182,6 +185,7 @@ static struct impl { ppc_cpu_check_state_function check_state; ppc_cpu_set_state_function set_state; ppc_cpu_reset_function reset; + ppc_cpu_flush_jit_function flush_jit; qemu_uae_ppc_in_cpu_thread_function in_cpu_thread; qemu_uae_ppc_external_interrupt_function external_interrupt; qemu_uae_lock_function lock; @@ -248,6 +252,10 @@ static bool load_qemu_implementation(void) impl.check_state = (ppc_cpu_check_state_function) uae_dlsym(handle, "ppc_cpu_check_state"); impl.set_state = (ppc_cpu_set_state_function) uae_dlsym(handle, "ppc_cpu_set_state"); impl.reset = (ppc_cpu_reset_function) uae_dlsym(handle, "ppc_cpu_reset"); + impl.flush_jit = (ppc_cpu_flush_jit_function) uae_dlsym(handle, "ppc_cpu_flush_jit"); + if (impl.flush_jit) { + write_log(_T("PPC: Imported optional ppc_cpu_flush_jit\n")); + } impl.in_cpu_thread = (qemu_uae_ppc_in_cpu_thread_function) uae_dlsym(handle, "qemu_uae_ppc_in_cpu_thread"); impl.lock = (qemu_uae_lock_function) uae_dlsym(handle, "qemu_uae_lock"); @@ -312,6 +320,22 @@ static bool using_pearpc(void) return ppc_implementation == PPC_IMPLEMENTATION_PEARPC; } +void uae_ppc_mark_code_cache_dirty(void) +{ + qemu_ppc_jit_flush_pending = true; +} + +static void request_qemu_ppc_jit_flush(void) +{ + /* OS3.x/WarpOS can patch PPC code/page tables from the m68k side, + * bypassing QEMU's PPC softmmu. Flush once at the next m68k->PPC handoff. */ + if (!qemu_ppc_jit_flush_pending || !using_qemu() || !impl.flush_jit || regs.halted) { + return; + } + qemu_ppc_jit_flush_pending = false; + impl.flush_jit(); +} + enum PPCLockMethod { PPC_RELEASE_SPINLOCK, PPC_KEEP_SPINLOCK, @@ -599,6 +623,7 @@ static void uae_ppc_cpu_reset(void) if (using_qemu()) { impl.reset(); + qemu_ppc_jit_flush_pending = true; } else if (using_pearpc()) { write_log(_T("PPC: Init\n")); impl.set_pc(0, 0xfff00100); @@ -627,6 +652,7 @@ static void ppc_thread(void *v) void uae_ppc_execute_check(void) { if (ppc_spinlock_waiting) { + request_qemu_ppc_jit_flush(); uae_ppc_spinlock_release(); uae_ppc_spinlock_get(); } @@ -634,6 +660,7 @@ void uae_ppc_execute_check(void) void uae_ppc_execute_quick() { + request_qemu_ppc_jit_flush(); uae_ppc_spinlock_release(); sleep_millis_main(1); uae_ppc_spinlock_get(); -- 2.47.3