From 611e721a4de1a9f08c8c5a01f962f15081b17a9e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 15 Jan 2023 12:55:29 +0100 Subject: [PATCH] Jit64: Properly handle backpatching overflowed address calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we would only backpatch overflowed address calculations if the overflow was 0x1000 or less. Now we can handle the full 2 GiB of overflow in both directions. I'm also making equivalent changes to JitArm64's code. This isn't because it needs it – JitArm64 address calculations should never overflow – but because I wanted to get rid of the 0x100001000 inherited from Jit64 that makes even less sense for JitArm64 than for Jit64. --- Source/Core/Core/HW/Memmap.cpp | 16 +++++++++--- Source/Core/Core/HW/Memmap.h | 3 +++ Source/Core/Core/PowerPC/Jit64/Jit.cpp | 24 +++++++++++------ Source/Core/Core/PowerPC/Jit64/Jit.h | 2 +- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 26 +++++++++++++++++-- Source/Core/Core/PowerPC/JitArm64/Jit.h | 2 +- .../PowerPC/JitArm64/JitArm64_BackPatch.cpp | 18 +------------ 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index f17cfd12b1..4911e44896 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -157,6 +157,11 @@ void MemoryManager::Init() m_is_initialized = true; } +bool MemoryManager::IsAddressInFastmemArea(const u8* address) const +{ + return address >= m_fastmem_arena && address < m_fastmem_arena + m_fastmem_arena_size; +} + bool MemoryManager::InitFastmemArena() { // Here we set up memory mappings for fastmem. The basic idea of fastmem is that we reserve 4 GiB @@ -194,15 +199,15 @@ bool MemoryManager::InitFastmemArena() constexpr size_t guard_size = 0x8000'0000; constexpr size_t memory_size = ppc_view_size * 2 + guard_size * 3; - u8* fastmem_arena = m_arena.ReserveMemoryRegion(memory_size); - if (!fastmem_arena) + m_fastmem_arena = m_arena.ReserveMemoryRegion(memory_size); + if (!m_fastmem_arena) { PanicAlertFmt("Memory::InitFastmemArena(): Failed finding a memory base."); return false; } - m_physical_base = fastmem_arena + guard_size; - m_logical_base = fastmem_arena + ppc_view_size + guard_size * 2; + m_physical_base = m_fastmem_arena + guard_size; + m_logical_base = m_fastmem_arena + ppc_view_size + guard_size * 2; for (const PhysicalMemoryRegion& region : m_physical_regions) { @@ -222,6 +227,7 @@ bool MemoryManager::InitFastmemArena() } m_is_fastmem_arena_initialized = true; + m_fastmem_arena_size = memory_size; return true; } @@ -371,6 +377,8 @@ void MemoryManager::ShutdownFastmemArena() m_arena.ReleaseMemoryRegion(); + m_fastmem_arena = nullptr; + m_fastmem_arena_size = 0; m_physical_base = nullptr; m_logical_base = nullptr; diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h index 70b8bb8d82..1873095d25 100644 --- a/Source/Core/Core/HW/Memmap.h +++ b/Source/Core/Core/HW/Memmap.h @@ -72,6 +72,7 @@ public: u32 GetExRamSize() const { return m_exram_size; } u32 GetExRamMask() const { return m_exram_mask; } + bool IsAddressInFastmemArea(const u8* address) const; u8* GetPhysicalBase() const { return m_physical_base; } u8* GetLogicalBase() const { return m_logical_base; } u8* GetPhysicalPageMappingsBase() const { return m_physical_page_mappings_base; } @@ -146,6 +147,8 @@ private: // are used to set up a full GC or Wii memory map in process memory. // In 64-bit, this might point to "high memory" (above the 32-bit limit), // so be sure to load it into a 64-bit register. + u8* m_fastmem_arena = nullptr; + size_t m_fastmem_arena_size = 0; u8* m_physical_base = nullptr; u8* m_logical_base = nullptr; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index c1041a674a..c7e51a9f06 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -227,19 +227,27 @@ bool Jit64::HandleFault(uintptr_t access_address, SContext* ctx) auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); - // TODO: do we properly handle off-the-end? - const auto base_ptr = reinterpret_cast(memory.GetPhysicalBase()); - if (access_address >= base_ptr && access_address < base_ptr + 0x100010000) - return BackPatch(static_cast(access_address - base_ptr), ctx); + if (memory.IsAddressInFastmemArea(reinterpret_cast(access_address))) + { + auto& ppc_state = system.GetPPCState(); + const uintptr_t memory_base = reinterpret_cast( + ppc_state.msr.DR ? memory.GetLogicalBase() : memory.GetPhysicalBase()); - const auto logical_base_ptr = reinterpret_cast(memory.GetLogicalBase()); - if (access_address >= logical_base_ptr && access_address < logical_base_ptr + 0x100010000) - return BackPatch(static_cast(access_address - logical_base_ptr), ctx); + if (access_address < memory_base || access_address >= memory_base + 0x1'0000'0000) + { + WARN_LOG_FMT(DYNA_REC, + "Jit64 address calculation overflowed! Please report if this happens a lot. " + "PC {:#018x}, access address {:#018x}, memory base {:#018x}, MSR.DR {}", + ctx->CTX_PC, access_address, memory_base, ppc_state.msr.DR); + } + + return BackPatch(ctx); + } return false; } -bool Jit64::BackPatch(u32 emAddress, SContext* ctx) +bool Jit64::BackPatch(SContext* ctx) { u8* codePtr = reinterpret_cast(ctx->CTX_PC); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index 525f50e552..521c8f5f35 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -51,7 +51,7 @@ public: bool HandleFault(uintptr_t access_address, SContext* ctx) override; bool HandleStackFault() override; - bool BackPatch(u32 emAddress, SContext* ctx); + bool BackPatch(SContext* ctx); void EnableOptimization(); void EnableBlockLink(); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index bdf28ded86..9d54f56a5c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -123,8 +123,30 @@ bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) 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 && IsInSpace(reinterpret_cast(ctx->CTX_PC))) + { + auto& system = Core::System::GetInstance(); + auto& memory = system.GetMemory(); + + if (memory.IsAddressInFastmemArea(reinterpret_cast(access_address))) + { + auto& ppc_state = system.GetPPCState(); + const uintptr_t memory_base = reinterpret_cast( + ppc_state.msr.DR ? memory.GetLogicalBase() : memory.GetPhysicalBase()); + + if (access_address < memory_base || access_address >= memory_base + 0x1'0000'0000) + { + ERROR_LOG_FMT(DYNA_REC, + "JitArm64 address calculation overflowed. This should never happen! " + "PC {:#018x}, access address {:#018x}, memory base {:#018x}, MSR.DR {}", + ctx->CTX_PC, access_address, memory_base, ppc_state.msr.DR); + } + else + { + success = HandleFastmemFault(ctx); + } + } + } if (!success) { diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 00f761ace9..d7bacb2191 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -33,7 +33,7 @@ public: 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); + bool HandleFastmemFault(SContext* ctx); void ClearCache() override; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp index e32d166be2..3d34afab4d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp @@ -16,13 +16,11 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" -#include "Core/HW/Memmap.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/JitArm64/Jit_Util.h" #include "Core/PowerPC/JitArmCommon/BackPatch.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/System.h" using namespace Arm64Gen; @@ -304,22 +302,8 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, MemAccessMode mode, ARM64Reg RS, } } -bool JitArm64::HandleFastmemFault(uintptr_t access_address, SContext* ctx) +bool JitArm64::HandleFastmemFault(SContext* ctx) { - auto& system = Core::System::GetInstance(); - auto& memory = system.GetMemory(); - - if (!(access_address >= (uintptr_t)memory.GetPhysicalBase() && - access_address < (uintptr_t)memory.GetPhysicalBase() + 0x100010000) && - !(access_address >= (uintptr_t)memory.GetLogicalBase() && - access_address < (uintptr_t)memory.GetLogicalBase() + 0x100010000)) - { - ERROR_LOG_FMT(DYNA_REC, - "Exception handler - access below memory space. PC: {:#018x} {:#018x} < {:#018x}", - ctx->CTX_PC, access_address, (uintptr_t)memory.GetPhysicalBase()); - return false; - } - const u8* pc = reinterpret_cast(ctx->CTX_PC); auto slow_handler_iter = m_fault_to_handler.upper_bound(pc);