diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 693ad8c7ea..8d6486c9a4 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -145,6 +145,7 @@ struct ppu_module : public Type std::shared_ptr> jit_bounds; // JIT instance modules addresses range std::unordered_map imports; // Imports information for release upon unload (TODO: OVL implementation!) std::map>> stub_addr_to_constant_state_of_registers; // Tells possible constant states of registers of functions + std::vector excluded_funcs; // Function code not be overwritten bool is_relocatable = false; // Is code relocatable(?) template diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index dbc2f04c0b..6ae204a375 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -934,13 +934,40 @@ struct ppu_far_jumps_t ppu_far_jumps_t(int) noexcept {} std::map vals; + std::pair vals_range{0, 0}; ::jit_runtime rt; mutable shared_mutex mutex; + void add_value(u32 addr, all_info_t info) + { + vals.insert_or_assign(addr, std::move(info)); + + if (vals.size() == 1) + { + vals_range.first = addr; + vals_range.second = addr; + } + else + { + vals_range.first = std::min(vals_range.first, addr); + vals_range.second = std::max(vals_range.second, addr); + } + } + // Get target address, 'ppu' is used in ppu_far_jump in order to modify registers u32 get_target(u32 pc, ppu_thread* ppu = nullptr) { + if (vals_range.first > pc) + { + return 0; + } + + if (vals_range.second < pc) + { + return 0; + } + reader_lock lock(mutex); if (auto it = vals.find(pc); it != vals.end()) @@ -949,7 +976,7 @@ struct ppu_far_jumps_t return all_info.get_target(pc, ppu); } - return {}; + return 0; } // Get function patches in range (entry -> target) @@ -957,6 +984,16 @@ struct ppu_far_jumps_t { std::vector> targets; + if (vals_range.first >= pc + size) + { + return targets; + } + + if (vals_range.second < pc) + { + return targets; + } + reader_lock lock(mutex); auto it = vals.lower_bound(pc); @@ -1110,7 +1147,7 @@ bool ppu_form_branch_to_code(u32 entry, u32 target, bool link, bool with_toc, st auto& jumps = g_fxo->get(); std::lock_guard lock(jumps.mutex); - jumps.vals.insert_or_assign(entry, ppu_far_jumps_t::all_info_t{target, link, with_toc, std::move(module_name)}); + jumps.add_value(entry, ppu_far_jumps_t::all_info_t{target, link, with_toc, std::move(module_name)}); ppu_register_function_at(entry, 4, g_cfg.core.ppu_decoder == ppu_decoder_type::_static ? &ppu_far_jump : ensure(g_fxo->get().gen_jump(entry))); return true; @@ -5214,6 +5251,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s { // Replace the function with ppu_far_jump fpos++; + part.excluded_funcs.emplace_back(func.addr); continue; } } @@ -5246,6 +5284,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s continue; } + if (std::count(part.excluded_funcs.begin(), part.excluded_funcs.end(), func.addr)) + { + continue; + } + const be_t addr = func.addr - reloc; const be_t size = func.size; sha1_update(&ctx, reinterpret_cast(&addr), sizeof(addr)); @@ -5343,6 +5386,13 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s continue; } + if (g_fxo->is_init() && !g_fxo->get().get_targets(func.addr, func.size).empty()) + { + // Filter out functions with patches + part.excluded_funcs.emplace_back(func.addr); + continue; + } + addrs.emplace_back(func.addr - reloc); } @@ -5779,6 +5829,11 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module { if (func.size) { + if (std::count(module_part.excluded_funcs.begin(), module_part.excluded_funcs.end(), func.addr)) + { + continue; + } + const auto f = cast(_module->getOrInsertFunction(fmt::format("__0x%x", func.addr - reloc), _func).getCallee()); f->setCallingConv(CallingConv::GHC); f->addParamAttr(1, llvm::Attribute::NoAlias); @@ -5834,6 +5889,11 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module if (mod_func.size) { + if (std::count(module_part.excluded_funcs.begin(), module_part.excluded_funcs.end(), mod_func.addr)) + { + continue; + } + num_func++; guest_code_size += mod_func.size; max_addr = std::max(max_addr, mod_func.addr + mod_func.size); diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index b7a6a263ce..0a17de2d0f 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -364,6 +364,12 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) continue; } + if (std::count(info.excluded_funcs.begin(), info.excluded_funcs.end(), f.addr)) + { + // Excluded function (possibly patched) + continue; + } + vec_addrs.push_back(static_cast(f.addr - base)); functions.push_back(cast(m_module->getOrInsertFunction(fmt::format("__0x%x", f.addr - base), ftype).getCallee())); }