diff --git a/rpcs3/Emu/Cell/Modules/StaticHLE.cpp b/rpcs3/Emu/Cell/Modules/StaticHLE.cpp new file mode 100644 index 0000000000..ba9f120e55 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/StaticHLE.cpp @@ -0,0 +1,177 @@ +#include "stdafx.h" +#include "StaticHLE.h" + +logs::channel static_hle("static_hle"); + +// for future use +DECLARE(ppu_module_manager::static_hle) ("static_hle", []() +{ +}); + +std::vector> shle_patterns_list +{ + { "2BA5000778630020788400207C6B1B78419D00702C2500004D82002028A5000F", "FF", "36D0", "05C4", "sys_libc", "memcpy" }, + { "2BA5000778630020788400207C6B1B78419D00702C2500004D82002028A5000F", "5C", "87A0", "05C4", "sys_libc", "memcpy" }, + { "2B8500077CA32A14788406207C6A1B78409D009C3903000198830000788B45E4", "B4", "1453", "00D4", "sys_libc", "memset" }, + { "280500087C661B7840800020280500004D8200207CA903A69886000038C60001", "F8", "F182", "0118", "sys_libc", "memset" }, + { "2B8500077CA32A14788406207C6A1B78409D009C3903000198830000788B45E4", "70", "DFDA", "00D4", "sys_libc", "memset" }, + { "7F832000FB61FFD8FBE1FFF8FB81FFE0FBA1FFE8FBC1FFF07C7B1B787C9F2378", "FF", "25B5", "12D4", "sys_libc", "memmove" }, + { "2B850007409D00B07C6923785520077E2F800000409E00ACE8030000E9440000", "FF", "71F1", "0158", "sys_libc", "memcmp" }, + { "280500007CE32050788B0760418200E028850100786A07607C2A580040840210", "FF", "87F2", "0470", "sys_libc", "memcmp" }, + { "2B850007409D00B07C6923785520077E2F800000409E00ACE8030000E9440000", "68", "EF18", "0158", "sys_libc", "memcmp" }, +}; + +statichle_handler::statichle_handler() +{ + load_patterns(); +} + +statichle_handler::~statichle_handler() +{ +} + +bool statichle_handler::load_patterns() +{ + for (int i = 0; i < shle_patterns_list.size(); i++) + { + auto& pattern = shle_patterns_list[i]; + + if (pattern[0].size() != 64) + { + static_hle.error("[%d]:Start pattern length != 64", i); + continue; + } + if (pattern[1].size() != 2) + { + static_hle.error("[%d]:Crc16_length != 2", i); + continue; + } + if (pattern[2].size() != 4) + { + static_hle.error("[d]:Crc16 length != 4", i); + continue; + } + if (pattern[3].size() != 4) + { + static_hle.error("[d]:Total length != 4", i); + continue; + } + + shle_pattern dapat; + + auto char_to_u8 = [&](u8 char1, u8 char2) -> u16 + { + u8 hv, lv; + if (char1 == '.' && char2 == '.') + return 0xFFFF; + + if (char1 == '.' || char2 == '.') + { + static_hle.error("[%d]:Broken byte pattern", i); + return -1; + } + + hv = char1 > '9' ? char1 - 'A' + 10 : char1 - '0'; + lv = char2 > '9' ? char2 - 'A' + 10 : char2 - '0'; + + return (hv << 4) | lv; + }; + + for (int j = 0; j < 32; j++) + dapat.start_pattern[j] = char_to_u8(pattern[0][j * 2], pattern[0][(j * 2) + 1]); + + dapat.crc16_length = char_to_u8(pattern[1][0], pattern[1][1]); + dapat.crc16 = (char_to_u8(pattern[2][0], pattern[2][1]) << 8) | char_to_u8(pattern[2][2], pattern[2][3]); + dapat.total_length = (char_to_u8(pattern[3][0], pattern[3][1]) << 8) | char_to_u8(pattern[3][2], pattern[3][3]); + dapat.module = pattern[4]; + dapat.name = pattern[5]; + + dapat.fnid = ppu_generate_id(dapat.name.c_str()); + + static_hle.success("Added a pattern for %s(id:0x%X)", dapat.name, dapat.fnid); + hle_patterns.push_back(std::move(dapat)); + } + + return true; +} + +#define POLY 0x8408 + +uint16_t statichle_handler::gen_CRC16(const uint8_t* data_p, size_t length) +{ + unsigned char i; + unsigned int data; + + if (length == 0) + return 0; + unsigned int crc = 0xFFFF; + do + { + data = *data_p++; + for (i = 0; i < 8; i++) + { + if ((crc ^ data) & 1) + crc = (crc >> 1) ^ POLY; + else + crc >>= 1; + data >>= 1; + } + } while (--length != 0); + + crc = ~crc; + data = crc; + crc = (crc << 8) | ((data >> 8) & 0xff); + return (unsigned short)(crc); +} + +bool statichle_handler::check_against_patterns(vm::cptr& data, u32 size, u32 addr) +{ + for (auto& pat : hle_patterns) + { + if (size < pat.total_length) + continue; + + // check start pattern + int i = 0; + for (i = 0; i < 32; i++) + { + if (pat.start_pattern[i] == 0xFFFF) + continue; + if (data[i] != pat.start_pattern[i]) + break; + } + + if (i != 32) + continue; + + // start pattern ok, checking middle part + if (pat.crc16_length != 0) + if (gen_CRC16(&data[32], pat.crc16_length) != pat.crc16) + continue; + + // we got a match! + static_hle.success("Found function %s at 0x%x", pat.name, addr); + + // patch the code + const auto smodule = ppu_module_manager::get_module(pat.module); + + if (smodule == nullptr) + { + static_hle.error("Couldn't find module: %s", pat.module); + return false; + } + + const auto sfunc = &smodule->functions.at(pat.fnid); + const u32 target = ppu_function_manager::addr + 8 * sfunc->index; + + // write stub + vm::write32(addr, ppu_instructions::LIS(0, (target&0xFFFF0000)>>16)); + vm::write32(addr+4, ppu_instructions::ORI(0, 0, target&0xFFFF)); + vm::write32(addr+8, ppu_instructions::MTCTR(0)); + vm::write32(addr+12, ppu_instructions::BCTR()); + + return true; + } + + return false; +} diff --git a/rpcs3/Emu/Cell/Modules/StaticHLE.h b/rpcs3/Emu/Cell/Modules/StaticHLE.h new file mode 100644 index 0000000000..6efca51515 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/StaticHLE.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../../Utilities/types.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/PPUOpcodes.h" +#include + +struct shle_pattern +{ + u16 start_pattern[32]; + u8 crc16_length; + u16 crc16; + u16 total_length; + std::string module; + std::string name; + + u32 fnid; +}; + +class statichle_handler +{ +public: + statichle_handler(); + ~statichle_handler(); + + bool load_patterns(); + bool check_against_patterns(vm::cptr& data, u32 size, u32 addr); + +protected: + uint16_t gen_CRC16(const uint8_t* data_p, size_t length); + + std::vector hle_patterns; +}; diff --git a/rpcs3/Emu/Cell/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc.cpp index d876258a22..fa5301e750 100644 --- a/rpcs3/Emu/Cell/Modules/sys_libc.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc.cpp @@ -1,17 +1,43 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/System.h" #include "Emu/Cell/PPUModule.h" LOG_CHANNEL(sys_libc); -void sys_libc_memcpy(vm::ptr dst, vm::cptr src, u32 size) +vm::ptr sys_libc_memcpy(vm::ptr dst, vm::cptr src, u32 size) { sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); ::memcpy(dst.get_ptr(), src.get_ptr(), size); + return dst; +} +vm::ptr sys_libc_memset(vm::ptr dst, s32 value, u32 size) +{ + sys_libc.trace("memset(dst=*0x%x, value=0x%x, size=0x%x)", dst, value, size); + + ::memset(dst.get_ptr(), value, size); + return dst; +} + +vm::ptr sys_libc_memmove(vm::ptr dst, vm::ptr src, u32 size) +{ + sys_libc.trace("memmove(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); + + ::memmove(dst.get_ptr(), src.get_ptr(), size); + return dst; +} + +u32 sys_libc_memcmp(vm::ptr buf1, vm::ptr buf2, u32 size) +{ + sys_libc.trace("memcmp(buf1=*0x%x, buf2=*0x%x, size=0x%x)", buf1, buf2, size); + + return ::memcmp(buf1.get_ptr(), buf2.get_ptr(), size); } DECLARE(ppu_module_manager::sys_libc)("sys_libc", []() { REG_FNID(sys_libc, "memcpy", sys_libc_memcpy)/*.flag(MFF_FORCED_HLE)*/; + REG_FNID(sys_libc, "memset", sys_libc_memset); + REG_FNID(sys_libc, "memmove", sys_libc_memmove); + REG_FNID(sys_libc, "memcmp", sys_libc_memcmp); }); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index d93e9b05a8..bb910c419b 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Utilities/VirtualMemory.h" #include "Utilities/bin_patch.h" #include "Crypto/sha1.h" @@ -14,6 +14,8 @@ #include "Emu/Cell/lv2/sys_prx.h" #include "Emu/Cell/lv2/sys_memory.h" +#include "Emu/Cell/Modules/StaticHLE.h" + #include #include #include @@ -255,6 +257,7 @@ static void ppu_initialize_modules(const std::shared_ptr& link &ppu_module_manager::sysPrxForUser, &ppu_module_manager::sys_libc, &ppu_module_manager::sys_lv2dbg, + &ppu_module_manager::static_hle, }; // Initialize double-purpose fake OPD array for HLE functions @@ -1136,6 +1139,18 @@ void ppu_load_exec(const ppu_exec_object& elf) // Initialize HLE modules ppu_initialize_modules(link); + // Static HLE patching + if (g_cfg.core.hook_functions) + { + auto shle = fxm::get_always(); + + for (u32 i = _main->segs[0].addr; i < (_main->segs[0].addr + _main->segs[0].size); i += 4) + { + vm::cptr _ptr = vm::cast(i); + shle->check_against_patterns(_ptr, (_main->segs[0].addr + _main->segs[0].size) - i, i); + } + } + // Load other programs for (auto& prog : elf.progs) { diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index f4d7efb768..072de3e24d 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -264,6 +264,7 @@ public: static const ppu_static_module sysPrxForUser; static const ppu_static_module sys_libc; static const ppu_static_module sys_lv2dbg; + static const ppu_static_module static_hle; }; template diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 1a8b77a325..e9f3da365f 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -114,6 +114,7 @@ + NotUsing @@ -402,6 +403,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 0f35977044..9e8e56661f 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -752,6 +752,9 @@ Emu\GPU\RSX + + Emu\Cell\Modules + Emu\GPU\RSX\Overlays @@ -1456,6 +1459,9 @@ Emu\GPU\RSX\Common + + Emu\Cell\Modules + Emu\Audio