diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h index 228c7ffd6e..4dbc1eb4cc 100644 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ b/rpcs3/Emu/Cell/PPUInstrTable.h @@ -663,14 +663,17 @@ namespace PPU_instr { using namespace lists; - //static auto LIS = std::bind(ADDIS, std::placeholders::_1, r0, std::placeholders::_2); - //static auto LI = std::bind(ADDI, std::placeholders::_1, r0, std::placeholders::_2); - static auto NOP = std::bind(ORI, r0, r0, 0); - static auto MR = std::bind(OR, std::placeholders::_1, std::placeholders::_2, std::placeholders::_2, false); - static auto BLR = std::bind(BCLR, 0x10 | 0x04, 0, 0, 0); - static auto BCTR = std::bind(BCCTR, 0x10 | 0x04, 0, 0, 0); - static auto BCTRL = std::bind(BCCTR, 0x10 | 0x04, 0, 0, 1); - static auto MTCTR = std::bind(MTSPR, (0x1 << 5) | 0x8, std::placeholders::_1); + inline u32 LIS(u32 reg, u32 imm) { return ADDIS(reg, r0, imm); } + inline u32 LI_(u32 reg, u32 imm) { return ADDI(reg, r0, imm); } + inline u32 NOP() { return ORI(r0, r0, 0); } + inline u32 MR(u32 x, u32 y) { return OR(x, y, y, false); } + inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0, 0); } + inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0, 0); } + inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, 1); } + inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } + inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } + inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } + inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm, 0, 0); } inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm, 0, 0); } diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index d628dfa0a0..f01ff3dec4 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -417,6 +417,102 @@ void hook_ppu_funcs(vm::ptr base, u32 size) } } +bool patch_ppu_import(u32 addr, u32 index) +{ + const auto data = vm::ptr::make(addr); + + using namespace PPU_instr; + + // check different patterns: + + if (vm::check_addr(addr, 32) && + (data[0] & 0xffff0000) == LI_(r12, 0) && + (data[1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[3] == STD(r2, r1, 0x28) && + data[4] == LWZ(r0, r12, 0) && + data[5] == LWZ(r2, r12, 4) && + data[6] == MTCTR(r0) && + data[7] == BCTR()) + { + vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR)); + return true; + } + + if (vm::check_addr(addr, 12) && + (data[0] & 0xffff0000) == LI_(r0, 0) && + (data[1] & 0xffff0000) == ORIS(r0, r0, 0) && + (data[2] & 0xfc000003) == B(0, 0, 0)) + { + const auto sub = vm::ptr::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2)); + + if (vm::check_addr(sub.addr(), 60) && + sub[0x0] == STDU(r1, r1, -0x80) && + sub[0x1] == STD(r2, r1, 0x70) && + sub[0x2] == MR(r2, r0) && + sub[0x3] == MFLR(r0) && + sub[0x4] == STD(r0, r1, 0x90) && + sub[0x5] == LWZ(r2, r2, 0) && + sub[0x6] == LWZ(r0, r2, 0) && + sub[0x7] == LWZ(r2, r2, 4) && + sub[0x8] == MTCTR(r0) && + sub[0x9] == BCTRL() && + sub[0xa] == LD(r2, r1, 0x70) && + sub[0xb] == ADDI(r1, r1, 0x80) && + sub[0xc] == LD(r0, r1, 0x10) && + sub[0xd] == MTLR(r0) && + sub[0xe] == BLR()) + { + vm::write32(addr, HACK(index | EIF_PERFORM_BLR)); + return true; + } + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LI_(r2, 0) && + (data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) && + data[0x6] == LWZ(r2, r2, 0) && + data[0x7] == LWZ(r0, r2, 0) && + data[0x8] == LWZ(r2, r2, 4) && + data[0x9] == MTCTR(r0) && + data[0xa] == BCTRL() && + data[0xb] == LD(r2, r1, 0x70) && + data[0xc] == ADDI(r1, r1, 0x80) && + data[0xd] == LD(r0, r1, 0x10) && + data[0xe] == MTLR(r0) && + data[0xf] == BLR()) + { + vm::write32(addr, HACK(index | EIF_PERFORM_BLR)); + return true; + } + + if (vm::check_addr(addr, 56) && + (data[0x0] & 0xffff0000) == LI_(r12, 0) && + (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x3] == STD(r2, r1, 0x28) && + data[0x4] == MFLR(r0) && + data[0x5] == STD(r0, r1, 0x20) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r0, r1, 0x20) && + data[0xb] == MTLR(r0) && + data[0xc] == LD(r2, r1, 0x28) && + data[0xd] == BLR()) + { + vm::write32(addr, HACK(index | EIF_PERFORM_BLR)); + return true; + } + + return false; +} + Module::Module(const char* name, void(*init)()) : m_is_loaded(false) , m_name(name) diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 42c679804e..58ea0d9cf7 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -154,6 +154,8 @@ u32 add_ppu_func_sub(const char group[8], const SearchPatternEntry ops[], size_t void hook_ppu_funcs(vm::ptr base, u32 size); +bool patch_ppu_import(u32 addr, u32 index); + #define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, bind_func(name))) #define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, bind_func(name))) diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index fd06566207..d4d6b6b01c 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -465,14 +465,10 @@ namespace loader LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); } - if (!vm::check_addr(addr, 4)) + if (!patch_ppu_import(addr, index)) { LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); } - else - { - vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR)); - } } } } @@ -686,7 +682,10 @@ namespace loader LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr); } - vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR)); + if (!patch_ppu_import(addr, index)) + { + LOG_ERROR(LOADER, "Failed to inject code at address 0x%x", addr); + } //if (!func || !func->lle_func) //{