From 22f6ba5507ac80334e6307bc1e506eea1adb5455 Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 3 Jul 2019 20:17:04 +0300 Subject: [PATCH] vm/sys_overlay Improvements - Implement sys_overlay_load_module_by_fd. - Implement special segment allocation when ppc_seg flag is specified. --- Utilities/Thread.cpp | 2 +- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 6 +- rpcs3/Emu/Cell/PPUModule.cpp | 24 ++++++- rpcs3/Emu/Cell/lv2/lv2.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_memory.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_overlay.cpp | 59 +++++++++++++++-- rpcs3/Emu/Cell/lv2/sys_overlay.h | 2 +- rpcs3/Emu/Cell/lv2/sys_process.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_process.h | 8 +++ rpcs3/Emu/Cell/lv2/sys_prx.cpp | 16 +++++ rpcs3/Emu/Cell/lv2/sys_prx.h | 6 ++ rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 2 +- rpcs3/Emu/Memory/vm.cpp | 85 ++++++++++++++++--------- rpcs3/Emu/Memory/vm.h | 7 +- 14 files changed, 173 insertions(+), 54 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index e2e0228d82ff..24d4997e1d4c 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1420,7 +1420,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) if (cpu->check_state()) { // Hack: allocate memory in case the emulator is stopping - auto area = vm::get(vm::any, addr & -0x10000, 0x10000); + auto area = vm::reserve_map(vm::any, addr & -0x10000, 0x10000); if (area->flags & 0x100) { diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 54ec7efca01c..68f743ce8f9d 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -16,8 +16,6 @@ LOG_CHANNEL(cellSaveData); -extern u32 g_ps3_sdk_version; - template<> void fmt_class_string::format(std::string& out, u64 arg) { @@ -140,7 +138,7 @@ static bool savedata_check_args(u32 operation, u32 version, vm::cptr dirNa } if (!memchr(setList->dirNamePrefix.get_ptr(), '\0', CELL_SAVEDATA_PREFIX_SIZE) - || (g_ps3_sdk_version > 0x3FFFFF && !setList->dirNamePrefix[0])) + || (g_ps3_process_info.sdk_ver > 0x3FFFFF && !setList->dirNamePrefix[0])) { // ****** sysutil savedata parameter error : 17 ****** return false; @@ -803,7 +801,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v return CELL_SAVEDATA_ERROR_PARAM; } - if (g_ps3_sdk_version > 0x36FFFF) + if (g_ps3_process_info.sdk_ver > 0x36FFFF) { for (u8 resv : statSet->setParam->reserved2) { diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 822ca734584f..80fe1b27ca49 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -12,6 +12,7 @@ #include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/PPUAnalyser.h" +#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_prx.h" #include "Emu/Cell/lv2/sys_memory.h" #include "Emu/Cell/lv2/sys_overlay.h" @@ -34,8 +35,6 @@ extern void ppu_initialize(); extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32); -extern u32 g_ps3_sdk_version; - // HLE function name cache std::vector g_ppu_function_names; @@ -1064,6 +1063,7 @@ void ppu_load_exec(const ppu_exec_object& elf) s32 primary_prio = 1001; u32 primary_stacksize = 0x100000; u32 malloc_pagesize = 0x100000; + u32 ppc_seg = 0; // Executable hash sha1_context sha; @@ -1219,6 +1219,7 @@ void ppu_load_exec(const ppu_exec_object& elf) primary_stacksize = info.primary_stacksize; malloc_pagesize = info.malloc_pagesize; + ppc_seg = info.ppc_seg; LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); @@ -1472,7 +1473,24 @@ void ppu_load_exec(const ppu_exec_object& elf) _main->validate(0); // Set SDK version - g_ps3_sdk_version = sdk_version; + g_ps3_process_info.sdk_ver = sdk_version; + + // Set ppc fixed allocations segment permission + g_ps3_process_info.ppc_seg = ppc_seg; + + if (ppc_seg != 0x0) + { + if (ppc_seg != 0x1) + { + LOG_TODO(LOADER, "Unknown ppc_seg flag value = 0x%x", ppc_seg); + } + + // Additional segment for fixed allocations + if (!vm::map(0x30000000, 0x10000000, 0x200)) + { + fmt::throw_exception("Failed to map ppc_seg's segment!" HERE); + } + } // Initialize process arguments auto args = vm::ptr::make(vm::alloc(u32{sizeof(u64)} * (::size32(Emu.argv) + ::size32(Emu.envp) + 2), vm::main)); diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 762f88eab655..d1feb0c42042 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -429,7 +429,7 @@ const std::array s_ppu_syscall_table 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) + BIND_FUNC(sys_overlay_load_module_by_fd), //454 (0x1C6) null_func,//BIND_FUNC(sys_overlay_get_module_info2) //455 (0x1C7) null_func,//BIND_FUNC(sys_overlay_get_sdk_version) //456 (0x1C8) null_func,//BIND_FUNC(sys_overlay_get_module_dbg_info) //457 (0x1C9) diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 007fe82a9212..b11c70b44d7d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -52,7 +52,7 @@ error_code sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) return CELL_ENOMEM; } - if (const auto area = vm::get(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000))) + if (const auto area = vm::reserve_map(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000), 0x401)) { if (u32 addr = area->alloc(size, align)) { @@ -118,7 +118,7 @@ error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm:: // Create phantom memory object const auto mem = idm::make_ptr(size, align, flags, ct.ptr); - if (const auto area = vm::get(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000))) + if (const auto area = vm::reserve_map(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000), 0x401)) { if (u32 addr = area->alloc(size, mem->align, &mem->shm)) { diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp index b1d5fe1874fe..e79a15269ffb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp @@ -7,7 +7,9 @@ #include "Crypto/unedat.h" #include "Loader/ELF.h" +#include "sys_process.h" #include "sys_overlay.h" +#include "sys_fs.h" extern std::shared_ptr ppu_load_overlay(const ppu_exec_object&, const std::string& path); @@ -15,14 +17,16 @@ 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) +static error_code overlay_load_module(vm::ptr ovlmid, const std::string& vpath, u64 flags, vm::ptr entry, fs::file src = {}) { - 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 = vfs::get(vpath); - const std::string path = path2.get_ptr(); - const auto name = path.substr(path.find_last_of('/') + 1); + if (!src) + { + src.open(path); + } - const ppu_exec_object obj = decrypt_self(fs::file(vfs::get(path)), fxm::get_always()->devKlic.data()); + const ppu_exec_object obj = decrypt_self(std::move(src), fxm::get_always()->devKlic.data()); if (obj != elf_error::ok) { @@ -33,7 +37,7 @@ error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path2, u6 ppu_initialize(*ovlm); - sys_overlay.success("Loaded overlay: %s", path); + sys_overlay.success("Loaded overlay: %s", vpath); *ovlmid = idm::last_id(); *entry = ovlm->entry; @@ -41,6 +45,49 @@ error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path2, u6 return CELL_OK; } +error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path, u64 flags, vm::ptr entry) +{ + sys_overlay.warning("sys_overlay_load_module(ovlmid=*0x%x, path=%s, flags=0x%x, entry=*0x%x)", ovlmid, path, flags, entry); + + if (!g_ps3_process_info.ppc_seg) + { + // Process not permitted + return CELL_ENOSYS; + } + + if (!path) + { + return CELL_EFAULT; + } + + return overlay_load_module(ovlmid, path.get_ptr(), flags, entry); +} + +error_code sys_overlay_load_module_by_fd(vm::ptr ovlmid, u32 fd, u64 offset, u64 flags, vm::ptr entry) +{ + sys_overlay.warning("sys_overlay_load_module_by_fd(ovlmid=*0x%x, fd=%d, offset=0x%llx, flags=0x%x, entry=*0x%x)", ovlmid, fd, offset, flags, entry); + + if (!g_ps3_process_info.ppc_seg) + { + // Process not permitted + return CELL_ENOSYS; + } + + if ((s64)offset < 0) + { + return CELL_EINVAL; + } + + const auto file = idm::get(fd); + + if (!file) + { + return CELL_EBADF; + } + + return overlay_load_module(ovlmid, fmt::format("%s_x%x", file->name.data(), offset), flags, entry, lv2_file::make_view(file, offset)); +} + error_code sys_overlay_unload_module(u32 ovlmid) { sys_overlay.warning("sys_overlay_unload_module(ovlmid=0x%x)", ovlmid); diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.h b/rpcs3/Emu/Cell/lv2/sys_overlay.h index 8e168b807ca4..a13ece4ecbdc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.h +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.h @@ -12,10 +12,10 @@ struct lv2_overlay final : lv2_obj, ppu_module }; error_code sys_overlay_load_module(vm::ptr ovlmid, vm::cptr path, u64 flags, vm::ptr entry); +error_code sys_overlay_load_module_by_fd(vm::ptr ovlmid, u32 fd, u64 offset, 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? diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 9c657de2aed2..126b221745e6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -28,7 +28,7 @@ LOG_CHANNEL(sys_process); -u32 g_ps3_sdk_version; +ps3_process_info_t g_ps3_process_info; s32 process_getpid() { @@ -182,7 +182,7 @@ s32 _sys_process_get_paramsfo(vm::ptr buffer) s32 process_get_sdk_version(u32 pid, s32& ver) { // get correct SDK version for selected pid - ver = g_ps3_sdk_version; + ver = g_ps3_process_info.sdk_ver; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h index 0ae695b9a08a..6c258bdc421e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.h +++ b/rpcs3/Emu/Cell/lv2/sys_process.h @@ -36,6 +36,14 @@ struct sys_exit2_param vm::bpptr args; }; +struct ps3_process_info_t +{ + u32 sdk_ver; + u32 ppc_seg; +}; + +extern ps3_process_info_t g_ps3_process_info; + // Auxiliary functions s32 process_getpid(); s32 process_get_sdk_version(u32 pid, s32& ver); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 1390a15bf27f..5543ff4d609b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -9,6 +9,7 @@ #include "Emu/Cell/ErrorCodes.h" #include "Crypto/unedat.h" #include "sys_fs.h" +#include "sys_process.h" @@ -83,6 +84,21 @@ static const std::unordered_map s_prx_ignore static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr pOpt, fs::file src = {}) { + if (flags != 0) + { + if (flags & SYS_PRX_LOAD_MODULE_FLAGS_INVALIDMASK) + { + return CELL_EINVAL; + } + + if (flags & SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR && !g_ps3_process_info.ppc_seg) + { + return CELL_ENOSYS; + } + + fmt::throw_exception("sys_prx: Unimplemented fixed address allocations" HERE); + } + std::string name = vpath.substr(vpath.find_last_of('/') + 1); std::string path = vfs::get(vpath); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index 442fe218240a..14125d5e52e6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -137,6 +137,12 @@ struct lv2_prx final : lv2_obj, ppu_module be_t module_info_attributes; }; +enum : u64 +{ + SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR = 0x1ull, + SYS_PRX_LOAD_MODULE_FLAGS_INVALIDMASK = ~SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR, +}; + // SysCalls error_code sys_prx_get_ppu_guid(); diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 8f6e18930ebf..19ef5f9aae86 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "sys_rsx.h" #include "Emu/System.h" diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 48faf48880eb..bc0b871d8b4a 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -943,6 +943,31 @@ namespace vm return block; } + static std::shared_ptr _get_map(memory_location_t location, u32 addr) + { + if (location != any) + { + // return selected location + if (location < g_locations.size()) + { + return g_locations[location]; + } + + return nullptr; + } + + // search location by address + for (auto& block : g_locations) + { + if (block && addr >= block->addr && addr <= block->addr + block->size - 1) + { + return block; + } + } + + return nullptr; + } + std::shared_ptr map(u32 addr, u32 size, u64 flags) { vm::writer_lock lock(0); @@ -1008,50 +1033,48 @@ namespace vm return nullptr; } - std::shared_ptr get(memory_location_t location, u32 addr, u32 area_size) + std::shared_ptr get(memory_location_t location, u32 addr) { vm::reader_lock lock; - if (location != any) - { - // return selected location - if (location < g_locations.size()) - { - auto& loc = g_locations[location]; + return _get_map(location, addr); + } - if (!loc && area_size) - { - if (location == vm::user64k || location == vm::user1m) - { - lock.upgrade(); + std::shared_ptr reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags) + { + vm::reader_lock lock; - if (!loc) - { - // Deferred allocation - loc = _find_map(area_size, 0x10000000, location == vm::user64k ? 0x201 : 0x401); - } - } - } + auto area = _get_map(location, addr); - return loc; - } + if (area) + { + return area; + } - return nullptr; + lock.upgrade(); + + // Fixed allocation + if (addr) + { + // Recheck + area = _get_map(location, addr); + + return !area ? _map(addr, area_size, flags) : area; } - // search location by address - for (auto& block : g_locations) + // Allocation on arbitrary address + if (location != any && location < g_locations.size()) { - if (block && addr >= block->addr && addr <= block->addr + block->size - 1) + // return selected location + auto& loc = g_locations[location]; + + if (!loc) { - return block; + // Deferred allocation + loc = _find_map(area_size, 0x10000000, flags); } - } - if (area_size) - { - lock.upgrade(); - return _map(addr, area_size, 0x200); + return loc; } return nullptr; diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 1aae3e619d3f..71cfeb7f569e 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -116,7 +116,10 @@ namespace vm std::shared_ptr unmap(u32 addr, bool must_be_empty = false); // Get memory block associated with optionally specified memory location or optionally specified address - std::shared_ptr get(memory_location_t location, u32 addr = 0, u32 area_size = 0); + std::shared_ptr get(memory_location_t location, u32 addr = 0); + + // Allocate segment at specified location, does nothing if exists already + std::shared_ptr reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags = 0x200); // Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0) inline vm::addr_t get_addr(const void* real_ptr)