From 2553e45d76025120b14b9559e80b74a078c029b7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:47:09 +0300 Subject: [PATCH] Partial commit: Loader --- rpcs3/Loader/ELF.h | 348 ++++++++++++++++++ rpcs3/Loader/ELF32.cpp | 453 ------------------------ rpcs3/Loader/ELF32.h | 139 -------- rpcs3/Loader/ELF64.cpp | 737 --------------------------------------- rpcs3/Loader/ELF64.h | 164 --------- rpcs3/Loader/Loader.cpp | 130 ------- rpcs3/Loader/Loader.h | 131 ------- rpcs3/Loader/PSF.cpp | 42 +-- rpcs3/Loader/PSF.h | 27 +- rpcs3/Loader/TROPUSR.cpp | 87 ++--- rpcs3/Loader/TROPUSR.h | 10 +- rpcs3/Loader/TRP.cpp | 47 +-- rpcs3/Loader/TRP.h | 20 +- 13 files changed, 450 insertions(+), 1885 deletions(-) create mode 100644 rpcs3/Loader/ELF.h delete mode 100644 rpcs3/Loader/ELF32.cpp delete mode 100644 rpcs3/Loader/ELF32.h delete mode 100644 rpcs3/Loader/ELF64.cpp delete mode 100644 rpcs3/Loader/ELF64.h delete mode 100644 rpcs3/Loader/Loader.cpp delete mode 100644 rpcs3/Loader/Loader.h diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h new file mode 100644 index 0000000000..3430fc1d2d --- /dev/null +++ b/rpcs3/Loader/ELF.h @@ -0,0 +1,348 @@ +#pragma once + +#include "../../Utilities/File.h" + +enum class elf_os : u8 +{ + none = 0, + + lv2 = 0x66, +}; + +enum class elf_type : u16 +{ + none = 0, + rel = 1, + exec = 2, + dyn = 3, + core = 4, + + prx = 0xffa4, + + psv1 = 0xfe00, // ET_SCE_EXEC + psv2 = 0xfe04, // ET_SCE_RELEXEC (vitasdk) +}; + +enum class elf_machine : u16 +{ + ppc64 = 0x15, + spu = 0x17, + arm = 0x28, + mips = 0x08, +}; + +template class en_t, typename sz_t> +struct elf_ehdr +{ + nse_t e_magic; + u8 e_class; + u8 e_data; + u8 e_curver; + elf_os e_os_abi; + u8 e_abi_ver; + u8 e_pad[7]; + en_t e_type; + en_t e_machine; + en_t e_version; + en_t e_entry; + en_t e_phoff; + en_t e_shoff; + en_t e_flags; + en_t e_ehsize; + en_t e_phentsize; + en_t e_phnum; + en_t e_shentsize; + en_t e_shnum; + en_t e_shstrndx; +}; + +template class en_t, typename sz_t> +struct elf_phdr +{ + static_assert(!sizeof(sz_t), "Invalid elf size type (must be u32 or u64)"); +}; + +template class en_t> +struct elf_phdr +{ + en_t p_type; + en_t p_flags; + en_t p_offset; + en_t p_vaddr; + en_t p_paddr; + en_t p_filesz; + en_t p_memsz; + en_t p_align; +}; + +template class en_t> +struct elf_phdr +{ + en_t p_type; + en_t p_offset; + en_t p_vaddr; + en_t p_paddr; + en_t p_filesz; + en_t p_memsz; + en_t p_flags; + en_t p_align; +}; + +template class en_t, typename sz_t> +struct elf_prog final : elf_phdr +{ + std::vector bin; + + using base = elf_phdr; + + elf_prog() = default; + + elf_prog(u32 type, u32 flags, sz_t vaddr, sz_t memsz, sz_t align, std::vector&& bin) + : bin(std::move(bin)) + { + base::p_type = type; + base::p_flags = flags; + base::p_vaddr = vaddr; + base::p_memsz = memsz; + base::p_align = align; + base::p_filesz = static_cast(bin.size()); + base::p_paddr = 0; + base::p_offset = -1; + } +}; + +template class en_t, typename sz_t> +struct elf_shdr +{ + en_t sh_name; + en_t sh_type; + en_t sh_flags; + en_t sh_addr; + en_t sh_offset; + en_t sh_size; + en_t sh_link; + en_t sh_info; + en_t sh_addralign; + en_t sh_entsize; +}; + +// Default elf_loader::load() return type, specialized to change. +template +struct elf_load_result +{ + using type = void; +}; + +// ELF loader errors +enum class elf_error +{ + ok = 0, + + stream, + stream_header, + stream_phdrs, + stream_shdrs, + stream_data, + + header_magic, + header_version, + header_class, + header_machine, + header_endianness, + header_type, + header_os, +}; + +// ELF loader error information +template<> +struct bijective +{ + static constexpr std::pair map[] + { + { elf_error::ok, "" }, + + { elf_error::stream, "Invalid stream" }, + { elf_error::stream_header, "Failed to read ELF header" }, + { elf_error::stream_phdrs, "Failed to read ELF program headers" }, + { elf_error::stream_shdrs, "Failed to read ELF section headers" }, + { elf_error::stream_data, "Failed to read ELF program data" }, + + { elf_error::header_magic, "Not an ELF" }, + { elf_error::header_version, "Invalid or unsupported ELF format" }, + { elf_error::header_class, "Invalid ELF class" }, + { elf_error::header_machine, "Invalid ELF machine" }, + { elf_error::header_endianness, "Invalid ELF data (endianness)" }, + { elf_error::header_type, "Invalid ELF type" }, + { elf_error::header_os, "Invalid ELF OS ABI" }, + }; +}; + +// ELF loader 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 +{ + elf_error m_error{}; + + elf_error error(elf_error e) + { + return m_error = e; + } + +public: + using ehdr_t = elf_ehdr; + using phdr_t = elf_phdr; + using shdr_t = elf_shdr; + using prog_t = elf_prog; + + ehdr_t header{}; + + std::vector progs; + std::vector shdrs; + +public: + elf_loader() = default; + + elf_loader(const fs::file& stream, u64 offset = 0) + { + open(stream, offset); + } + + elf_error open(const fs::file& stream, u64 offset = 0) + { + // Check stream + if (!stream) + return error(elf_error::stream); + + // Read ELF header + stream.seek(offset); + if (!stream.read(header)) + return error(elf_error::stream_header); + + // Check magic + if (header.e_magic != "\177ELF"_u32) + return error(elf_error::header_magic); + + // Check class + if (header.e_class != (std::is_same::value ? 1 : 2)) + return error(elf_error::header_class); + + // Check endianness + if (header.e_data != (std::is_same, le_t>::value ? 1 : 2)) + return error(elf_error::header_endianness); + + // Check machine + if (header.e_machine != Machine) + return error(elf_error::header_machine); + + // Check OS only if specified (hack) + if (OS != elf_os::none && header.e_os_abi != OS) + return error(elf_error::header_os); + + // Check type only if specified (hack) + if (Type != elf_type::none && header.e_type != Type) + return error(elf_error::header_type); + + // Check version and other params + if (header.e_curver != 1 || header.e_version != 1 || header.e_ehsize != sizeof(ehdr_t)) + return error(elf_error::header_version); + + if (header.e_phnum && header.e_phentsize != sizeof(phdr_t)) + return error(elf_error::header_version); + + if (header.e_shnum && header.e_shentsize != sizeof(shdr_t)) + return error(elf_error::header_version); + + // Load program headers + std::vector _phdrs(header.e_phnum); + stream.seek(offset + header.e_phoff); + if (!stream.read(_phdrs)) + return error(elf_error::stream_phdrs); + + shdrs.resize(header.e_shnum); + stream.seek(offset + header.e_shoff); + if (!stream.read(shdrs)) + return error(elf_error::stream_shdrs); + + progs.clear(); + progs.reserve(_phdrs.size()); + for (const auto& hdr : _phdrs) + { + progs.emplace_back(); + + static_cast(progs.back()) = hdr; + progs.back().bin.resize(hdr.p_filesz); + stream.seek(offset + hdr.p_offset); + if (!stream.read(progs.back().bin)) + return error(elf_error::stream_data); + } + + shdrs.shrink_to_fit(); + progs.shrink_to_fit(); + + return m_error = elf_error::ok; + } + + void save(const fs::file& stream) const + { + // Write header + ehdr_t header{}; + header.e_magic = "\177ELF"_u32; + header.e_class = std::is_same::value ? 1 : 2; + header.e_data = std::is_same, le_t>::value ? 1 : 2; + header.e_curver = 1; + header.e_os_abi = OS != elf_os::none ? OS : this->header.e_os_abi; + header.e_abi_ver = this->header.e_abi_ver; + header.e_type = Type != elf_type::none ? Type : this->header.e_type; + header.e_machine = Machine; + header.e_version = 1; + header.e_entry = this->header.e_entry; + header.e_phoff = SIZE_32(ehdr_t); + header.e_shoff = SIZE_32(ehdr_t) + SIZE_32(phdr_t) * ::size32(progs); + header.e_flags = this->header.e_flags; + header.e_ehsize = SIZE_32(ehdr_t); + header.e_phentsize = SIZE_32(phdr_t); + header.e_phnum = ::size32(progs); + header.e_shentsize = SIZE_32(shdr_t); + header.e_shnum = ::size32(shdrs); + header.e_shstrndx = this->header.e_shstrndx; + stream.write(header); + + sz_t off = header.e_shoff + SIZE_32(shdr_t) * ::size32(shdrs); + + for (phdr_t phdr : progs) + { + phdr.p_offset = std::exchange(off, off + phdr.p_filesz); + stream.write(phdr); + } + + for (shdr_t shdr : shdrs) + { + // TODO? + stream.write(shdr); + } + + // Write data + for (const auto& prog : progs) + { + stream.write(prog.bin); + } + } + + // Return error code + operator elf_error() const + { + 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; }; diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp deleted file mode 100644 index dc3b3db9f5..0000000000 --- a/rpcs3/Loader/ELF32.cpp +++ /dev/null @@ -1,453 +0,0 @@ -#include "stdafx.h" -#include "ELF32.h" -#include "Emu/FS/vfsStream.h" -#include "Emu/Memory/Memory.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Emu/ARMv7/ARMv7Decoder.h" -#include "Emu/ARMv7/PSVFuncList.h" -#include "Emu/System.h" -#include "Emu/state.h" - -extern void armv7_init_tls(); - -namespace loader -{ - namespace handlers - { - handler::error_code elf32::init(vfsStream& stream) - { - m_ehdr = {}; - m_phdrs.clear(); - m_shdrs.clear(); - - error_code res = handler::init(stream); - - if (res != ok) - { - return res; - } - - m_stream->Read(&m_ehdr, sizeof(ehdr)); - - if (!m_ehdr.check()) - { - return bad_file; - } - - if (m_ehdr.data_le.e_phnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_phentsize != sizeof(phdr) : m_ehdr.data_be.e_phentsize != sizeof(phdr))) - { - return broken_file; - } - - if (m_ehdr.data_le.e_shnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_shentsize != sizeof(shdr) : m_ehdr.data_be.e_shentsize != sizeof(shdr))) - { - return broken_file; - } - - LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", m_ehdr.is_le() ? m_ehdr.data_le.e_type : m_ehdr.data_be.e_type.value()); - - if (m_ehdr.data_le.e_phnum) - { - m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value()); - m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff.value())); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value()) * sizeof(phdr); - - if (m_stream->Read(m_phdrs.data(), size) != size) - return broken_file; - } - - if (m_ehdr.data_le.e_shnum) - { - m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value()); - m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff.value())); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value()) * sizeof(shdr); - - if (m_stream->Read(m_shdrs.data(), size) != size) - return broken_file; - } - - return ok; - } - - handler::error_code elf32::load() - { - Elf_Machine machine; - switch (machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value())) - { - case MACHINE_MIPS: vm::psp::init(); break; - case MACHINE_ARM: vm::psv::init(); break; - case MACHINE_SPU: vm::ps3::init(); break; - - default: - return bad_version; - } - - error_code res = load_data(0); - - if (res != ok) - return res; - - switch (machine) - { - case MACHINE_MIPS: break; - case MACHINE_ARM: - { - struct psv_libc_param_t - { - u32 size; // 0x0000001c - u32 unk1; // 0x00000000 - - vm::lptr sceLibcHeapSize; - vm::lptr sceLibcHeapSizeDefault; - vm::lptr sceLibcHeapExtendedAlloc; - vm::lptr sceLibcHeapDelayedAlloc; - - u32 unk2; - u32 unk3; - - vm::lptr __sce_libcmallocreplace; - vm::lptr __sce_libcnewreplace; - }; - - struct psv_process_param_t - { - u32 size; // 0x00000030 - u32 unk1; // 'PSP2' - u32 unk2; // 0x00000005 - u32 unk3; - - vm::lcptr sceUserMainThreadName; - vm::lptr sceUserMainThreadPriority; - vm::lptr sceUserMainThreadStackSize; - vm::lptr sceUserMainThreadAttribute; - vm::lcptr sceProcessName; - vm::lptr sce_process_preload_disabled; - vm::lptr sceUserMainThreadCpuAffinityMask; - - vm::lptr __sce_libcparam; - }; - - initialize_psv_modules(); - - auto armv7_thr_stop_data = vm::ptr::make(vm::alloc(3 * 4, vm::main)); - armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb) - armv7_thr_stop_data[1] = SFI_HLE_RETURN; - Emu.SetCPUThreadStop(armv7_thr_stop_data.addr()); - - u32 entry = 0; // actual entry point (ELFs entry point is ignored) - u32 fnid_addr = 0; - u32 code_start = 0; - u32 code_end = 0; - u32 vnid_addr = 0; - std::unordered_map vnid_list; - - vm::ptr proc_param = vm::null; - - for (auto& shdr : m_shdrs) - { - // get secton name - //auto name = vm::cptr::make(sname_base + shdr.data_le.sh_name); - - m_stream->Seek(handler::get_stream_offset() + m_shdrs[m_ehdr.data_le.e_shstrndx].data_le.sh_offset + shdr.data_le.sh_name); - std::string name; - char c; - while (m_stream->SRead(c) && c) - { - name.push_back(c); - } - - if (!strcmp(name.c_str(), ".text")) - { - LOG_NOTICE(LOADER, ".text analysis..."); - - code_start = shdr.data_le.sh_addr; - code_end = shdr.data_le.sh_size + code_start; - } - else if (!strcmp(name.c_str(), ".sceExport.rodata")) - { - LOG_NOTICE(LOADER, ".sceExport.rodata analysis..."); - - auto enid = vm::cptr::make(shdr.data_le.sh_addr); - auto edata = vm::cptr::make(enid.addr() + shdr.data_le.sh_size / 2); - - for (u32 j = 0; j < shdr.data_le.sh_size / 8; j++) - { - switch (const u32 nid = enid[j]) - { - case 0x935cd196: // set entry point - { - entry = edata[j]; - break; - } - - case 0x6c2224ba: // __sce_moduleinfo - { - // currently nothing, but it should theoretically be the root of analysis instead of section name comparison - break; - } - - case 0x70fba1e7: // __sce_process_param - { - proc_param.set(edata[j]); - break; - } - - default: - { - LOG_ERROR(LOADER, "Unknown export 0x%08x (addr=0x%08x)", nid, edata[j]); - } - } - } - } - else if (!strcmp(name.c_str(), ".sceFNID.rodata")) - { - LOG_NOTICE(LOADER, ".sceFNID.rodata analysis..."); - - fnid_addr = shdr.data_le.sh_addr; - } - else if (!strcmp(name.c_str(), ".sceFStub.rodata")) - { - LOG_NOTICE(LOADER, ".sceFStub.rodata analysis..."); - - if (!fnid_addr) - { - LOG_ERROR(LOADER, ".sceFNID.rodata address not found, unable to process imports"); - continue; - } - - auto fnid = vm::cptr::make(fnid_addr); - auto fstub = vm::cptr::make(shdr.data_le.sh_addr); - - for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++) - { - const u32 nid = fnid[j]; - const u32 addr = fstub[j]; - - u32 index; - - if (auto func = get_psv_func_by_nid(nid, &index)) - { - if (func->module) - { - LOG_NOTICE(LOADER, "Imported function '%s' in module '%s' (nid=0x%08x, addr=0x%x)", func->name, func->module->name, nid, addr); - } - else - { - LOG_NOTICE(LOADER, "Imported function '%s' (nid=0x%08x, addr=0x%x)", func->name, nid, addr); - } - } - else - { - LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); - - // TODO: set correct name if possible - index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr)); - } - - vm::psv::write32(addr, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) - - code_end = std::min(addr, code_end); - } - } - else if (!strcmp(name.c_str(), ".sceVNID.rodata")) - { - LOG_NOTICE(LOADER, ".sceVNID.rodata analysis..."); - - vnid_addr = shdr.data_le.sh_addr; - } - else if (!strcmp(name.c_str(), ".sceVStub.rodata")) - { - LOG_NOTICE(LOADER, ".sceVStub.rodata analysis..."); - - if (!vnid_addr) - { - if (shdr.data_le.sh_size) - { - LOG_ERROR(LOADER, ".sceVNID.rodata address not found, unable to process imports"); - } - continue; - } - - auto vnid = vm::cptr::make(vnid_addr); - auto vstub = vm::cptr::make(shdr.data_le.sh_addr); - - for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++) - { - const u32 nid = vnid[j]; - const u32 addr = vstub[j]; - - LOG_ERROR(LOADER, "Unknown object 0x%08x (ref_addr=0x%x)", nid, addr); - - // TODO: find imported object (vtable, typeinfo or something), assign it to vnid_list[addr] - } - } - else if (!strcmp(name.c_str(), ".tbss")) - { - LOG_NOTICE(LOADER, ".tbss analysis..."); - const u32 img_addr = shdr.data_le.sh_addr; // start address of TLS initialization image - const u32 img_size = (&shdr)[1].data_le.sh_addr - img_addr; // calculate its size as the difference between sections - const u32 tls_size = shdr.data_le.sh_size; // full size of TLS - - LOG_WARNING(LOADER, "TLS: img_addr=0x%08x, img_size=0x%x, tls_size=0x%x", img_addr, img_size, tls_size); - Emu.SetTLSData(img_addr, img_size, tls_size); - } - else if (!strcmp(name.c_str(), ".sceRefs.rodata")) - { - LOG_NOTICE(LOADER, ".sceRefs.rodata analysis..."); - - u32 data = 0; - - for (auto code = vm::cptr::make(shdr.data_le.sh_addr); code.addr() < shdr.data_le.sh_addr + shdr.data_le.sh_size; code++) - { - switch (*code) - { - case 0x000000ff: // save address for future use - { - data = *++code; - break; - } - case 0x0000002f: // movw r*,# instruction is replaced - { - if (!data) // probably, imported object - { - auto found = vnid_list.find(code.addr()); - if (found != vnid_list.end()) - { - data = found->second; - } - } - - if (!data) - { - LOG_ERROR(LOADER, ".sceRefs: movw writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]); - } - else - { - LOG_NOTICE(LOADER, ".sceRefs: movw written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data); - } - - const u32 addr = *++code; - vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x800) >> 1 | (data & 0xf000) >> 12); - vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x700) << 4 | (data & 0xff)); - break; - } - case 0x00000030: // movt r*,# instruction is replaced - { - if (!data) - { - LOG_ERROR(LOADER, ".sceRefs: movt writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]); - } - else - { - LOG_NOTICE(LOADER, ".sceRefs: movt written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data); - } - - const u32 addr = *++code; - vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x8000000) >> 17 | (data & 0xf0000000) >> 28); - vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x7000000) >> 12 | (data & 0xff0000) >> 16); - break; - } - case 0x00000000: - { - data = 0; - - LOG_TRACE(LOADER, ".sceRefs: zero code found"); - break; - } - default: - { - LOG_ERROR(LOADER, "Unknown code in .sceRefs section (0x%08x)", *code); - } - } - } - } - } - - LOG_NOTICE(LOADER, "__sce_process_param(addr=0x%x) analysis...", proc_param); - - if (proc_param->size != 0x30 || proc_param->unk1 != *(u32*)"PSP2" || proc_param->unk2 != 5) - { - LOG_ERROR(LOADER, "__sce_process_param: unexpected data found (size=0x%x, 0x%x, 0x%x, 0x%x)", proc_param->size, proc_param->unk1, proc_param->unk2, proc_param->unk3); - } - - LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute); - LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName); - LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask); - - auto libc_param = proc_param->__sce_libcparam; - - LOG_NOTICE(LOADER, "__sce_libcparam(addr=0x%x) analysis...", libc_param); - - if (libc_param->size != 0x1c || libc_param->unk1) - { - LOG_ERROR(LOADER, "__sce_libcparam: unexpected data found (size=0x%x, 0x%x, 0x%x)", libc_param->size, libc_param->unk1, libc_param->unk2); - } - - LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize); - LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault); - LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); - LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); - - armv7_init_tls(); - armv7_decoder_initialize(code_start, code_end); - - const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; - const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; - const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; - - armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run(); - break; - } - case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry.value(), "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break; - } - - return ok; - } - - handler::error_code elf32::load_data(u32 offset, bool skip_writeable) - { - Elf_Machine machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value()); - - for (auto &phdr : m_phdrs) - { - u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz.value(); - u32 filesz = m_ehdr.is_le() ? phdr.data_le.p_filesz : phdr.data_be.p_filesz.value(); - u32 vaddr = offset + (m_ehdr.is_le() ? phdr.data_le.p_vaddr : phdr.data_be.p_vaddr.value()); - u32 offset = m_ehdr.is_le() ? phdr.data_le.p_offset : phdr.data_be.p_offset.value(); - - switch (m_ehdr.is_le() ? phdr.data_le.p_type : phdr.data_be.p_type.value()) - { - case 0x00000001: //LOAD - if (phdr.data_le.p_memsz) - { - if (machine == MACHINE_ARM && !vm::falloc(vaddr, memsz, vm::main)) - { - LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz); - - return loading_error; - } - - if (skip_writeable == true && (phdr.data_be.p_flags & 2/*PF_W*/) != 0) - { - continue; - } - - if (filesz) - { - m_stream->Seek(handler::get_stream_offset() + offset); - m_stream->Read(vm::base(vaddr), filesz); - } - } - break; - } - } - - return ok; - } - } -} diff --git a/rpcs3/Loader/ELF32.h b/rpcs3/Loader/ELF32.h deleted file mode 100644 index 76cc910ec2..0000000000 --- a/rpcs3/Loader/ELF32.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once -#include "Loader.h" - -struct vfsStream; - -namespace loader -{ - namespace handlers - { - class elf32 : public handler - { - public: - struct ehdr - { - u32 e_magic; - u8 e_class; - u8 e_data; - u8 e_curver; - u8 e_os_abi; - - union - { - struct - { - u64 e_abi_ver; - u16 e_type; - u16 e_machine; - u32 e_version; - u32 e_entry; - u32 e_phoff; - u32 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; - } data_le; - - struct - { - be_t e_abi_ver; - be_t e_type; - be_t e_machine; - be_t e_version; - be_t e_entry; - be_t e_phoff; - be_t e_shoff; - be_t e_flags; - be_t e_ehsize; - be_t e_phentsize; - be_t e_phnum; - be_t e_shentsize; - be_t e_shnum; - be_t e_shstrndx; - } data_be; - }; - - bool is_le() const { return e_data == 1; } - bool check() const { return e_magic == 0x464C457F; } - }; - - struct shdr - { - union - { - struct - { - u32 sh_name; - u32 sh_type; - u32 sh_flags; - u32 sh_addr; - u32 sh_offset; - u32 sh_size; - u32 sh_link; - u32 sh_info; - u32 sh_addralign; - u32 sh_entsize; - } data_le; - - struct - { - be_t sh_name; - be_t sh_type; - be_t sh_flags; - be_t sh_addr; - be_t sh_offset; - be_t sh_size; - be_t sh_link; - be_t sh_info; - be_t sh_addralign; - be_t sh_entsize; - } data_be; - }; - }; - - struct phdr - { - union - { - struct - { - u32 p_type; - u32 p_offset; - u32 p_vaddr; - u32 p_paddr; - u32 p_filesz; - u32 p_memsz; - u32 p_flags; - u32 p_align; - } data_le; - - struct - { - be_t p_type; - be_t p_offset; - be_t p_vaddr; - be_t p_paddr; - be_t p_filesz; - be_t p_memsz; - be_t p_flags; - be_t p_align; - } data_be; - }; - }; - - ehdr m_ehdr; - std::vector m_phdrs; - std::vector m_shdrs; - - error_code init(vfsStream& stream) override; - error_code load() override; - error_code load_data(u32 offset, bool skip_writeable = false); - - virtual ~elf32() = default; - }; - } -} diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp deleted file mode 100644 index 288aeb61a5..0000000000 --- a/rpcs3/Loader/ELF64.cpp +++ /dev/null @@ -1,737 +0,0 @@ -#include "stdafx.h" -#include "Emu/FS/vfsStream.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/SysCalls/lv2/sys_prx.h" -#include "Emu/Cell/PPUInstrTable.h" -#include "ELF64.h" - -using namespace PPU_instr; - -namespace loader -{ - namespace handlers - { - handler::error_code elf64::init(vfsStream& stream) - { - m_ehdr = {}; - m_sprx_module_info = {}; - m_sprx_function_info = {}; - - m_phdrs.clear(); - m_shdrs.clear(); - - m_sprx_segments_info.clear(); - m_sprx_import_info.clear(); - m_sprx_export_info.clear(); - - error_code res = handler::init(stream); - - if (res != ok) - { - return res; - } - - m_stream->Read(&m_ehdr, sizeof(ehdr)); - - if (!m_ehdr.check()) - { - return bad_file; - } - - if (m_ehdr.e_phnum && m_ehdr.e_phentsize != sizeof(phdr)) - { - return broken_file; - } - - if (m_ehdr.e_shnum && m_ehdr.e_shentsize != sizeof(shdr)) - { - return broken_file; - } - - if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU) - { - LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine); - return bad_version; - } - - if (m_ehdr.e_phnum) - { - m_phdrs.resize(m_ehdr.e_phnum); - m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_phoff); - if (m_stream->Read(m_phdrs.data(), m_ehdr.e_phnum * sizeof(phdr)) != m_ehdr.e_phnum * sizeof(phdr)) - return broken_file; - } - - if (m_ehdr.e_shnum) - { - m_shdrs.resize(m_ehdr.e_shnum); - m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_shoff); - if (m_stream->Read(m_shdrs.data(), m_ehdr.e_shnum * sizeof(shdr)) != m_ehdr.e_shnum * sizeof(shdr)) - return broken_file; - } - - if (is_sprx()) - { - m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr()); - m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info)); - - //m_stream->Seek(handler::get_stream_offset() + m_phdrs[1].p_vaddr.addr()); - //m_stream->Read(&m_sprx_function_info, sizeof(sprx_function_info)); - } - - return ok; - } - - handler::error_code elf64::load_sprx(sprx_info& info) - { - for (auto &phdr : m_phdrs) - { - switch ((u32)phdr.p_type) - { - case 0x1: //load - { - if (phdr.p_memsz) - { - sprx_segment_info segment; - segment.size = phdr.p_memsz; - segment.size_file = phdr.p_filesz; - - segment.begin.set(vm::alloc(segment.size, vm::main)); - - if (!segment.begin) - { - LOG_ERROR(LOADER, "%s() sprx: vm::alloc(0x%x) failed", __FUNCTION__, segment.size); - - return loading_error; - } - - segment.initial_addr = phdr.p_vaddr; - LOG_WARNING(LOADER, "segment addr=0x%x, initial addr = 0x%x", segment.begin.addr(), segment.initial_addr.addr()); - - if (phdr.p_filesz) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - m_stream->Read(segment.begin.get_ptr(), phdr.p_filesz); - } - - if (phdr.p_paddr) - { - sys_prx_module_info_t module_info; - m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr()); - m_stream->Read(&module_info, sizeof(module_info)); - - info.name = std::string(module_info.name, 28); - info.rtoc = module_info.toc + segment.begin.addr(); - - LOG_WARNING(LOADER, "%s (rtoc=0x%x):", info.name, info.rtoc); - - sys_prx_library_info_t lib; - for (u32 e = module_info.exports_start.addr(); - e < module_info.exports_end.addr(); - e += lib.size ? lib.size : sizeof(sys_prx_library_info_t)) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + e); - m_stream->Read(&lib, sizeof(lib)); - - std::string modulename; - if (lib.name_addr) - { - char name[27]; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr); - m_stream->Read(name, sizeof(name)); - modulename = name; - LOG_WARNING(LOADER, "**** Exported: %s", name); - } - - auto &module = info.modules[modulename]; - - LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6); - - for (u16 i = 0, end = lib.num_func; i < end; ++i) - { - be_t fnid, fstub; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid)); - m_stream->Read(&fnid, sizeof(fnid)); - - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub)); - m_stream->Read(&fstub, sizeof(fstub)); - - module.exports[fnid] = fstub; - - //LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", get_ps3_function_name(fnid), module_name); - LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub); - } - } - - for (u32 i = module_info.imports_start; - i < module_info.imports_end; - i += lib.size ? lib.size : sizeof(sys_prx_library_info_t)) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + i); - m_stream->Read(&lib, sizeof(lib)); - - std::string modulename; - if (lib.name_addr) - { - char name[27]; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr); - m_stream->Read(name, sizeof(name)); - modulename = name; - LOG_WARNING(LOADER, "**** Imported: %s", name); - } - - auto &module = info.modules[modulename]; - - LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6); - - for (u16 i = 0, end = lib.num_func; i < end; ++i) - { - be_t fnid, fstub; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid)); - m_stream->Read(&fnid, sizeof(fnid)); - - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub)); - m_stream->Read(&fstub, sizeof(fstub)); - - module.imports[fnid] = fstub; - - LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub); - } - } - } - - info.segments.push_back(segment); - } - - break; - } - - case 0x700000a4: //relocation - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - - for (uint i = 0; i < phdr.p_filesz; i += sizeof(sys_prx_relocation_info_t)) - { - sys_prx_relocation_info_t rel; - m_stream->Read(&rel, sizeof(rel)); - - u32 ADDR = info.segments[rel.index_addr].begin.addr() + rel.offset; - - switch ((u32)rel.type) - { - case 1: - LOG_NOTICE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr())); - *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr(); - break; - - case 4: - LOG_NOTICE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr())); - *vm::ptr::make(ADDR) = (u16)(u64)rel.ptr.addr(); - break; - - case 5: - LOG_NOTICE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16)); - *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16; - break; - - case 6: - LOG_WARNING(LOADER, "**** RELOCATION(6): 0x%x <- 0x%x", ADDR, (u16)(info.segments[1].begin.addr() >> 16)); - *vm::ptr::make(ADDR) = info.segments[1].begin.addr() >> 16; - break; - - default: - LOG_ERROR(LOADER, "unknown prx relocation type (0x%x)", (u32)rel.type); - return bad_relocation_type; - } - } - - break; - } - } - } - - for (auto &m : info.modules) - { - for (auto &e : m.second.exports) - { - u32 stub = e.second; - - for (auto &s : info.segments) - { - if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) - { - stub += s.begin.addr() - s.initial_addr.addr(); - break; - } - } - - assert(e.second != stub); - e.second = stub; - } - - for (auto &i : m.second.imports) - { - u32 stub = i.second; - - for (auto &s : info.segments) - { - if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) - { - stub += s.begin.addr() - s.initial_addr.addr(); - break; - } - } - - assert(i.second != stub); - i.second = stub; - } - } - - return ok; - } - - handler::error_code elf64::load() - { - if (is_sprx()) - { - sprx_info info; - return load_sprx(info); - } - - //store elf to memory - vm::ps3::init(); - Emu.GetModuleManager().Init(); - - error_code res = alloc_memory(0); - if (res != ok) - { - return res; - } - - std::vector start_funcs; - std::vector stop_funcs; - std::vector exit_funcs; - - //load modules - vfsDir lle_dir("/dev_flash/sys/external"); - - for (const auto module : lle_dir) - { - if (module->flags & DirEntry_TypeDir) - { - continue; - } - - if (rpcs3::state.config.core.load_liblv2.value()) - { - if (module->name != "liblv2.sprx") - { - continue; - } - } - - elf64 sprx_handler; - - vfsFile fsprx(lle_dir.GetPath() + "/" + module->name); - - if (fsprx.IsOpened()) - { - sprx_handler.init(fsprx); - - if (sprx_handler.is_sprx()) - { - if (!rpcs3::state.config.core.load_liblv2.value()) - { - if (rpcs3::config.lle.get_entry_value(sprx_handler.sprx_get_module_name(), false) == false) - { - continue; - } - } - - LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str()); - - sprx_info info; - sprx_handler.load_sprx(info); - - for (auto &m : info.modules) - { - if (m.first == "") - { - for (auto &e : m.second.exports) - { - auto code = vm::cptr::make(vm::check_addr(e.second, 8) ? vm::read32(e.second).value() : 0); - - bool is_empty = !code || (code[0] == 0x38600000 && code[1] == BLR()); - - if (!code) - { - LOG_ERROR(LOADER, "bad OPD of special function 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code); - } - - switch (e.first) - { - case 0xbc9a0086: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "start func found in '%s' library (0x%x)", info.name.c_str(), code); - start_funcs.push_back(e.second); - } - break; - } - - case 0xab779874: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "stop func found in '%s' library (0x%x)", info.name.c_str(), code); - stop_funcs.push_back(e.second); - } - break; - } - - case 0x3ab9a95e: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "exit func found in '%s' library (0x%x)", info.name.c_str(), code); - exit_funcs.push_back(e.second); - } - break; - } - - default: LOG_ERROR(LOADER, "unknown special func 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code); break; - } - } - - continue; - } - - Module<>* module = Emu.GetModuleManager().GetModuleByName(m.first.c_str()); - - if (!module) - { - LOG_ERROR(LOADER, "Unknown module '%s' in '%s' library", m.first.c_str(), info.name.c_str()); - } - - for (auto& f : m.second.exports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr::make(addr))); - } - else - { - func->lle_func.set(addr); - - if (func->flags & MFF_FORCED_HLE) - { - u32 i_addr = 0; - - if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4)) - { - LOG_ERROR(LOADER, "Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr); - } - else - { - vm::write32(i_addr, HACK(index | EIF_PERFORM_BLR)); - } - } - } - } - - for (auto& f : m.second.imports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - LOG_ERROR(LOADER, "Unknown function '%s' (0x%x)", get_ps3_function_name(nid), addr); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", get_ps3_function_name(nid), addr); - } - - if (!patch_ppu_import(addr, index)) - { - LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", get_ps3_function_name(nid), addr); - } - } - } - } - } - } - - res = load_data(0); - if (res != ok) - return res; - - //initialize process - auto rsx_callback_data = vm::ptr::make(vm::alloc(4 * 4, vm::main)); - *rsx_callback_data++ = (rsx_callback_data + 1).addr(); - Emu.SetRSXCallback(rsx_callback_data.addr()); - - rsx_callback_data[0] = ADDI(r11, 0, 0x3ff); - rsx_callback_data[1] = SC(0); - rsx_callback_data[2] = BLR(); - - auto ppu_thr_stop_data = vm::ptr::make(vm::alloc(2 * 4, vm::main)); - ppu_thr_stop_data[0] = SC(3); - ppu_thr_stop_data[1] = BLR(); - Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); - - Emu.GetModuleManager().Alloc(); - - static const int branch_size = 8 * 4; - - auto make_branch = [](vm::ptr& ptr, u32 addr) - { - u32 stub = vm::read32(addr); - u32 rtoc = vm::read32(addr + 4); - - *ptr++ = LI_(r0, 0); - *ptr++ = ORI(r0, r0, stub & 0xffff); - *ptr++ = ORIS(r0, r0, stub >> 16); - *ptr++ = LI_(r2, 0); - *ptr++ = ORI(r2, r2, rtoc & 0xffff); - *ptr++ = ORIS(r2, r2, rtoc >> 16); - *ptr++ = MTCTR(r0); - *ptr++ = BCTRL(); - }; - - auto entry = vm::ptr::make(vm::alloc(56 + branch_size * (start_funcs.size() + 1), vm::main)); - - const auto OPD = entry; - - // make initial OPD - *entry++ = OPD.addr() + 8; - *entry++ = 0xdeadbeef; - - // save initialization args - *entry++ = MR(r14, r3); - *entry++ = MR(r15, r4); - *entry++ = MR(r16, r5); - *entry++ = MR(r17, r6); - *entry++ = MR(r18, r11); - *entry++ = MR(r19, r12); - - for (auto &f : start_funcs) - { - make_branch(entry, f); - } - - // restore initialization args - *entry++ = MR(r3, r14); - *entry++ = MR(r4, r15); - *entry++ = MR(r5, r16); - *entry++ = MR(r6, r17); - *entry++ = MR(r11, r18); - *entry++ = MR(r12, r19); - - // branch to initialization - make_branch(entry, m_ehdr.e_entry); - - const auto decoder_cache = fxm::make(); - - for (u32 page = 0; page < 0x20000000; page += 4096) - { - // TODO: scan only executable areas - if (vm::check_addr(page, 4096)) - { - decoder_cache->initialize(page, 4096); - } - } - - ppu_thread main_thread(OPD.addr(), "main_thread"); - - main_thread.args({ Emu.GetPath()/*, "-emu"*/ }).run(); - main_thread.gpr(11, OPD.addr()).gpr(12, Emu.GetMallocPageSize()); - - return ok; - } - - handler::error_code elf64::alloc_memory(u64 offset) - { - for (auto &phdr : m_phdrs) - { - switch (phdr.p_type.value()) - { - case 0x00000001: //LOAD - { - if (phdr.p_memsz) - { - if (!vm::falloc(phdr.p_vaddr.addr(), phdr.p_memsz, vm::main)) - { - LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%llx) failed", __FUNCTION__, phdr.p_vaddr.addr(), phdr.p_memsz); - - return loading_error; - } - } - break; - } - } - } - - return ok; - } - - handler::error_code elf64::load_data(u64 offset) - { - for (auto &phdr : m_phdrs) - { - switch (phdr.p_type.value()) - { - case 0x00000001: //LOAD - { - if (phdr.p_memsz) - { - if (phdr.p_filesz) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - m_stream->Read(phdr.p_vaddr.get_ptr(), phdr.p_filesz); - - if (rpcs3::state.config.core.hook_st_func.value()) - { - hook_ppu_funcs(vm::static_ptr_cast(phdr.p_vaddr), phdr.p_filesz / 4); - } - } - } - break; - } - - case 0x00000007: //TLS - { - Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz, phdr.p_memsz); - break; - } - - case 0x60000001: //LOOS+1 - { - if (phdr.p_filesz) - { - struct process_param_t - { - be_t size; - be_t magic; - be_t version; - be_t sdk_version; - be_t primary_prio; - be_t primary_stacksize; - be_t malloc_pagesize; - be_t ppc_seg; - //be_t crash_dump_param_addr; - }; - - const auto& info = *(process_param_t*)phdr.p_vaddr.get_ptr(); - - if (info.size < sizeof(process_param_t)) - { - LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); - } - if (info.magic != 0x13bcc5f6) - { - LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); - } - else - { - LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); - LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); - LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); - LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); - LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); - //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); - - Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); - } - } - break; - } - - case 0x60000002: //LOOS+2 - { - if (phdr.p_filesz) - { - const sys_proc_prx_param& proc_prx_param = *(sys_proc_prx_param*)phdr.p_vaddr.get_ptr(); - - if (proc_prx_param.magic != 0x1b434cec) - { - LOG_ERROR(LOADER, "Bad magic! (0x%x)", proc_prx_param.magic); - break; - } - - for (auto stub = proc_prx_param.libstubstart; stub < proc_prx_param.libstubend; ++stub) - { - const std::string module_name = stub->s_modulename.get_ptr(); - - Module<>* module = Emu.GetModuleManager().GetModuleByName(module_name.c_str()); - - if (!module) - { - LOG_ERROR(LOADER, "Unknown module '%s'", module_name.c_str()); - } - - for (u32 i = 0; i < stub->s_imports; ++i) - { - const u32 nid = stub->s_nid[i]; - const u32 addr = stub->s_text[i]; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - LOG_ERROR(LOADER, "Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_name, addr); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE); - - LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", get_ps3_function_name(nid), module_name, addr); - } - - if (!patch_ppu_import(addr, index)) - { - LOG_ERROR(LOADER, "Failed to inject code at address 0x%x", addr); - } - } - } - } - break; - } - default: - { - LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", phdr.p_type); - } - } - } - - return ok; - } - } -} diff --git a/rpcs3/Loader/ELF64.h b/rpcs3/Loader/ELF64.h deleted file mode 100644 index bb0120ecd5..0000000000 --- a/rpcs3/Loader/ELF64.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once -#include "Loader.h" - -struct vfsStream; - -namespace loader -{ - namespace handlers - { - class elf64 : public handler - { - public: - struct ehdr - { - be_t e_magic; - u8 e_class; - u8 e_data; - u8 e_curver; - u8 e_os_abi; - be_t e_abi_ver; - be_t e_type; - be_t e_machine; - be_t e_version; - be_t e_entry; - be_t e_phoff; - be_t e_shoff; - be_t e_flags; - be_t e_ehsize; - be_t e_phentsize; - be_t e_phnum; - be_t e_shentsize; - be_t e_shnum; - be_t e_shstrndx; - - bool check() const { return e_magic == 0x7F454C46; } - } m_ehdr; - - struct phdr - { - be_t p_type; - be_t p_flags; - be_t p_offset; - _ptr_base> p_vaddr; - _ptr_base> p_paddr; - be_t p_filesz; - be_t p_memsz; - be_t p_align; - }; - - struct shdr - { - be_t sh_name; - be_t sh_type; - be_t sh_flags; - _ptr_base> sh_addr; - be_t sh_offset; - be_t sh_size; - be_t sh_link; - be_t sh_info; - be_t sh_addralign; - be_t sh_entsize; - }; - - struct sprx_module_info - { - be_t attr; - u8 version[2]; - char name[28]; - be_t toc_addr; - be_t export_start; - be_t export_end; - be_t import_start; - be_t import_end; - } m_sprx_module_info; - - struct sprx_export_info - { - u8 size; - u8 padding; - be_t version; - be_t attr; - be_t func_count; - be_t vars_count; - be_t tls_vars_count; - be_t hash_info; - be_t tls_hash_info; - u8 reserved[2]; - be_t lib_name_offset; - be_t nid_offset; - be_t stub_offset; - }; - - struct sprx_import_info - { - u8 size; - u8 unused; - be_t version; - be_t attr; - be_t func_count; - be_t vars_count; - be_t tls_vars_count; - u8 reserved[4]; - be_t lib_name_offset; - be_t nid_offset; - be_t stub_offset; - //... - }; - - struct sprx_function_info - { - be_t name_table_offset; - be_t entry_table_offset; - be_t padding; - } m_sprx_function_info; - - struct sprx_lib_info - { - std::string name; - }; - - struct sprx_segment_info - { - _ptr_base begin; - u32 size; - u32 size_file; - _ptr_base initial_addr; - std::vector modules; - }; - - struct sprx_info - { - std::string name; - u32 rtoc; - - struct module_info - { - std::unordered_map exports; - std::unordered_map imports; - }; - - std::unordered_map modules; - std::vector segments; - }; - - std::vector m_phdrs; - std::vector m_shdrs; - - std::vector m_sprx_segments_info; - std::vector m_sprx_import_info; - std::vector m_sprx_export_info; - - public: - virtual ~elf64() = default; - - error_code init(vfsStream& stream) override; - error_code load() override; - error_code alloc_memory(u64 offset); - error_code load_data(u64 offset); - error_code load_sprx(sprx_info& info); - bool is_sprx() const { return m_ehdr.e_type == 0xffa4; } - std::string sprx_get_module_name() const { return m_sprx_module_info.name; } - }; - } -} diff --git a/rpcs3/Loader/Loader.cpp b/rpcs3/Loader/Loader.cpp deleted file mode 100644 index dcc0e2d5f7..0000000000 --- a/rpcs3/Loader/Loader.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "stdafx.h" -#include "Loader.h" -#include "PSF.h" -#include "Emu/FS/vfsLocalFile.h" - -namespace loader -{ - bool loader::load(vfsStream& stream) - { - for (auto i : m_handlers) - { - i->set_status(i->init(stream)); - if (i->get_status() == handler::ok) - { - i->set_status(i->load()); - if (i->get_status() == handler::ok) - { - return true; - } - - LOG_NOTICE(LOADER, "loader::load() failed: %s", i->get_error_code().c_str()); - } - else - { - LOG_NOTICE(LOADER, "loader::init() failed: %s", i->get_error_code().c_str()); - stream.Seek(i->get_stream_offset()); - } - } - - return false; - } - - handler::error_code handler::init(vfsStream& stream) - { - m_stream_offset = stream.Tell(); - m_stream = &stream; - - return ok; - } -}; - -static const u64 g_spu_offset = 0x10000; - -const std::string Ehdr_DataToString(const u8 data) -{ - if(data > 1) return fmt::format("%d's complement, big endian", data); - if(data < 1) return "Data is not found"; - - return fmt::format("%d's complement, little endian", data); -} - -const std::string Ehdr_TypeToString(const u16 type) -{ - switch(type) - { - case 0: return "NULL"; - case 2: return "EXEC (Executable file)"; - }; - - return fmt::format("Unknown (%d)", type); -} - -const std::string Ehdr_OS_ABIToString(const u8 os_abi) -{ - switch(os_abi) - { - case 0x0 : return "UNIX System V"; - case 0x66: return "Cell OS LV-2"; - }; - - return fmt::format("Unknown (0x%x)", os_abi); -} - -const std::string Ehdr_MachineToString(const u16 machine) -{ - switch(machine) - { - case MACHINE_MIPS: return "MIPS"; - case MACHINE_PPC64: return "PowerPC64"; - case MACHINE_SPU: return "SPU"; - case MACHINE_ARM: return "ARM"; - }; - - return fmt::format("Unknown (0x%x)", machine); -} - -const std::string Phdr_FlagsToString(u32 flags) -{ - enum {ppu_R = 0x1, ppu_W = 0x2, ppu_E = 0x4}; - enum {spu_E = 0x1, spu_W = 0x2, spu_R = 0x4}; - enum {rsx_R = 0x1, rsx_W = 0x2, rsx_E = 0x4}; - -#define FLAGS_TO_STRING(f) \ - std::string(f & f##_R ? "R" : "-") + \ - std::string(f & f##_W ? "W" : "-") + \ - std::string(f & f##_E ? "E" : "-") - - const u8 ppu = flags & 0xf; - const u8 spu = (flags >> 0x14) & 0xf; - const u8 rsx = (flags >> 0x18) & 0xf; - - std::string ret; - ret += fmt::format("[0x%x] ", flags); - - flags &= ~ppu; - flags &= ~spu << 0x14; - flags &= ~rsx << 0x18; - - if(flags != 0) return fmt::format("Unknown %s PPU[0x%x] SPU[0x%x] RSX[0x%x]", ret.c_str(), ppu, spu, rsx); - - ret += "PPU[" + FLAGS_TO_STRING(ppu) + "] "; - ret += "SPU[" + FLAGS_TO_STRING(spu) + "] "; - ret += "RSX[" + FLAGS_TO_STRING(rsx) + "]"; - - return ret; -} - -const std::string Phdr_TypeToString(const u32 type) -{ - switch(type) - { - case 0x00000001: return "LOAD"; - case 0x00000004: return "NOTE"; - case 0x00000007: return "TLS"; - case 0x60000001: return "LOOS+1"; - case 0x60000002: return "LOOS+2"; - }; - - return fmt::format("Unknown (0x%x)", type); -} diff --git a/rpcs3/Loader/Loader.h b/rpcs3/Loader/Loader.h deleted file mode 100644 index 0b6834ccbd..0000000000 --- a/rpcs3/Loader/Loader.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once -#include "Emu/Memory/vm.h" - -struct vfsFileBase; -struct vfsStream; - -#ifdef _DEBUG - //#define LOADER_DEBUG -#endif - -enum Elf_Machine -{ - MACHINE_Unknown, - MACHINE_MIPS = 0x08, - MACHINE_PPC64 = 0x15, - MACHINE_SPU = 0x17, - MACHINE_ARM = 0x28 -}; - -enum ShdrType -{ - SHT_NULL, - SHT_PROGBITS, - SHT_SYMTAB, - SHT_STRTAB, - SHT_RELA, - SHT_HASH, - SHT_DYNAMIC, - SHT_NOTE, - SHT_NOBITS, - SHT_REL, - SHT_SHLIB, - SHT_DYNSYM -}; - -enum ShdrFlag -{ - SHF_WRITE = 0x1, - SHF_ALLOC = 0x2, - SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xf0000000 -}; - -const std::string Ehdr_DataToString(const u8 data); -const std::string Ehdr_TypeToString(const u16 type); -const std::string Ehdr_OS_ABIToString(const u8 os_abi); -const std::string Ehdr_MachineToString(const u16 machine); -const std::string Phdr_FlagsToString(u32 flags); -const std::string Phdr_TypeToString(const u32 type); - -namespace loader -{ - class handler - { - u64 m_stream_offset; - - protected: - vfsStream* m_stream; - - public: - enum error_code - { - bad_version = -1, - bad_file = -2, - broken_file = -3, - loading_error = -4, - bad_relocation_type = -5, - ok = 0 - }; - - virtual ~handler() = default; - - virtual error_code init(vfsStream& stream); - virtual error_code load() = 0; - u64 get_stream_offset() const - { - return m_stream_offset; - } - - void set_status(const error_code& code) - { - m_status = code; - } - - error_code get_status() const - { - return m_status; - } - - const std::string get_error_code() const - { - switch (m_status) - { - case bad_version: return "Bad version"; - case bad_file: return "Bad file"; - case broken_file: return "Broken file"; - case loading_error: return "Loading error"; - case bad_relocation_type: return "Bad relocation type"; - case ok: return "Ok"; - - default: return "Unknown error code"; - } - } - - protected: - error_code m_status; - }; - - class loader - { - std::vector m_handlers; - - public: - ~loader() - { - for (auto &h : m_handlers) - { - delete h; - } - } - - void register_handler(handler* handler) - { - m_handlers.push_back(handler); - } - - bool load(vfsStream& stream); - }; - - using namespace vm; -} diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index 3a9c5838b4..7292b2079f 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -3,7 +3,7 @@ namespace psf { - _log::channel log("PSF"); + _log::channel log("PSF", _log::level::notice); struct header_t { @@ -25,26 +25,26 @@ namespace psf const std::string& entry::as_string() const { - CHECK_ASSERTION(m_type == format::string || m_type == format::array); + Expects(m_type == format::string || m_type == format::array); return m_value_string; } u32 entry::as_integer() const { - CHECK_ASSERTION(m_type == format::integer); + Expects(m_type == format::integer); return m_value_integer; } entry& entry::operator =(const std::string& value) { - CHECK_ASSERTION(m_type == format::string || m_type == format::array); + Expects(m_type == format::string || m_type == format::array); m_value_string = value; return *this; } entry& entry::operator =(u32 value) { - CHECK_ASSERTION(m_type == format::integer); + Expects(m_type == format::integer); m_value_integer = value; return *this; } @@ -61,10 +61,10 @@ namespace psf return SIZE_32(u32); } - throw EXCEPTION("Invalid format (0x%x)", m_type); + throw fmt::exception("Invalid format (0x%x)" HERE, m_type); } - registry load(const std::vector& data) + registry load_object(const std::vector& data) { registry result; @@ -75,18 +75,18 @@ namespace psf } // Check size - CHECK_ASSERTION(data.size() >= sizeof(header_t)); - CHECK_ASSERTION((std::uintptr_t)data.data() % 8 == 0); + Expects(data.size() >= sizeof(header_t)); + Expects((std::uintptr_t)data.data() % 8 == 0); // Get header const header_t& header = reinterpret_cast(data[0]); // Check magic and version - CHECK_ASSERTION(header.magic == *(u32*)"\0PSF"); - CHECK_ASSERTION(header.version == 0x101); - CHECK_ASSERTION(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); - CHECK_ASSERTION(header.off_key_table <= header.off_data_table); - CHECK_ASSERTION(header.off_data_table <= data.size()); + Expects(header.magic == "\0PSF"_u32); + Expects(header.version == 0x101); + Expects(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); + Expects(header.off_key_table <= header.off_data_table); + Expects(header.off_data_table <= data.size()); // Get indices (alignment should be fine) const def_table_t* indices = reinterpret_cast(data.data() + sizeof(header_t)); @@ -94,7 +94,7 @@ namespace psf // Load entries for (u32 i = 0; i < header.entries_num; ++i) { - CHECK_ASSERTION(indices[i].key_off < header.off_data_table - header.off_key_table); + Expects(indices[i].key_off < header.off_data_table - header.off_key_table); // Get key name range const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off; @@ -103,10 +103,10 @@ namespace psf // Get name (must be unique) std::string key(name_ptr, name_end); - CHECK_ASSERTION(result.count(key) == 0); - CHECK_ASSERTION(indices[i].param_len <= indices[i].param_max); - CHECK_ASSERTION(indices[i].data_off < data.size() - header.off_data_table); - CHECK_ASSERTION(indices[i].param_max < data.size() - indices[i].data_off); + Expects(result.count(key) == 0); + Expects(indices[i].param_len <= indices[i].param_max); + Expects(indices[i].data_off < data.size() - header.off_data_table); + Expects(indices[i].param_max < data.size() - indices[i].data_off); // Get data pointer const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off; @@ -147,7 +147,7 @@ namespace psf return result; } - std::vector save(const registry& psf) + std::vector save_object(const registry& psf) { std::vector indices; indices.reserve(psf.size()); @@ -175,7 +175,7 @@ namespace psf // Generate header header_t header; - header.magic = *(u32*)"\0PSF"; + header.magic = "\0PSF"_u32; header.version = 0x101; header.off_key_table = gsl::narrow(sizeof(header_t) + sizeof(def_table_t) * psf.size()); header.off_data_table = gsl::narrow(header.off_key_table + key_offset); diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index 0a03d76caf..ed360ed2b8 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace psf { enum class format : u16 @@ -23,8 +25,8 @@ namespace psf , m_max_size(max_size) , m_value_string(value) { - CHECK_ASSERTION(type == format::string || type == format::array); - CHECK_ASSERTION(max_size); + Expects(type == format::string || type == format::array); + Expects(max_size); } // Construct integer entry, assign the value @@ -49,11 +51,24 @@ namespace psf // Define PSF registry as a sorted map of entries: using registry = std::map; - // Load PSF registry from binary data - registry load(const std::vector&); + // Load PSF registry from SFO binary data + registry load_object(const std::vector&); - // Convert PSF registry to binary format - std::vector save(const registry&); + // Load PSF registry from SFO file, if opened + inline registry load_object(const fs::file& f) + { + if (f) + { + return load_object(f.to_vector()); + } + else + { + return registry{}; + } + } + + // Convert PSF registry to SFO binary format + std::vector save_object(const registry&); // Get string value or default value std::string get_string(const registry& psf, const std::string& key, const std::string& def = {}); diff --git a/rpcs3/Loader/TROPUSR.cpp b/rpcs3/Loader/TROPUSR.cpp index 00f8473846..bd3e859a41 100644 --- a/rpcs3/Loader/TROPUSR.cpp +++ b/rpcs3/Loader/TROPUSR.cpp @@ -1,52 +1,41 @@ #include "stdafx.h" #include "Utilities/rXml.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" #include "Emu/System.h" #include "TROPUSR.h" -TROPUSRLoader::TROPUSRLoader() -{ - m_file = NULL; - memset(&m_header, 0, sizeof(m_header)); -} - -TROPUSRLoader::~TROPUSRLoader() -{ - Close(); -} - bool TROPUSRLoader::Load(const std::string& filepath, const std::string& configpath) { - if (m_file) - { - Close(); - } + const std::string& path = vfs::get(filepath); - if (!Emu.GetVFS().ExistsFile(filepath)) + if (!fs::is_file(path)) { Generate(filepath, configpath); } - m_file = Emu.GetVFS().OpenFile(filepath, fom::read); - LoadHeader(); - LoadTableHeaders(); - LoadTables(); + if (!m_file.open(path, fs::read)) + { + return false; + } - Close(); + if (!LoadHeader() || !LoadTableHeaders() || !LoadTables()) + { + return false; + } + + m_file.release(); return true; } bool TROPUSRLoader::LoadHeader() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } - m_file->Seek(0); + m_file.seek(0); - if (m_file->Read(&m_header, sizeof(TROPUSRHeader)) != sizeof(TROPUSRHeader)) + if (!m_file.read(m_header)) { return false; } @@ -56,18 +45,18 @@ bool TROPUSRLoader::LoadHeader() bool TROPUSRLoader::LoadTableHeaders() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } - m_file->Seek(0x30); + m_file.seek(0x30); m_tableHeaders.clear(); m_tableHeaders.resize(m_header.tables_count); for (TROPUSRTableHeader& tableHeader : m_tableHeaders) { - if (m_file->Read(&tableHeader, sizeof(TROPUSRTableHeader)) != sizeof(TROPUSRTableHeader)) + if (!m_file.read(tableHeader)) return false; } @@ -76,14 +65,14 @@ bool TROPUSRLoader::LoadTableHeaders() bool TROPUSRLoader::LoadTables() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } for (const TROPUSRTableHeader& tableHeader : m_tableHeaders) { - m_file->Seek(tableHeader.offset); + m_file.seek(tableHeader.offset); if (tableHeader.type == 4) { @@ -92,7 +81,7 @@ bool TROPUSRLoader::LoadTables() for (auto& entry : m_table4) { - if (m_file->Read(&entry, sizeof(TROPUSREntry4)) != sizeof(TROPUSREntry4)) + if (!m_file.read(entry)) return false; } } @@ -104,7 +93,7 @@ bool TROPUSRLoader::LoadTables() for (auto& entry : m_table6) { - if (m_file->Read(&entry, sizeof(TROPUSREntry6)) != sizeof(TROPUSREntry6)) + if (!m_file.read(entry)) return false; } } @@ -118,39 +107,39 @@ bool TROPUSRLoader::LoadTables() // TODO: TROPUSRLoader::Save deletes the TROPUSR and creates it again. This is probably very slow. bool TROPUSRLoader::Save(const std::string& filepath) { - if (m_file) + if (!m_file.open(vfs::get(filepath), fs::rewrite)) { - Close(); + return false; } - m_file = Emu.GetVFS().OpenFile(filepath, fom::rewrite); - m_file->Write(&m_header, sizeof(TROPUSRHeader)); + m_file.write(m_header); for (const TROPUSRTableHeader& tableHeader : m_tableHeaders) { - m_file->Write(&tableHeader, sizeof(TROPUSRTableHeader)); + m_file.write(tableHeader); } for (const auto& entry : m_table4) { - m_file->Write(&entry, sizeof(TROPUSREntry4)); + m_file.write(entry); } for (const auto& entry : m_table6) { - m_file->Write(&entry, sizeof(TROPUSREntry6)); + m_file.write(entry); } - m_file->Close(); - + m_file.release(); return true; } bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& configpath) { - std::string path; + const std::string& path = vfs::get(configpath); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); rXmlDocument doc; - Emu.GetVFS().GetDevice(configpath.c_str(), path); doc.Load(path); m_table4.clear(); @@ -238,13 +227,3 @@ bool TROPUSRLoader::UnlockTrophy(u32 id, u64 timestamp1, u64 timestamp2) return true; } - -void TROPUSRLoader::Close() -{ - if (m_file) - { - m_file->Close(); - delete m_file; - m_file = nullptr; - } -} diff --git a/rpcs3/Loader/TROPUSR.h b/rpcs3/Loader/TROPUSR.h index e3d2921aae..128b5b0064 100644 --- a/rpcs3/Loader/TROPUSR.h +++ b/rpcs3/Loader/TROPUSR.h @@ -1,7 +1,5 @@ #pragma once -struct vfsStream; - struct TROPUSRHeader { be_t magic; // 81 8F 54 AD @@ -56,8 +54,8 @@ struct TROPUSREntry6 class TROPUSRLoader { - vfsStream* m_file; - TROPUSRHeader m_header; + fs::file m_file; + TROPUSRHeader m_header{}; std::vector m_tableHeaders; std::vector m_table4; @@ -69,12 +67,8 @@ class TROPUSRLoader virtual bool LoadTables(); public: - TROPUSRLoader(); - ~TROPUSRLoader(); - virtual bool Load(const std::string& filepath, const std::string& configpath); virtual bool Save(const std::string& filepath); - virtual void Close(); virtual u32 GetTrophiesCount(); diff --git a/rpcs3/Loader/TRP.cpp b/rpcs3/Loader/TRP.cpp index 2a8123cf55..28cfc3b108 100644 --- a/rpcs3/Loader/TRP.cpp +++ b/rpcs3/Loader/TRP.cpp @@ -1,42 +1,34 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" #include "TRP.h" -TRPLoader::TRPLoader(vfsStream& f) : trp_f(f) +TRPLoader::TRPLoader(const fs::file& f) + : trp_f(f) { } -TRPLoader::~TRPLoader() +bool TRPLoader::Install(const std::string& dest, bool show) { - Close(); -} - -bool TRPLoader::Install(std::string dest, bool show) -{ - if (!trp_f.IsOpened()) + if (!trp_f) { return false; } - if (!dest.empty() && dest.back() != '/') + const std::string& local_path = vfs::get(dest); + + if (!fs::create_dir(local_path) && errno != EEXIST) { - dest += '/'; + return false; } - if (!Emu.GetVFS().ExistsDir(dest)) - { - Emu.GetVFS().CreateDir(dest); - } + std::vector buffer; buffer.reserve(65536); for (const TRPEntry& entry : m_entries) { - char* buffer = new char [(u32)entry.size]; - trp_f.Seek(entry.offset); - trp_f.Read(buffer, entry.size); - vfsFile(dest + entry.name, fom::rewrite).Write(buffer, entry.size); - delete[] buffer; + trp_f.seek(entry.offset); + buffer.resize(entry.size); + if (!trp_f.read(buffer)) continue; // ??? + fs::file(local_path + '/' + entry.name, fs::rewrite).write(buffer); } return true; @@ -44,14 +36,14 @@ bool TRPLoader::Install(std::string dest, bool show) bool TRPLoader::LoadHeader(bool show) { - if (!trp_f.IsOpened()) + if (!trp_f) { return false; } - trp_f.Seek(0); + trp_f.seek(0); - if (trp_f.Read(&m_header, sizeof(TRPHeader)) != sizeof(TRPHeader)) + if (!trp_f.read(m_header)) { return false; } @@ -71,7 +63,7 @@ bool TRPLoader::LoadHeader(bool show) for (u32 i = 0; i < m_header.trp_files_count; i++) { - if (trp_f.Read(&m_entries[i], sizeof(TRPEntry)) != sizeof(TRPEntry)) + if (!trp_f.read(m_entries[i])) { return false; } @@ -123,8 +115,3 @@ void TRPLoader::RenameEntry(const char *oldname, const char *newname) } } } - -void TRPLoader::Close() -{ - trp_f.Close(); -} diff --git a/rpcs3/Loader/TRP.h b/rpcs3/Loader/TRP.h index f2818ad525..46c687058a 100644 --- a/rpcs3/Loader/TRP.h +++ b/rpcs3/Loader/TRP.h @@ -1,7 +1,5 @@ #pragma once -struct vfsStream; - struct TRPHeader { be_t trp_magic; @@ -23,21 +21,19 @@ struct TRPEntry char padding[12]; }; -class TRPLoader +class TRPLoader final { - vfsStream& trp_f; + const fs::file& trp_f; TRPHeader m_header; std::vector m_entries; public: - TRPLoader(vfsStream& f); - ~TRPLoader(); - virtual bool Install(std::string dest, bool show = false); - virtual bool LoadHeader(bool show = false); + TRPLoader(const fs::file& f); - virtual bool ContainsEntry(const char *filename); - virtual void RemoveEntry(const char *filename); - virtual void RenameEntry(const char *oldname, const char *newname); + bool Install(const std::string& dest, bool show = false); + bool LoadHeader(bool show = false); - virtual void Close(); + bool ContainsEntry(const char *filename); + void RemoveEntry(const char *filename); + void RenameEntry(const char *oldname, const char *newname); };