From 52a12185a0a6ce94cf60c0b477752360bc66756e Mon Sep 17 00:00:00 2001 From: Inviuz Date: Sun, 31 Dec 2017 15:38:02 +0100 Subject: [PATCH] Initial sys_overlay --- rpcs3/Emu/Cell/PPUAnalyser.cpp | 38 ++++++ rpcs3/Emu/Cell/PPUModule.cpp | 193 ++++++++++++++++++++++++++++- rpcs3/Emu/Cell/lv2/lv2.cpp | 5 +- rpcs3/Emu/Cell/lv2/sys_overlay.cpp | 60 +++++++++ rpcs3/Emu/Cell/lv2/sys_overlay.h | 23 ++++ rpcs3/Emu/Cell/lv2/sys_process.cpp | 3 + rpcs3/Emu/Cell/lv2/sys_process.h | 1 + rpcs3/emucore.vcxproj | 4 +- rpcs3/emucore.vcxproj.filters | 8 +- rpcs3/rpcs3qt/kernel_explorer.cpp | 10 +- 10 files changed, 339 insertions(+), 6 deletions(-) create mode 100644 rpcs3/Emu/Cell/lv2/sys_overlay.cpp create mode 100644 rpcs3/Emu/Cell/lv2/sys_overlay.h diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 8a975bcd8d..75968b726e 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -931,6 +931,44 @@ void ppu_module::analyse(u32 lib_toc, u32 entry) } } + if (ptr + 0x7 <= fend && + ptr[0] == STD(r2, r1, 0x28) && + (ptr[1] & 0xffff0000) == ADDIS(r12, r2, {}) && + (ptr[2] & 0xffff0000) == LWZ(r11, r12, {}) && + (ptr[3] & 0xffff0000) == ADDIS(r2, r2, {}) && + (ptr[4] & 0xffff0000) == ADDI(r2, r2, {}) && + ptr[5] == MTCTR(r11) && + ptr[6] == BCTR()) + { + func.toc = -1; + func.size = 0x1C; + func.blocks.emplace(func.addr, func.size); + func.attr += ppu_attr::known_addr; + func.attr += ppu_attr::known_size; + + // Look for another imports to fill gaps (hack) + auto p2 = ptr + 7; + + while (p2 + 0x7 <= fend && + p2[0] == STD(r2, r1, 0x28) && + (p2[1] & 0xffff0000) == ADDIS(r12, r2, {}) && + (p2[2] & 0xffff0000) == LWZ(r11, r12, {}) && + (p2[3] & 0xffff0000) == ADDIS(r2, r2, {}) && + (p2[4] & 0xffff0000) == ADDI(r2, r2, {}) && + p2[5] == MTCTR(r11) && + p2[6] == BCTR()) + { + auto& next = add_func(p2.addr(), -1, func.addr); + next.size = 0x1C; + next.blocks.emplace(next.addr, next.size); + next.attr += ppu_attr::known_addr; + next.attr += ppu_attr::known_size; + p2 += 7; + } + + continue; + } + if (ptr + 4 <= fend && ptr[0] == STD(r2, r1, 0x28) && (ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) && diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 50269a68a7..db4915b25d 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -13,6 +13,7 @@ #include "Emu/Cell/lv2/sys_prx.h" #include "Emu/Cell/lv2/sys_memory.h" +#include "Emu/Cell/lv2/sys_overlay.h" #include "Emu/Cell/Modules/StaticHLE.h" @@ -1529,7 +1530,7 @@ void ppu_load_exec(const ppu_exec_object& elf) u32 mem_size; if (sdk_version > 0x0021FFFF) { - mem_size = 0xD500000; + mem_size = 0xD500000; } else if (sdk_version > 0x00192FFF) { @@ -1620,3 +1621,193 @@ void ppu_load_exec(const ppu_exec_object& elf) } } } + +std::shared_ptr ppu_load_overlay(const ppu_exec_object& elf, const std::string& path) +{ + const auto ovlm = idm::make_ptr(); + + // Access linkage information object + const auto link = fxm::get_always(); + + // Executable hash + sha1_context sha; + sha1_starts(&sha); + + // Allocate memory at fixed positions + 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); + + ppu_segment _seg; + const u32 addr = _seg.addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = _seg.size = ::narrow(prog.p_memsz, "p_memsz" HERE); + const u32 type = _seg.type = prog.p_type; + const u32 flag = _seg.flags = prog.p_flags; + _seg.filesz = ::narrow(prog.p_filesz, "p_filesz" HERE); + + // Hash big-endian values + sha1_update(&sha, (uchar*)&prog.p_type, sizeof(prog.p_type)); + sha1_update(&sha, (uchar*)&prog.p_flags, sizeof(prog.p_flags)); + + if (type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz) + fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size); + + if (!vm::falloc(addr, size)) + fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size); + + // Copy segment data, hash it + std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); + sha1_update(&sha, (uchar*)&prog.p_vaddr, sizeof(prog.p_vaddr)); + sha1_update(&sha, (uchar*)&prog.p_memsz, sizeof(prog.p_memsz)); + sha1_update(&sha, prog.bin.data(), prog.bin.size()); + + // Initialize executable code if necessary + if (prog.p_flags & 0x1) + { + ppu_register_range(addr, size); + } + + // Store only LOAD segments (TODO) + ovlm->segs.emplace_back(_seg); + } + } + + // Load section list, used by the analyser + 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); + + ppu_segment _sec; + const u32 addr = _sec.addr = vm::cast(s.sh_addr); + const u32 size = _sec.size = vm::cast(s.sh_size); + const u32 type = _sec.type = s.sh_type; + const u32 flag = _sec.flags = s.sh_flags & 7; + _sec.filesz = 0; + + if (s.sh_type == 1 && addr && size) + { + ovlm->secs.emplace_back(_sec); + } + } + + sha1_finish(&sha, ovlm->sha1); + + // Format patch name + std::string hash("OVL-0000000000000000000000000000000000000000"); + for (u32 i = 0; i < 20; i++) + { + constexpr auto pal = "0123456789abcdef"; + hash[4 + i * 2] = pal[ovlm->sha1[i] >> 4]; + hash[5 + i * 2] = pal[ovlm->sha1[i] & 15]; + } + + // Apply the patch + auto applied = fxm::check_unlocked()->apply(hash, vm::g_base_addr); + + if (!Emu.GetTitleID().empty()) + { + // Alternative patch + applied += fxm::check_unlocked()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr); + } + + LOG_NOTICE(LOADER, "OVL executable hash: %s (<- %u)", hash, applied); + + // Load other programs + for (auto& prog : elf.progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x00000001: break; // LOAD (already loaded) + + case 0x60000001: // LOOS+1 + { + if (prog.p_filesz) + { + struct process_param_t + { + be_t size; //0x60 + be_t magic; //string OVLM + be_t version; //0x17000 + be_t sdk_version; //seems to be correct + //string "stage_ovlm" + //and a lot of zeros. + }; + + const auto& info = vm::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (info.size < sizeof(process_param_t)) + { + LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, u32{sizeof(process_param_t)}); + } + + if (info.magic != 0x4f564c4d) //string "OVLM" + { + LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); + } + else + { + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); + } + } + break; + } + + case 0x60000002: // LOOS+2 seems to be 0x0 in size for overlay elfs, at least in known cases + { + if (prog.p_filesz) + { + struct ppu_proc_prx_param_t + { + be_t size; + be_t magic; + be_t version; + be_t unk0; + be_t libent_start; + be_t libent_end; + be_t libstub_start; + be_t libstub_end; + be_t ver; + be_t unk1; + be_t unk2; + }; + + const auto& proc_prx_param = vm::_ref(vm::cast(prog.p_vaddr, HERE)); + + LOG_NOTICE(LOADER, "* libent_start = *0x%x", proc_prx_param.libent_start); + LOG_NOTICE(LOADER, "* libstub_start = *0x%x", proc_prx_param.libstub_start); + LOG_NOTICE(LOADER, "* unk0 = 0x%x", proc_prx_param.unk0); + LOG_NOTICE(LOADER, "* unk2 = 0x%x", proc_prx_param.unk2); + + if (proc_prx_param.magic != 0x1b434cec) + { + fmt::throw_exception("Bad magic! (0x%x)", proc_prx_param.magic); + } + + ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end); + ppu_load_imports(ovlm->relocs, link, proc_prx_param.libstub_start, proc_prx_param.libstub_end); + } + break; + } + default: + { + LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", p_type); + } + } + } + + ovlm->entry = static_cast(elf.header.e_entry); + + // Analyse executable (TODO) + ovlm->analyse(0, ovlm->entry); + + // Validate analyser results (not required) + ovlm->validate(0); + + // Set path (TODO) + ovlm->name = path.substr(path.find_last_of('/') + 1); + ovlm->path = path; + + return ovlm; +} diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 77ae5f4620..8c0c6166d2 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -15,6 +15,7 @@ #include "sys_memory.h" #include "sys_mmapper.h" #include "sys_net.h" +#include "sys_overlay.h" #include "sys_ppu_thread.h" #include "sys_process.h" #include "sys_prx.h" @@ -422,8 +423,8 @@ const std::array s_ppu_syscall_table uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //430-439 UNS uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //440-449 UNS - null_func,//BIND_FUNC(sys_overlay_load_module) //450 (0x1C2) - null_func,//BIND_FUNC(sys_overlay_unload_module) //451 (0x1C3) + BIND_FUNC(sys_overlay_load_module), //450 (0x1C2) + BIND_FUNC(sys_overlay_unload_module), //451 (0x1C3) null_func,//BIND_FUNC(sys_overlay_get_module_list) //452 (0x1C4) null_func,//BIND_FUNC(sys_overlay_get_module_info) //453 (0x1C5) null_func,//BIND_FUNC(sys_overlay_load_module_by_fd) //454 (0x1C6) diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp new file mode 100644 index 0000000000..99ebf627a8 --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp @@ -0,0 +1,60 @@ +#include "stdafx.h" +#include "Emu/Memory/vm.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Crypto/unself.h" +#include "Crypto/unedat.h" +#include "Loader/ELF.h" + +#include "sys_overlay.h" + +extern std::shared_ptr ppu_load_overlay(const ppu_exec_object&, const std::string& path); + +extern void ppu_initialize(const ppu_module&); + +LOG_CHANNEL(sys_overlay); + +error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path2, u64 flags, vm::ptr entry) +{ + sys_overlay.warning("sys_overlay_load_module(ovlmid=*0x%x, path=%s, flags=0x%x, entry=*0x%x)", ovlmid, path2, flags, entry); + + const std::string path = path2.get_ptr(); + const auto name = path.substr(path.find_last_of('/') + 1); + + const ppu_exec_object obj = decrypt_self(fs::file(vfs::get(path)), fxm::get_always()->devKlic.data()); + + if (obj != elf_error::ok) + { + return {CELL_ENOEXEC, obj.operator elf_error()}; + } + + const auto ovlm = ppu_load_overlay(obj, path); + + ppu_initialize(*ovlm); + + sys_overlay.success("Loaded overlay: %s", path); + + *ovlmid = idm::last_id(); + *entry = ovlm->entry; + + return CELL_OK; +} + +error_code sys_overlay_unload_module(u32 ovlmid) +{ + sys_overlay.warning("sys_overlay_unload_module(ovlmid=0x%x)", ovlmid); + + const auto _main = idm::withdraw(ovlmid); + + if (!_main) + { + return CELL_ESRCH; + } + + for (auto& seg : _main->segs) + { + vm::dealloc(seg.addr); + } + + return CELL_OK; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.h b/rpcs3/Emu/Cell/lv2/sys_overlay.h new file mode 100644 index 0000000000..8e168b807c --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Emu/Cell/PPUAnalyser.h" +#include "sys_sync.h" +#include "Emu/Cell/ErrorCodes.h" + +struct lv2_overlay final : lv2_obj, ppu_module +{ + static const u32 id_base = 0x25000000; + + u32 entry; +}; + +error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path, u64 flags, vm::ptr entry); +error_code sys_overlay_unload_module(u32 ovlmid); +//error_code sys_overlay_get_module_list(sys_pid_t pid, size_t ovlmids_num, sys_overlay_t * ovlmids, size_t * num_of_modules); +//error_code sys_overlay_get_module_info(sys_pid_t pid, sys_overlay_t ovlmid, sys_overlay_module_info_t * info); +//error_code sys_overlay_load_module_by_fd(sys_overlay_t * ovlmid, int fd, u64 offset, uint64_t flags, sys_addr_t * entry); +//error_code sys_overlay_get_module_info2(sys_pid_t pid, sys_overlay_t ovlmid, sys_overlay_module_info2_t * info);// +//error_code sys_overlay_get_sdk_version(); //2 params +//error_code sys_overlay_get_module_dbg_info(); //3 params? + +//error_code _sys_prx_load_module(vm::ps3::cptr path, u64 flags, vm::ps3::ptr pOpt); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 42e6415fa6..519e57ee2e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -16,6 +16,7 @@ #include "sys_memory.h" #include "sys_mmapper.h" #include "sys_prx.h" +#include "sys_overlay.h" #include "sys_rwlock.h" #include "sys_semaphore.h" #include "sys_timer.h" @@ -71,6 +72,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr nump) case SYS_SPUIMAGE_OBJECT: fmt::throw_exception("SYS_SPUIMAGE_OBJECT" HERE); case SYS_PRX_OBJECT: *nump = idm_get_count(); break; case SYS_SPUPORT_OBJECT: fmt::throw_exception("SYS_SPUPORT_OBJECT" HERE); + case SYS_OVERLAY_OBJECT: *nump = idm_get_count(); break; case SYS_LWMUTEX_OBJECT: *nump = idm_get_count(); break; case SYS_TIMER_OBJECT: *nump = idm_get_count(); break; case SYS_SEMAPHORE_OBJECT: *nump = idm_get_count(); break; @@ -118,6 +120,7 @@ s32 sys_process_get_id(u32 object, vm::ptr buffer, u32 size, vm::ptr s case SYS_SPUIMAGE_OBJECT: fmt::throw_exception("SYS_SPUIMAGE_OBJECT" HERE); case SYS_PRX_OBJECT: idm_get_set(objects); break; case SYS_SPUPORT_OBJECT: fmt::throw_exception("SYS_SPUPORT_OBJECT" HERE); + case SYS_OVERLAY_OBJECT: idm_get_set(objects); break; case SYS_LWMUTEX_OBJECT: idm_get_set(objects); break; case SYS_TIMER_OBJECT: idm_get_set(objects); break; case SYS_SEMAPHORE_OBJECT: idm_get_set(objects); break; diff --git a/rpcs3/Emu/Cell/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h index f5a77c7f7a..dd103431b3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.h +++ b/rpcs3/Emu/Cell/lv2/sys_process.h @@ -15,6 +15,7 @@ enum : u32 SYS_SPUIMAGE_OBJECT = 0x22, SYS_PRX_OBJECT = 0x23, SYS_SPUPORT_OBJECT = 0x24, + SYS_OVERLAY_OBJECT = 0x25, SYS_LWMUTEX_OBJECT = 0x95, SYS_TIMER_OBJECT = 0x11, SYS_SEMAPHORE_OBJECT = 0x96, diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index c7201f53d3..34dafb2182 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -115,6 +115,7 @@ + NotUsing @@ -408,6 +409,7 @@ + @@ -607,4 +609,4 @@ - \ No newline at end of file + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 25b710c9a0..f26d2965f4 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -779,6 +779,9 @@ Emu\GPU\RSX\Overlays + + Emu\Cell\lv2 + @@ -1423,6 +1426,9 @@ Emu\Cell\lv2 + + Emu\Cell\lv2 + Emu\Cell\lv2 @@ -1490,4 +1496,4 @@ Emu\Audio\Null - \ No newline at end of file + diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index 5cae91a1f4..4fd1442a53 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -15,6 +15,7 @@ #include "Emu/Cell/lv2/sys_event_flag.h" #include "Emu/Cell/lv2/sys_rwlock.h" #include "Emu/Cell/lv2/sys_prx.h" +#include "Emu/Cell/lv2/sys_overlay.h" #include "Emu/Cell/lv2/sys_memory.h" #include "Emu/Cell/lv2/sys_mmapper.h" #include "Emu/Cell/lv2/sys_spu.h" @@ -125,8 +126,9 @@ void kernel_explorer::Update() lv2_types[SYS_EVENT_PORT_OBJECT] = l_addTreeChild(root, "Event Ports"); lv2_types[SYS_TRACE_OBJECT] = l_addTreeChild(root, "Traces"); lv2_types[SYS_SPUIMAGE_OBJECT] = l_addTreeChild(root, "SPU Images"); - lv2_types[SYS_PRX_OBJECT] = l_addTreeChild(root, "Modules"); + lv2_types[SYS_PRX_OBJECT] = l_addTreeChild(root, "PRX Modules"); lv2_types[SYS_SPUPORT_OBJECT] = l_addTreeChild(root, "SPU Ports"); + lv2_types[SYS_OVERLAY_OBJECT] = l_addTreeChild(root, "Overlay Modules"); lv2_types[SYS_LWMUTEX_OBJECT] = l_addTreeChild(root, "Light Weight Mutexes"); lv2_types[SYS_TIMER_OBJECT] = l_addTreeChild(root, "Timers"); lv2_types[SYS_SEMAPHORE_OBJECT] = l_addTreeChild(root, "Semaphores"); @@ -212,6 +214,12 @@ void kernel_explorer::Update() l_addTreeChild(node, qstr(fmt::format("SPU Port: ID = 0x%08x", id))); break; } + case SYS_OVERLAY_OBJECT: + { + auto& ovl = static_cast(obj); + l_addTreeChild(node, qstr(fmt::format("OVL: ID = 0x%08x '%s'", id, ovl.name))); + break; + } case SYS_LWMUTEX_OBJECT: { auto& lwm = static_cast(obj);