diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp index 646514ed27..b2b464081c 100644 --- a/Utilities/bin_patch.cpp +++ b/Utilities/bin_patch.cpp @@ -505,39 +505,26 @@ void patch_engine::append_title_patches(const std::string& title_id) load(m_map, get_patches_path() + title_id + "_patch.yml"); } -std::basic_string patch_engine::apply(const std::string& name, u8* dst) -{ - return apply_patch(name, dst, 0, 0); -} - -std::basic_string patch_engine::apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr) -{ - return apply_patch(name, dst, filesz, ls_addr); -} - -template -static std::basic_string apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 ls_addr) +static std::basic_string apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 min_addr) { std::basic_string applied; for (const auto& p : patch.data_list) { u32 offset = p.offset; - u32 resval = 0; - if constexpr (CheckLS) + if (offset < min_addr || offset - min_addr >= filesz) { - if (offset < ls_addr || offset >= (ls_addr + filesz)) - { - // This patch is out of range for this segment - continue; - } - - offset -= ls_addr; + // This patch is out of range for this segment + continue; } + offset -= min_addr; + auto ptr = dst + offset; + u32 resval = -1; + switch (p.type) { case patch_type::invalid: @@ -584,10 +571,7 @@ static std::basic_string apply_modification(const patch_engine::patch_info& case patch_type::be32: { *reinterpret_cast*>(ptr) = static_cast(p.value.long_value); - - // Possibly an executable instruction - if constexpr (!CheckLS) - resval = offset; + if (offset % 4 == 0) resval = offset; break; } case patch_type::bef32: @@ -598,6 +582,14 @@ static std::basic_string apply_modification(const patch_engine::patch_info& case patch_type::be64: { *reinterpret_cast*>(ptr) = static_cast(p.value.long_value); + + if (offset % 4) + { + break; + } + + resval = offset; + applied.push_back((offset + 7) & -4); // Two 32-bit locations break; } case patch_type::bef64: @@ -607,14 +599,14 @@ static std::basic_string apply_modification(const patch_engine::patch_info& } } + // Possibly an executable instruction applied.push_back(resval); } return applied; } -template -std::basic_string patch_engine::apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr) +std::basic_string patch_engine::apply(const std::string& name, u8* dst, u32 filesz, u32 min_addr) { if (m_map.find(name) == m_map.cend()) { @@ -719,7 +711,7 @@ std::basic_string patch_engine::apply_patch(const std::string& name, u8* ds m_applied_groups.insert(patch.patch_group); } - auto applied = apply_modification(patch, dst, filesz, ls_addr); + auto applied = apply_modification(patch, dst, filesz, min_addr); applied_total += applied; diff --git a/Utilities/bin_patch.h b/Utilities/bin_patch.h index 0a8e5d64fe..b7a39d8ee3 100644 --- a/Utilities/bin_patch.h +++ b/Utilities/bin_patch.h @@ -129,16 +129,9 @@ public: void append_title_patches(const std::string& title_id); // Apply patch (returns the number of entries applied) - std::basic_string apply(const std::string& name, u8* dst); - - // Apply patch with a check that the address exists in SPU local storage - std::basic_string apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr); + std::basic_string apply(const std::string& name, u8* dst, u32 filesz = UINT32_MAX, u32 min_addr = 0); private: - // Internal: Apply patch (returns the number of entries applied) - template - std::basic_string apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr); - // Database patch_map m_map; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 03866ce38d..f4532111bf 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -315,18 +315,18 @@ static void ppu_initialize_modules(ppu_linkage_info* link) ppu_loader.trace("** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); // Allocate HLE variable - if (variable.second.size >= 4096 || variable.second.align >= 4096) + if (variable.second.size >= 0x10000 || variable.second.align >= 0x10000) { variable.second.addr = vm::alloc(variable.second.size, vm::main, std::max(variable.second.align, 0x10000)); } else { const u32 next = utils::align(alloc_addr, variable.second.align); - const u32 end = next + variable.second.size; + const u32 end = next + variable.second.size - 1; - if (!next || (end >> 12 != alloc_addr >> 12)) + if (!next || (end >> 16 != alloc_addr >> 16)) { - alloc_addr = vm::alloc(4096, vm::main); + alloc_addr = vm::alloc(0x10000, vm::main); } else { @@ -773,12 +773,12 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg) for (const auto& prog : obj.progs) { // Apply the patch - applied += g_fxo->get()->apply_with_ls_check(hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr); + applied += g_fxo->get()->apply(hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr); if (!Emu.GetTitleID().empty()) { // Alternative patch - applied += g_fxo->get()->apply_with_ls_check(Emu.GetTitleID() + '-' + hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr); + applied += g_fxo->get()->apply(Emu.GetTitleID() + '-' + hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr); } } @@ -1084,21 +1084,33 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri sha1_finish(&sha, prx->sha1); // Format patch name - std::string hash("PRX-0000000000000000000000000000000000000000"); - for (u32 i = 0; i < 20; i++) - { - constexpr auto pal = "0123456789abcdef"; - hash[4 + i * 2] = pal[prx->sha1[i] >> 4]; - hash[5 + i * 2] = pal[prx->sha1[i] & 15]; - } + std::string hash = fmt::format("PRX-%s", fmt::base57(prx->sha1)); - // Apply the patch - auto applied = g_fxo->get()->apply(hash, vm::g_base_addr); + std::basic_string applied; - if (!Emu.GetTitleID().empty()) + for (usz i = 0; i < prx->segs.size(); i++) { - // Alternative patch - applied += g_fxo->get()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr); + const auto& seg = prx->segs[i]; + + if (!seg.size) continue; + + const std::string hash_seg = fmt::format("%s-%u", hash, i); + + // Apply the patch + auto _applied = g_fxo->get()->apply(hash_seg, vm::get_super_ptr(seg.addr), seg.size); + + if (!Emu.GetTitleID().empty()) + { + // Alternative patch + _applied += g_fxo->get()->apply(Emu.GetTitleID() + '-' + hash_seg, vm::get_super_ptr(seg.addr), seg.size); + } + + // Rebase patch offsets + std::for_each(_applied.begin(), _applied.end(), [&](u32& res) { if (res != umax) res += seg.addr; }); + + applied += _applied; + + ppu_loader.success("PRX library hash: %s (<- %u)", hash_seg, _applied.size()); } // Embedded SPU elf patching @@ -1109,8 +1121,6 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri prx->analyse(toc, 0, end, applied); - ppu_loader.success("PRX library hash: %s (<- %u)", hash, applied.size()); - try_spawn_ppu_if_exclusive_program(*prx); return prx; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index b2dd6bcbbb..4fdadf4c39 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -385,15 +385,16 @@ extern void ppu_register_range(u32 addr, u32 size) return; } + size = utils::align(size + addr % 0x10000, 0x10000); + addr &= -0x10000; + // Register executable range at - utils::memory_commit(&ppu_ref(addr), size * 2, utils::protection::rw); - vm::page_protect(addr, utils::align(size, 0x10000), 0, vm::page_executable); + utils::memory_commit(&ppu_ref(addr), u64{size} * 2, utils::protection::rw); + vm::page_protect(addr, size, 0, vm::page_executable); const u64 fallback = reinterpret_cast(ppu_fallback); const u64 seg_base = addr; - size &= ~3; // Loop assumes `size = n * 4`, enforce that by rounding down - while (size) { if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)