diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 9cb3940de0..50cd4f908f 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -13,6 +13,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/CoreTiming.h" #include "Core/HLE/HLE.h" #include "Core/HW/GPFifo.h" #include "Core/HW/Memmap.h" @@ -62,7 +63,10 @@ void JitArm64::Init() analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_FOLLOW); - m_enable_blr_optimization = true; + + m_enable_blr_optimization = jo.enableBlocklink && SConfig::GetInstance().bFastmem && + !SConfig::GetInstance().bEnableDebugging; + m_cleanup_after_stackfault = false; AllocStack(); GenerateAsm(); @@ -70,6 +74,53 @@ void JitArm64::Init() m_supports_cycle_counter = HasCycleCounters(); } +bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) +{ + // We can't handle any fault from other threads. + if (!Core::IsCPUThread()) + { + ERROR_LOG(DYNA_REC, "Exception handler - Not on CPU thread"); + DoBacktrace(access_address, ctx); + return false; + } + + bool success = false; + + // Handle BLR stack faults, may happen in C++ code. + uintptr_t stack = (uintptr_t)m_stack_base; + uintptr_t diff = access_address - stack; + if (diff >= GUARD_OFFSET && diff < GUARD_OFFSET + GUARD_SIZE) + success = HandleStackFault(); + + // If the fault is in JIT code space, look for fastmem areas. + if (!success && IsInSpace((u8*)ctx->CTX_PC)) + success = HandleFastmemFault(access_address, ctx); + + if (!success) + { + ERROR_LOG(DYNA_REC, "Exception handler - Unhandled fault"); + DoBacktrace(access_address, ctx); + } + return success; +} + +bool JitArm64::HandleStackFault() +{ + if (!m_enable_blr_optimization) + return false; + + ERROR_LOG(POWERPC, "BLR cache disabled due to excessive BL in the emulated program."); + m_enable_blr_optimization = false; +#ifndef _WIN32 + Common::UnWriteProtectMemory(m_stack_base + GUARD_OFFSET, GUARD_SIZE); +#endif + GetBlockCache()->InvalidateICache(0, 0xffffffff, true); + CoreTiming::ForceExceptionCheck(0); + m_cleanup_after_stackfault = true; + + return true; +} + void JitArm64::ClearCache() { m_fault_to_handler.clear(); @@ -550,6 +601,16 @@ void JitArm64::SingleStep() void JitArm64::Jit(u32) { + if (m_cleanup_after_stackfault) + { + ClearCache(); + m_cleanup_after_stackfault = false; +#ifdef _WIN32 + // The stack is in an invalid state with no guard page, reset it. + _resetstkoflw(); +#endif + } + if (IsAlmostFull() || farcode.IsAlmostFull() || SConfig::GetInstance().bJITNoBlockCache) { ClearCache(); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index e0613f82b9..bf2bdc4a47 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -29,6 +29,9 @@ public: JitBaseBlockCache* GetBlockCache() override { return &blocks; } bool IsInCodeSpace(const u8* ptr) const { return IsInSpace(ptr); } bool HandleFault(uintptr_t access_address, SContext* ctx) override; + void DoBacktrace(uintptr_t access_address, SContext* ctx); + bool HandleStackFault() override; + bool HandleFastmemFault(uintptr_t access_address, SContext* ctx); void ClearCache() override; @@ -188,6 +191,7 @@ private: bool m_supports_cycle_counter; bool m_enable_blr_optimization; + bool m_cleanup_after_stackfault = false; u8* m_stack_base = nullptr; u8* m_stack_pointer = nullptr; u8* m_saved_stack_pointer = nullptr; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp index 8f069389f4..209d3cffe4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp @@ -17,7 +17,7 @@ using namespace Arm64Gen; -static void DoBacktrace(uintptr_t access_address, SContext* ctx) +void JitArm64::DoBacktrace(uintptr_t access_address, SContext* ctx) { for (int i = 0; i < 30; i += 2) ERROR_LOG(DYNA_REC, "R%d: 0x%016llx\tR%d: 0x%016llx", i, ctx->CTX_REG(i), i + 1, @@ -283,17 +283,8 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR } } -bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) +bool JitArm64::HandleFastmemFault(uintptr_t access_address, SContext* ctx) { - if (!IsInSpace((u8*)ctx->CTX_PC)) - { - ERROR_LOG(DYNA_REC, "Backpatch location not within codespace 0x%016llx(0x%08x)", ctx->CTX_PC, - Common::swap32(*(u32*)ctx->CTX_PC)); - - DoBacktrace(access_address, ctx); - return false; - } - if (!(access_address >= (uintptr_t)Memory::physical_base && access_address < (uintptr_t)Memory::physical_base + 0x100010000) && !(access_address >= (uintptr_t)Memory::logical_base && @@ -302,8 +293,6 @@ bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) ERROR_LOG(DYNA_REC, "Exception handler - access below memory space. PC: 0x%016llx 0x%016lx < 0x%016lx", ctx->CTX_PC, access_address, (uintptr_t)Memory::physical_base); - - DoBacktrace(access_address, ctx); return false; }