diff --git a/Utilities/JIT.cpp b/Utilities/JIT.cpp index 3f279db3d4..4f7e72e2c4 100644 --- a/Utilities/JIT.cpp +++ b/Utilities/JIT.cpp @@ -231,7 +231,6 @@ jit_compiler::jit_compiler(std::unique_ptr&& _module, std::unorder .setErrorStr(&result) .setMCJITMemoryManager(std::make_unique(std::move(table))) .setOptLevel(llvm::CodeGenOpt::Aggressive) - .setRelocationModel(llvm::Reloc::PIC_) .setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Medium : llvm::CodeModel::Large) // TODO .setMCPU(llvm::sys::getHostCPUName()) .create()); diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp index 26ef8ba13c..956dc733cf 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -2022,15 +2022,15 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6 return CELL_SPURS_TASK_ERROR_INVAL; } - const spu_exec_loader loader(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr))); + const spu_exec_object obj(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr))); - if (loader != elf_error::ok) + if (obj != elf_error::ok) { return CELL_SPURS_TASK_ERROR_NOEXEC; } u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM; - for (const auto& prog : loader.progs) + for (const auto& prog : obj.progs) { if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) { @@ -2051,7 +2051,7 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6 } } - for (const auto& prog : loader.progs) + for (const auto& prog : obj.progs) { if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) // ??? { @@ -2067,7 +2067,7 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6 } } - *entryPoint = loader.header.e_entry; + *entryPoint = obj.header.e_entry; if (lowestLoadAddr) *lowestLoadAddr = _lowestLoadAddr; return CELL_OK; diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index a4edaa0e98..d06a307704 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -80,12 +80,231 @@ void ppu_validate(const std::string& fname, const std::vector& fun } } +static u32 ppu_test(const vm::cptr ptr, vm::cptr fend, std::initializer_list pat) +{ + vm::cptr cur = ptr; + + for (auto& p : pat) + { + if (cur >= fend) + { + return 0; + } + + if (*cur == ppu_instructions::NOP()) + { + cur++; + + if (cur >= fend) + { + return 0; + } + } + + if ((*cur & p.mask) != p.opcode) + { + return 0; + } + + cur++; + } + + return cur.addr() - ptr.addr(); +} + +static u32 ppu_test(vm::cptr ptr, vm::cptr fend, std::initializer_list> pats) +{ + for (auto pat : pats) + { + if (const u32 len = ppu_test(ptr, fend, pat)) + { + return len; + } + } + + return 0; +} + +namespace ppu_patterns +{ + using namespace ppu_instructions; + + const std::initializer_list abort1 + { + { STDU(r1, r1, -0xc0) }, + { MFLR(r0) }, + { STD(r26, r1, 0x90) }, + { STD(r27, r1, 0x98) }, + { STD(r28, r1, 0xa0) }, + { STD(r29, r1, 0xa8) }, + { STD(r30, r1, 0xb0) }, + { STD(r31, r1, 0xb8) }, + { STD(r0, r1, 0xd0) }, + { LI(r3, 4) }, + { LI(r4, 0) }, + { LI(r11, 0x3dc) }, + { SC(0) }, + { MR(r29, r1) }, + { CLRLDI(r29, r29, 32) }, + { LWZ(r4, r2, 0), 0xffff }, + { ADDI(r31, r1, 0x70) }, + { LI(r3, 1) }, + { LI(r5, 0x19) }, + { MR(r6, r31) }, + { LWZ(r28, r29, 4) }, + { LI(r11, 0x193) }, + { SC(0) }, + { ADDI(r26, r1, 0x78) }, + { LD(r3, r28, 0x10) }, + { MR(r4, r26) }, + { B(0, false, true), 0x3fffffc }, // .hex2str + { LI(r5, 0x10) }, + { CLRLDI(r4, r3, 32) }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LWZ(r27, r2, 0), 0xffff }, + { LI(r3, 1) }, + { LI(r5, 1) }, + { MR(r4, r27) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LD(r28, r28, 0) }, + { CMPDI(cr7, r28, 0) }, + { BEQ(cr7, +0x6c) }, + { LWZ(r30, r2, 0), 0xffff }, + { LI(r3, 1) }, + { MR(r4, r30) }, + { LI(r5, 0x19) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { CLRLDI(r29, r28, 32) }, + { CLRLDI(r4, r26, 32) }, + { LD(r3, r29, 0x10) }, + { 0, 0xffffffff }, // .hex2str + { LI(r5, 0x10) }, + { CLRLDI(r4, r3, 32) }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LI(r3, 1) }, + { MR(r4, r27) }, + { LI(r5, 1) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LD(r28, r29, 0) }, + { CMPDI(cr7, r28, 0) }, + { BNE(cr7, -0x60) }, + { LWZ(r4, r2, 0), 0xffff }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r5, 0x27) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LI(r3, 1) }, + { B(0, false, true), 0x3fffffc }, // .sys_process_exit + { LD(r2, r1, 0x28) }, + { LI(r3, 1) }, + { B(0, false, true), 0x3fffffc }, // .exit + }; + + const std::initializer_list abort2 + { + { STDU(r1, r1, -0xc0) }, + { MFLR(r0) }, + { STD(r27, r1, 0x98) }, + { STD(r28, r1, 0xa0) }, + { STD(r29, r1, 0xa8) }, + { STD(r30, r1, 0xb0) }, + { STD(r31, r1, 0xb8) }, + { STD(r0, r1, 0xd0) }, + { MR(r9, r1) }, + { CLRLDI(r9, r9, 32) }, + { LWZ(r4, r2, 0), 0xffff }, + { ADDI(r31, r1, 0x70) }, + { LI(r3, 1) }, + { LI(r5, 0x19) }, + { MR(r6, r31) }, + { LWZ(r29, r9, 4) }, + { LI(r11, 0x193) }, + { SC(0) }, + { ADDI(r27, r1, 0x78) }, + { LD(r3, r29, 0x10) }, + { MR(r4, r27) }, + { B(0, false, true), 0x3fffffc }, // .hex2str + { LI(r5, 0x10) }, + { CLRLDI(r4, r3, 32) }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LWZ(r28, r2, 0), 0xffff }, + { LI(r3, 1) }, + { LI(r5, 1) }, + { MR(r4, r28) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LD(r29, r29, 0) }, + { CMPDI(cr7, r29, 0) }, + { BEQ(cr7, +0x6c) }, + { LWZ(r30, r2, 0), 0xffff }, + { LI(r3, 1) }, + { MR(r4, r30) }, + { LI(r5, 0x19) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { CLRLDI(r29, r29, 32) }, + { CLRLDI(r4, r27, 32) }, + { LD(r3, r29, 0x10) }, + { 0, 0xffffffff }, // .hex2str + { LI(r5, 0x10) }, + { CLRLDI(r4, r3, 32) }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LI(r3, 1) }, + { MR(r4, r28) }, + { LI(r5, 1) }, + { MR(r6, r31) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LD(r29, r29, 0) }, + { CMPDI(cr7, r29, 0) }, + { BNE(cr7, -0x60) }, + { LWZ(r4, r2, 0), 0xffff }, + { MR(r6, r31) }, + { LI(r3, 1) }, + { LI(r5, 0x27) }, + { LI(r11, 0x193) }, + { SC(0) }, + { LI(r3, 1) }, + { B(0, false, true), 0x3fffffc }, // .sys_process_exit + { LD(r2, r1, 0x28) }, + { LI(r3, 1) }, + { B(0, false, true), 0x3fffffc }, // .exit + }; + + const std::initializer_list> abort + { + abort1, + abort2, + }; +} + std::vector ppu_analyse(const std::vector>& segs, const std::vector>& secs, u32 entry, u32 lib_toc) { // Assume first segment is executable const u32 start = segs[0].first; const u32 end = segs[0].first + segs[0].second; - const u32 start_toc = entry ? +vm::read32(entry + 4) : lib_toc; + const u32 start_toc = entry && !lib_toc ? +vm::read32(entry + 4) : lib_toc; // Known TOCs (usually only 1) std::unordered_set TOCs; @@ -186,26 +405,98 @@ std::vector ppu_analyse(const std::vector>& se // Otherwise, register initial set of functions (likely including the entry point) add_toc(start_toc); - // Find eh_frame section + // Find .eh_frame section for (const auto& sec : secs) { - const u32 sec_end = sec.first + sec.second; + u32 sec_end = sec.first + sec.second; - if (sec.first + 32 >= sec_end || vm::read64(sec.first) != 0x0000001c00000000 || vm::read16(sec.first + 8) != 0x017a) + // Probe + for (vm::cptr ptr = vm::cast(sec.first); ptr.addr() < sec_end;) { - continue; + if (ptr % 4 || ptr.addr() < sec.first || ptr.addr() >= sec_end) + { + sec_end = 0; + break; + } + + const u32 size = ptr[0] + 4; + + if (size == 4 && ptr.addr() == sec_end - 4) + { + // Null terminator + break; + } + + if (size % 4 || size < 0x10 || size > sec_end - ptr.addr()) + { + sec_end = 0; + break; + } + + if (ptr[1]) + { + const u32 cie_off = ptr.addr() - ptr[1] + 4; + + if (cie_off % 4 || cie_off < sec.first || cie_off >= sec_end) + { + sec_end = 0; + break; + } + } + + ptr = vm::cast(ptr.addr() + size); } - for (vm::cptr ptr = vm::cast(sec.first); ptr.addr() < sec_end - 4; ptr = vm::cast(ptr.addr() + ptr[0] + 4)) + // Mine + for (vm::cptr ptr = vm::cast(sec.first); ptr.addr() < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4)) { - if (const u32 off = ptr[1]) + if (ptr[0] == 0) { - const u32 addr = ptr[3] + (ptr + 2).addr(); // Function offset (64 bit) - const u32 size = ptr[5]; // Function size (64 bit) + // Null terminator + break; + } - LOG_NOTICE(PPU, ".eh_frame: [0x%x] 0x%x, 0x%x (size=0x%x)", ptr, ptr[0], ptr[1], size); + if (ptr[1] == 0) + { + // CIE + LOG_NOTICE(PPU, ".eh_frame: [0x%x] CIE 0x%x", ptr, ptr[0]); + } + else + { + // Get associated CIE (currently unused) + const vm::cptr cie = vm::cast(ptr.addr() - ptr[1] + 4); - if (!ptr[3]) continue; // TODO (some entries have zero offset) + u32 addr = 0; + u32 size = 0; + + if ((ptr[2] == -1 || ptr[2] == 0) && ptr[4] == 0) + { + addr = ptr[3] + ptr.addr() + 8; + size = ptr[5]; + } + else if (ptr[2] == 0 && ptr[3] == 0) + { + } + else if (ptr[2] != -1 && ptr[4]) + { + addr = ptr[2]; + size = ptr[3]; + } + else + { + LOG_ERROR(PPU, ".eh_frame: [0x%x] 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", ptr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]); + continue; + } + + LOG_NOTICE(PPU, ".eh_frame: [0x%x] FDE 0x%x (cie=*0x%x, addr=0x%x, size=0x%x)", ptr, ptr[0], cie, addr, size); + + if (!addr) continue; // TODO (some entries have zero offset) + + if (addr % 4 || addr < start || addr >= end) + { + LOG_ERROR(PPU, ".eh_frame: Invalid function 0x%x", addr); + continue; + } auto& func = add_func(addr, 0, ptr.addr()); func.attr += ppu_attr::known_size; @@ -230,11 +521,15 @@ std::vector ppu_analyse(const std::vector>& se if (ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {})) { // Simple gate - func.size = 0x4; - func.blocks.emplace(func.addr, func.size); const u32 target = ppu_branch_target(ptr[0] & 0x2 ? 0 : ptr.addr(), s32(ptr[0]) << 6 >> 6); - add_func(target, func.toc, func.addr); - continue; + + if (target >= start && target < end) + { + func.size = 0x4; + func.blocks.emplace(func.addr, func.size); + add_func(target, func.toc, func.addr); + continue; + } } if (ptr + 4 <= fend && @@ -244,13 +539,17 @@ std::vector ppu_analyse(const std::vector>& se (ptr[3] & 0xfc000001) == B({}, {})) { // TOC change gate - func.size = 0x10; - func.blocks.emplace(func.addr, func.size); const u32 new_toc = func.toc && func.toc != -1 ? func.toc + (ptr[1] << 16) + s16(ptr[2]) : 0; const u32 target = ppu_branch_target(ptr[3] & 0x2 ? 0 : (ptr + 3).addr(), s32(ptr[3]) << 6 >> 6); - add_func(target, new_toc, func.addr); - add_toc(new_toc); - continue; + + if (target >= start && target < end) + { + func.size = 0x10; + func.blocks.emplace(func.addr, func.size); + add_func(target, new_toc, func.addr); + add_toc(new_toc); + continue; + } } if (ptr + 8 <= fend && @@ -269,6 +568,15 @@ std::vector ppu_analyse(const std::vector>& se continue; } + if (const u32 len = ppu_test(ptr, fend, ppu_patterns::abort)) + { + // Function .abort + LOG_NOTICE(PPU, "Function [0x%x]: 'abort'", func.addr); + func.attr += ppu_attr::no_return; + func.attr += ppu_attr::known_size; + func.size = len; + } + if (ptr + 3 <= fend && (ptr[0] & 0xffff0000) == LI(r0, 0) && (ptr[1] & 0xffff0000) == ORIS(r0, r0, 0) && @@ -350,6 +658,13 @@ std::vector ppu_analyse(const std::vector>& se else if (type == ppu_itype::B || type == ppu_itype::BC) { const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16); + + if (target < start || target >= end) + { + LOG_WARNING(PPU, "[0x%x] Invalid branch at 0x%x -> 0x%x", func.addr, iaddr, target); + continue; + } + const bool is_call = op.lk && target != iaddr; const auto pfunc = is_call ? &add_func(target, 0, func.addr) : nullptr; @@ -537,9 +852,12 @@ std::vector ppu_analyse(const std::vector>& se { const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16); - if (target < func.addr || target >= func.addr + func.size) + if (target >= start && target < end) { - add_func(target, func.toc, func.addr); + if (target < func.addr || target >= func.addr + func.size) + { + add_func(target, func.toc, func.addr); + } } } else if (type == ppu_itype::BCCTR && !op.lk) diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index f9e9d43271..52af617c7b 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -2,7 +2,8 @@ #include -#include "../Utilities/BitSet.h" +#include "Utilities/BitSet.h" +#include "Utilities/BEType.h" // PPU Function Attributes enum class ppu_attr : u32 @@ -24,6 +25,27 @@ struct ppu_function std::map blocks; // Basic blocks: addr -> size }; +// Aux +struct ppu_pattern +{ + be_t opcode; + be_t mask; + + ppu_pattern() = default; + + ppu_pattern(u32 op) + : opcode(op) + , mask(0xffffffff) + { + } + + ppu_pattern(u32 op, u32 ign) + : opcode(op & ~ign) + , mask(~ign) + { + } +}; + extern void ppu_validate(const std::string& fname, const std::vector& funcs, u32 reloc); extern std::vector ppu_analyse(const std::vector>& segs, const std::vector>& secs, u32 entry, u32 lib_toc); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index ec7ff94b85..54b7ce750e 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -731,13 +731,12 @@ static void ppu_load_imports(const std::shared_ptr& link, u32 } } -template<> -std::shared_ptr ppu_prx_loader::load() const +std::shared_ptr ppu_load_prx(const ppu_prx_object& elf) { std::vector> segments; - std::vector> sections; // Unused + std::vector> sections; - for (const auto& prog : progs) + for (const auto& prog : elf.progs) { LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); @@ -775,8 +774,30 @@ std::shared_ptr ppu_prx_loader::load() const } } + for (const auto& s : elf.shdrs) + { + LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags); + + const u32 addr = vm::cast(s.sh_addr); + const u32 size = vm::cast(s.sh_size); + + if (s.sh_type == 1 && addr && size) + { + for (auto i = 0; i < segments.size(); i++) + { + const u32 saddr = static_cast(elf.progs[i].p_vaddr); + if (addr >= addr && addr < saddr + elf.progs[i].p_memsz) + { + // "Relocate" section + sections.emplace_back(std::make_pair(addr - saddr + segments[i].first, size)); + break; + } + } + } + } + // Do relocations - for (auto& prog : progs) + for (auto& prog : elf.progs) { switch (const u32 p_type = prog.p_type) { @@ -831,9 +852,27 @@ std::shared_ptr ppu_prx_loader::load() const } case 10: + { + const u32 value = vm::_ref>(raddr) = static_cast(rdata - raddr) >> 2; + LOG_WARNING(LOADER, "**** RELOCATION(10): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata); + break; + } + case 44: + { + const u64 value = vm::_ref(raddr) = rdata - raddr; + LOG_TRACE(LOADER, "**** RELOCATION(44): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata); + break; + } + case 57: - default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x)", type, raddr); + { + const u16 value = vm::_ref>(raddr) = static_cast(rdata) >> 2; + LOG_WARNING(LOADER, "**** RELOCATION(57): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", type, raddr, rdata); } } @@ -848,7 +887,7 @@ std::shared_ptr ppu_prx_loader::load() const // Create new PRX object auto prx = idm::make_ptr(); - if (!progs.empty() && progs[0].p_paddr) + if (!elf.progs.empty() && elf.progs[0].p_paddr) { struct ppu_prx_library_info { @@ -863,7 +902,7 @@ std::shared_ptr ppu_prx_loader::load() const }; // Access library information (TODO) - const auto& lib_info = vm::cptr(vm::cast(segments[0].first + progs[0].p_paddr - progs[0].p_offset, HERE)); + const auto& lib_info = vm::cptr(vm::cast(segments[0].first + elf.progs[0].p_paddr - elf.progs[0].p_offset, HERE)); const auto& lib_name = std::string(lib_info->name); LOG_WARNING(LOADER, "Library %s (rtoc=0x%x):", lib_name, lib_info->toc); @@ -872,7 +911,7 @@ std::shared_ptr ppu_prx_loader::load() const ppu_load_imports(link, lib_info->imports_start, lib_info->imports_end); - prx->funcs = ppu_analyse(segments, sections, 0, lib_info->toc); + prx->funcs = ppu_analyse(segments, sections, prx->specials[0xbc9a0086], lib_info->toc); } else { @@ -886,8 +925,7 @@ std::shared_ptr ppu_prx_loader::load() const return prx; } -template<> -void ppu_exec_loader::load() const +void ppu_load_exec(const ppu_exec_object& elf) { ppu_initialize_modules(); @@ -909,7 +947,7 @@ void ppu_exec_loader::load() const std::vector exec_set; // Allocate memory at fixed positions - for (const auto& prog : progs) + for (const auto& prog : elf.progs) { LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); @@ -932,7 +970,7 @@ void ppu_exec_loader::load() const } } - for (const auto& s : shdrs) + for (const auto& s : elf.shdrs) { LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags); @@ -946,7 +984,7 @@ void ppu_exec_loader::load() const } // Load other programs - for (auto& prog : progs) + for (auto& prog : elf.progs) { switch (const u32 p_type = prog.p_type) { @@ -1057,28 +1095,28 @@ void ppu_exec_loader::load() const if (g_cfg_load_liblv2) { - const ppu_prx_loader loader = fs::file(lle_dir + "/liblv2.sprx"); + const ppu_prx_object obj = fs::file(lle_dir + "/liblv2.sprx"); - if (loader == elf_error::ok) + if (obj == elf_error::ok) { - start_funcs.push_back(loader.load()->start.addr()); + start_funcs.push_back(ppu_load_prx(obj)->start.addr()); } else { - throw fmt::exception("Failed to load liblv2.sprx: %s", loader.get_error()); + throw fmt::exception("Failed to load liblv2.sprx: %s", obj.get_error()); } } else { for (const auto& name : g_cfg_load_libs.get_set()) { - const ppu_prx_loader loader = fs::file(lle_dir + '/' + name); + const ppu_prx_object obj = fs::file(lle_dir + '/' + name); - if (loader == elf_error::ok) + if (obj == elf_error::ok) { LOG_WARNING(LOADER, "Loading library: %s", name); - const auto prx = loader.load(); + const auto prx = ppu_load_prx(obj); // Register start function if (prx->start) @@ -1093,7 +1131,7 @@ void ppu_exec_loader::load() const } else { - LOG_FATAL(LOADER, "Failed to load %s: %s", name, loader.get_error()); + LOG_FATAL(LOADER, "Failed to load %s: %s", name, obj.get_error()); } } } @@ -1221,7 +1259,7 @@ void ppu_exec_loader::load() const } // Analyse executable - const auto funcs = ppu_analyse(segments, sections, static_cast(header.e_entry), 0); + const auto funcs = ppu_analyse(segments, sections, static_cast(elf.header.e_entry), 0); ppu_validate(vfs::get(Emu.GetPath()), funcs, 0); @@ -1287,7 +1325,7 @@ void ppu_exec_loader::load() const *entry++ = MR(r12, r19); // Branch to initialization - make_branch(entry, static_cast(header.e_entry), true); + make_branch(entry, static_cast(elf.header.e_entry), true); // Register entry function (addr, size) ppu_function entry_func; @@ -1296,7 +1334,7 @@ void ppu_exec_loader::load() const exec_set.emplace_back(entry_func); // Initialize recompiler - ppu_initialize("", exec_set, static_cast(header.e_entry)); + ppu_initialize("", exec_set, static_cast(elf.header.e_entry)); auto ppu = idm::make_ptr("main_thread"); diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 36691c9c8e..a310db22a4 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -586,6 +586,11 @@ namespace ppu_instructions r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, }; + + enum + { + cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7, + }; } using namespace fields; @@ -595,7 +600,7 @@ namespace ppu_instructions inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } - inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 }; op.lev = lev; return op.opcode; } + inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 | 1 << 1 }; op.lev = lev; return op.opcode; } inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } @@ -607,8 +612,8 @@ namespace ppu_instructions inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } - //inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } - //inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } namespace implicts @@ -627,21 +632,21 @@ namespace ppu_instructions 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); } - //inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } - //inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } - //inline u32 BNE(s32 imm) { return BNE(cr0, imm); } - //inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } - //inline u32 BGT(s32 imm) { return BGT(cr0, imm); } + inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } + inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } + inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } + inline u32 BNE(s32 imm) { return BNE(cr0, imm); } + inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } + inline u32 BGT(s32 imm) { return BGT(cr0, imm); } - //inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } - //inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } - //inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } - //inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } - //inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } - //inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } - //inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } - //inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } + inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } + inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } + inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } + inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } + inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } + inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } + inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } + inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 2b1181cd92..3adca76fe0 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -566,7 +566,7 @@ extern void ppu_initialize(const std::string& name, const std::vector -void spu_exec_loader::load() const +void spu_load_exec(const spu_exec_object& elf) { auto spu = idm::make_ptr("TEST_SPU"); - for (const auto& prog : progs) + for (const auto& prog : elf.progs) { if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) { @@ -248,5 +247,5 @@ void spu_exec_loader::load() const } spu->cpu_init(); - spu->npc = header.e_entry; + spu->npc = elf.header.e_entry; } diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index a7cf11a62c..08f7284365 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -8,20 +8,22 @@ #include "Emu/Cell/ErrorCodes.h" #include "sys_prx.h" +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&); + logs::channel sys_prx("sys_prx", logs::level::notice); s32 prx_load_module(std::string path, u64 flags, vm::ptr pOpt) { sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt); - const ppu_prx_loader loader = fs::file(vfs::get(path)); + const ppu_prx_object obj = fs::file(vfs::get(path)); - if (loader != elf_error::ok) + if (obj != elf_error::ok) { return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } - const auto prx = loader.load(); + const auto prx = ppu_load_prx(obj); if (!prx) { diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 5ffa71ca81..ad06d482dd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -15,14 +15,14 @@ logs::channel sys_spu("sys_spu", logs::level::notice); void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr) { - const spu_exec_loader loader = stream; + const spu_exec_object obj = stream; - if (loader != elf_error::ok) + if (obj != elf_error::ok) { - throw fmt::exception("Failed to load SPU image: %s" HERE, loader.get_error()); + throw fmt::exception("Failed to load SPU image: %s" HERE, obj.get_error()); } - for (const auto& prog : loader.progs) + for (const auto& prog : obj.progs) { if (prog.p_type == 0x1 /* LOAD */) { @@ -30,7 +30,7 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr) } } - spu_ep = loader.header.e_entry; + spu_ep = obj.header.e_entry; } u32 LoadSpuImage(const fs::file& stream, u32& spu_ep) diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index 7992b3b6f8..b184c6d7d9 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -355,8 +355,7 @@ static void arm_patch_refs(u32 refs, u32 addr) } -template<> -void arm_exec_loader::load() const +void arm_load_exec(const arm_exec_object& elf) { arm_initialize_modules(); @@ -373,7 +372,7 @@ void arm_exec_loader::load() const u32 tls_fsize{}; u32 tls_vsize{}; - for (const auto& prog : progs) + for (const auto& prog : elf.progs) { if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) { @@ -397,7 +396,7 @@ void arm_exec_loader::load() const } } - if (!module_info) module_info.set(start_addr + header.e_entry); + if (!module_info) module_info.set(start_addr + elf.header.e_entry); if (!libent) libent.set(start_addr + module_info->libent_top); if (!libstub) libstub.set(start_addr + module_info->libstub_top); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 98ba74fb37..0c7e21fd17 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -39,6 +39,11 @@ extern atomic_t g_ppu_core[2]; extern u64 get_system_time(); +extern void ppu_load_exec(const ppu_exec_object&); +extern void spu_load_exec(const spu_exec_object&); +extern void arm_load_exec(const arm_exec_object&); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&); + fs::file g_tty; namespace rpcs3 @@ -173,10 +178,10 @@ void Emulator::Load() } const fs::file elf_file(m_path); - ppu_exec_loader ppu_exec; - ppu_prx_loader ppu_prx; - spu_exec_loader spu_exec; - arm_exec_loader arm_exec; + ppu_exec_object ppu_exec; + ppu_prx_object ppu_prx; + spu_exec_object spu_exec; + arm_exec_object arm_exec; if (!elf_file) { @@ -230,7 +235,7 @@ void Emulator::Load() vfs::dump(); - ppu_exec.load(); + ppu_load_exec(ppu_exec); Emu.GetCallbackManager().Init(); fxm::import(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall @@ -240,7 +245,7 @@ void Emulator::Load() // PPU PRX (experimental) m_status = Ready; vm::ps3::init(); - ppu_prx.load(); + ppu_load_prx(ppu_prx); GetCallbackManager().Init(); } else if (spu_exec.open(elf_file) == elf_error::ok) @@ -248,23 +253,23 @@ void Emulator::Load() // SPU executable (experimental) m_status = Ready; vm::ps3::init(); - spu_exec.load(); + spu_load_exec(spu_exec); } else if (arm_exec.open(elf_file) == elf_error::ok) { // ARMv7 executable m_status = Ready; vm::psv::init(); - arm_exec.load(); + arm_load_exec(arm_exec); } else { LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); - LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error()); - LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error()); - LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error()); - LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error()); + LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error()); + LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error()); + LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error()); + LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error()); return; } diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index 4cd47c323b..2feb06bcc6 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -340,7 +340,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent) for (const auto& prxf : fs::dir(lle_dir)) { // List found unselected modules - if (!prxf.is_directory && ppu_prx_loader(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name)) + if (!prxf.is_directory && ppu_prx_object(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name)) { lle_module_list_unselected.push_back(prxf.name); } diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h index f66084ad19..cbe308c138 100644 --- a/rpcs3/Loader/ELF.h +++ b/rpcs3/Loader/ELF.h @@ -127,14 +127,7 @@ struct elf_shdr en_t sh_entsize; }; -// Default elf_loader::load() return type, specialized to change. -template -struct elf_load_result -{ - using type = void; -}; - -// ELF loader errors +// ELF loading error enum class elf_error { ok = 0, @@ -154,7 +147,7 @@ enum class elf_error header_os, }; -// ELF loader error information +// ELF loading error information template<> struct unveil { @@ -183,11 +176,11 @@ struct unveil } }; -// ELF loader with specified parameters. +// ELF object with specified parameters. // en_t: endianness (specify le_t or be_t) // sz_t: size (specify u32 for ELF32, u64 for ELF64) template class en_t, typename sz_t, elf_machine Machine, elf_os OS, elf_type Type> -class elf_loader +class elf_object { elf_error m_error{}; @@ -208,9 +201,9 @@ public: std::vector shdrs; public: - elf_loader() = default; + elf_object() = default; - elf_loader(const fs::file& stream, u64 offset = 0) + elf_object(const fs::file& stream, u64 offset = 0) { open(stream, offset); } @@ -346,14 +339,9 @@ public: { return m_error; } - - // Format-specific loader function (must be specialized) - typename elf_load_result::type load() const; }; -using ppu_exec_loader = elf_loader; -using ppu_prx_loader = elf_loader; -using spu_exec_loader = elf_loader; -using arm_exec_loader = elf_loader; - -template<> struct elf_load_result { using type = std::shared_ptr; }; +using ppu_exec_object = elf_object; +using ppu_prx_object = elf_object; +using spu_exec_object = elf_object; +using arm_exec_object = elf_object;