From 82eb5a03f4713c039a379cedef9b3f7628b177fb Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 3 Nov 2025 20:36:38 +0100 Subject: [PATCH] [core/arm] introduce vtable bouncing (#2943) Basically this just makes functions that go into zero-page or invalid addresses "bounce" back (with a return err of 0) such that it emulates a subroutine returning appropriatedly... this is mainly inspired by [this particular commit](https://git.citron-emu.org/Citron/Emulator/commit/fbb4f5c015d778ed0c8e2d91b01dcdffd7da9681); with the key difference of accounting for the scheduler fucking up some random bs. I don't like this hack but anyways maybe it fixes something? Signed-off-by: lizzie lizzie@eden-emu.dev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2943 Reviewed-by: Maufeat Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/settings.h | 2 +- src/core/hle/kernel/physical_core.cpp | 16 +++++++++++++++- src/qt_common/config/shared_translation.cpp | 4 ++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index b5c8db5cec..2aef8ba85a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -240,7 +240,7 @@ struct Values { Category::Cpu}; SwitchableSetting cpu_accuracy{linkage, CpuAccuracy::Auto, "cpu_accuracy", Category::Cpu}; - + SwitchableSetting vtable_bouncing{linkage, true, "vtable_bouncing", Category::Cpu}; SwitchableSetting use_fast_cpu_time{linkage, false, "use_fast_cpu_time", diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 04f0010688..77cdab76d7 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -103,12 +103,26 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) { const bool data_abort = True(hr & Core::HaltReason::DataAbort); const bool interrupt = True(hr & Core::HaltReason::BreakLoop); + bool may_abort = true; // Ignore aborting virtual functions (for debugging) + if (prefetch_abort && ::Settings::values.vtable_bouncing) { + auto& lock = m_kernel.GlobalSchedulerContext().SchedulerLock(); + lock.Lock(); + Kernel::Svc::ThreadContext ctx; + interface->GetContext(ctx); + LOG_WARNING(Core_ARM, "vtable bouncing {:016X}", ctx.lr); + ctx.pc = ctx.lr; + ctx.r[0] = 0; + interface->SetContext(ctx); + lock.Unlock(); + may_abort = false; + } + // Since scheduling may occur here, we cannot use any cached // state after returning from calls we make. // Notify the debugger and go to sleep if a breakpoint was hit, // or if the thread is unable to continue for any reason. - if (breakpoint || prefetch_abort) { + if (breakpoint || (prefetch_abort && may_abort)) { if (breakpoint) { interface->RewindBreakpointInstruction(); } diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index 2d54fc2a30..b54211142c 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -109,6 +109,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) "cause deadlocks. A range of 77-21000 is recommended.")); INSERT(Settings, cpu_backend, tr("Backend:"), QString()); + INSERT(Settings, vtable_bouncing, + tr("Virtual Table Bouncing"), + tr("Bounces (by emulating a 0-valued return) any functions that triggers a prefetch abort")); + // Cpu Debug // Cpu Unsafe