From f98595bee582edb6c2d40a377ac7c05a82110919 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 2 Sep 2021 18:14:26 +0300 Subject: [PATCH] Patches/PPU: Add jump_link patch type --- Utilities/bin_patch.cpp | 6 ++++-- Utilities/bin_patch.h | 1 + rpcs3/Emu/Cell/PPUModule.cpp | 2 +- rpcs3/Emu/Cell/PPUThread.cpp | 32 +++++++++++++++++++------------- rpcs3/Emu/Cell/PPUTranslator.cpp | 5 +++-- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp index c217ddb77b..ac120104b9 100644 --- a/Utilities/bin_patch.cpp +++ b/Utilities/bin_patch.cpp @@ -40,6 +40,7 @@ void fmt_class_string::format(std::string& out, u64 arg) case patch_type::alloc: return "alloc"; case patch_type::code_alloc: return "calloc"; case patch_type::jump: return "jump"; + case patch_type::jump_link: return "jumpl"; case patch_type::load: return "load"; case patch_type::byte: return "byte"; case patch_type::le16: return "le16"; @@ -551,7 +552,7 @@ void patch_engine::append_title_patches(const std::string& title_id) } void ppu_register_range(u32 addr, u32 size); -bool ppu_form_branch_to_code(u32 entry, u32 target); +bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false); void unmap_vm_area(std::shared_ptr& ptr) { @@ -737,12 +738,13 @@ static usz apply_modification(std::basic_string& applied, const patch_engin break; } case patch_type::jump: + case patch_type::jump_link: { const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first; const u32 dest = static_cast(p.value.long_value); // Allow only if points to a PPU executable instruction - if (!ppu_form_branch_to_code(out_branch, dest)) + if (!ppu_form_branch_to_code(out_branch, dest, p.type == patch_type::jump_link)) { continue; } diff --git a/Utilities/bin_patch.h b/Utilities/bin_patch.h index 972dad8a73..b4b1680b8b 100644 --- a/Utilities/bin_patch.h +++ b/Utilities/bin_patch.h @@ -29,6 +29,7 @@ enum class patch_type alloc, // Allocate memory at address (zeroized executable memory) code_alloc,// Allocate memory somewhere, saves branch to memory at specfied address (filled with PPU NOP and branch for returning) jump, // Install special 32-bit jump instruction (PPU only atm) + jump_link, // jump + set link (PPU only atm) byte, le16, le32, diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 221f883be2..634f9b1f1e 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -528,7 +528,7 @@ struct ppu_prx_module_info be_t unk5; }; -bool ppu_form_branch_to_code(u32 entry, u32 target); +bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false); // Load and register exports; return special exports found (nameless module) static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index b3a46f1d63..4aff0f09d7 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -487,11 +487,11 @@ extern void ppu_register_function_at(u32 addr, u32 size, u64 ptr) struct ppu_far_jumps_t { - std::unordered_map vals; + std::unordered_map> vals; mutable shared_mutex mutex; - u32 get_target(u32 pc) const + std::pair get_target(u32 pc) const { reader_lock lock(mutex); @@ -500,23 +500,25 @@ struct ppu_far_jumps_t return it->second; } - return 0; + return {}; } }; u32 ppu_get_far_jump(u32 pc) { g_fxo->init(); - return g_fxo->get().get_target(pc); + return g_fxo->get().get_target(pc).first; } static bool ppu_far_jump(ppu_thread& ppu) { - ppu.cia = g_fxo->get().get_target(ppu.cia); + auto [cia, link] = g_fxo->get().get_target(ppu.cia); + if (link) ppu.lr = ppu.cia + 4; + ppu.cia = cia; return false; } -bool ppu_form_branch_to_code(u32 entry, u32 target) +bool ppu_form_branch_to_code(u32 entry, u32 target, bool link) { entry &= -4; target &= -4; @@ -532,7 +534,7 @@ bool ppu_form_branch_to_code(u32 entry, u32 target) auto& jumps = g_fxo->get(); std::lock_guard lock(jumps.mutex); - jumps.vals.insert_or_assign(entry, target); + jumps.vals.insert_or_assign(entry, std::make_pair(target, link)); ppu_register_function_at(entry, 4, &ppu_far_jump); return true; @@ -691,7 +693,7 @@ std::array op_branch_targets(u32 pc, ppu_opcode_t op) g_fxo->need(); - if (u32 target = g_fxo->get().get_target(pc)) + if (u32 target = g_fxo->get().get_target(pc).first) { res[0] = target; return res; @@ -3253,9 +3255,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only) if (!func.size) continue; const auto name = fmt::format("__0x%x", func.addr - reloc); - const u64 addr = ensure(jit->get(name)); - jit_mod.funcs.emplace_back(reinterpret_cast(addr)); - ppu_register_function_at(func.addr, 4, jit_mod.funcs.back()); + const auto addr = ensure(reinterpret_cast(jit->get(name))); + jit_mod.funcs.emplace_back(addr); + + if (ppu_ref(func.addr) != reinterpret_cast(ppu_far_jump)) + ppu_register_function_at(func.addr, 4, addr); if (g_cfg.core.ppu_debug) ppu_log.notice("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc); @@ -3272,8 +3276,10 @@ bool ppu_initialize(const ppu_module& info, bool check_only) { if (!func.size) continue; - const u64 addr = ensure(reinterpret_cast(jit_mod.funcs[index++])); - ppu_ref(func.addr) = (addr & 0x7fff'ffff'ffffu) | (ppu_ref(func.addr) & ~0x7fff'ffff'ffffu); + const u64 addr = reinterpret_cast(ensure(jit_mod.funcs[index++])); + + if (ppu_ref(func.addr) != reinterpret_cast(ppu_far_jump)) + ppu_register_function_at(func.addr, 4, addr); if (g_cfg.core.ppu_debug) ppu_log.notice("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc); diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 5697e33e05..1ee0d8e759 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -234,10 +234,11 @@ Function* PPUTranslator::Translate(const ppu_function& info) m_rel = nullptr; } - if (u32 target = ppu_get_far_jump(m_addr + base)) + if (ppu_get_far_jump(m_addr + base)) { + // Branch into an HLEd instruction using the jump table FlushRegisters(); - CallFunction(0, m_ir->getInt64(target)); + CallFunction(0, m_reloc ? m_ir->CreateAdd(m_ir->getInt64(m_addr), m_seg0) : m_ir->getInt64(m_addr)); continue; }