diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index fe29ef58dc99..a47a9ba35def 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1407,7 +1407,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 ca9982c0e561..3493864bd288 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 db4915b25d7b..c7c9458a1170 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -11,6 +11,7 @@ #include "Emu/Cell/PPUModule.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" @@ -33,8 +34,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; @@ -1057,6 +1056,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; @@ -1083,8 +1083,14 @@ void ppu_load_exec(const ppu_exec_object& elf) 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); + // Check if .rsx_image segment + const bool is_rsx_image = addr == 0x10000000; + + if (auto area = vm::reserve_map(!is_rsx_image ? vm::main : vm::rsx_image, 0, u32{is_rsx_image} << 28, ((flag >> 24) & 0x7) ? 0x400 : 0x200); + !area || !area->falloc(addr, size)) + { + fmt::throw_exception("falloc() failed (addr=0x%x, memsz=0x%x)" HERE, addr, size); + } // Copy segment data, hash it std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); @@ -1103,6 +1109,9 @@ void ppu_load_exec(const ppu_exec_object& elf) } } + // Allocate user 64k allocation block + vm::reserve_map(vm::user64k, 0, 0x20000000, 0x201); + // Load section list, used by the analyser for (const auto& s : elf.shdrs) { @@ -1212,6 +1221,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); @@ -1465,7 +1475,27 @@ 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 != 0) + { + if (vm::get(vm::rsx_image)) + { + // TODO: Check this + fmt::throw_exception("Unhandled ppc seg allocation" HERE); + } + + if (ppc_seg != 1) + { + LOG_TODO(LOADER, "Unknown ppc_seg flag = 0x%x", ppc_seg); + } + + // Additional segment for fixed allocations + vm::reserve_map(vm::main_ex, 0, 0x10000000, 0x200); + } // 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 8c0c6166d252..e0e42ce44dac 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -427,7 +427,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 4c9e0e8c3e4a..871f81b9703c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -45,7 +45,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)) { @@ -109,7 +109,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 99ebf627a8ca..e635f7ef23ee 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp @@ -6,7 +6,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); @@ -14,11 +16,14 @@ 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, std::string 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, path2, flags, entry); + if (!g_ps3_process_info.ppc_seg) + { + // Process not permitted + return CELL_ENOSYS; + } - 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()); @@ -40,6 +45,32 @@ 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 (!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, flags=0x%x, entry=*0x%x)", ovlmid, fd, flags, entry); + + 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); +} + 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 ad89d76d612e..acf6fd6f6dd0 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 dd103431b368..65da852662f3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.h +++ b/rpcs3/Emu/Cell/lv2/sys_process.h @@ -34,6 +34,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 76e206fbbb91..d532a9a5b99e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/Memory/vm.h" #include "Emu/System.h" #include "Emu/IdManager.h" @@ -8,6 +8,7 @@ #include "Emu/Cell/ErrorCodes.h" #include "Crypto/unedat.h" #include "sys_fs.h" +#include "sys_process.h" #include "sys_prx.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 ((u32)flags) + { + 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 ffc967e604bc..4db694c73a01 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -135,6 +135,12 @@ struct lv2_prx final : lv2_obj, ppu_module be_t module_info_attributes; }; +enum : u64 +{ + SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR = 1, + SYS_PRX_LOAD_MODULE_FLAGS_INVALIDMASK = 0xFFFFFFFE +}; + // 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 d9e89a4aded0..df3bebe2326f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -186,7 +186,7 @@ error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 f for (u32 addr = ea, end = ea + size; addr < end; addr += 0x100000) { - if (!vm::check_addr(addr, 1, vm::page_allocated | (addr < 0x20000000 ? 0 : vm::page_1m_size))) + if (!vm::check_addr(addr, 1, vm::page_allocated | vm::page_1m_size)) { return CELL_EINVAL; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 0e4fed623e01..cfd498c6c3e4 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -892,7 +892,7 @@ namespace vm static std::shared_ptr _find_map(u32 size, u32 align, u64 flags) { - for (u32 addr = ::align(0x20000000, align); addr < 0xC0000000; addr += align) + for (u32 addr = ::align(0x10000000, align); addr < 0xC0000000; addr += align) { if (_test_map(addr, size)) { @@ -930,6 +930,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); @@ -995,50 +1020,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; @@ -1050,8 +1073,10 @@ namespace vm { g_locations = { - std::make_shared(0x00010000, 0x1FFF0000, 0x200), // main - std::make_shared(0x20000000, 0x10000000, 0x201), // user 64k pages + std::make_shared(0x00010000, 0x0FFF0000, 0x200), // main + nullptr, // rsx_image + nullptr, // main extended + nullptr, // user 64k pages nullptr, // user 1m pages std::make_shared(0xC0000000, 0x10000000), // video std::make_shared(0xD0000000, 0x10000000, 0x111), // stack diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 2f58ca60e9f6..fc0b9785a350 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -21,6 +21,8 @@ namespace vm enum memory_location_t : uint { main, + rsx_image, + main_ex, user64k, user1m, video, @@ -189,7 +191,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) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 71d0d66f77ad..63a430b488a6 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1568,7 +1568,7 @@ void Emulator::Resume() std::string dump; - for (u32 i = 0x10000; i < 0x20000000;) + for (u32 i = 0x10000; i < 0x10000000;) { if (vm::check_addr(i)) {