diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index 7ecf9f1b2c2b..570ea6164005 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -4,6 +4,8 @@ #include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_memory.h" +#include "util/asm.hpp" #include "cellAudio.h" #include @@ -1182,6 +1184,7 @@ error_code cellAudioInit() cellAudio.warning("cellAudioInit()"); auto& g_audio = g_fxo->get(); + auto& dct = g_fxo->get(); std::lock_guard lock(g_audio.mutex); @@ -1190,6 +1193,12 @@ error_code cellAudioInit() return CELL_AUDIO_ERROR_ALREADY_INIT; } + // TODO: This is the minimum amount, it can allocate more if specified by VSH (needs investigation) + if (!dct.take(0x10000)) + { + return CELL_AUDIO_ERROR_SHAREDMEMORY; + } + std::memset(g_audio_buffer.get_ptr(), 0, g_audio_buffer.alloc_size); std::memset(g_audio_indices.get_ptr(), 0, g_audio_indices.alloc_size); @@ -1211,6 +1220,7 @@ error_code cellAudioQuit() cellAudio.warning("cellAudioQuit()"); auto& g_audio = g_fxo->get(); + auto& dct = g_fxo->get(); std::lock_guard lock(g_audio.mutex); @@ -1219,6 +1229,19 @@ error_code cellAudioQuit() return CELL_AUDIO_ERROR_NOT_INIT; } + // See cellAudioInit + u32 to_free = 0x10000; + + for (auto& port : g_audio.ports) + { + if (port.state.exchange(audio_port_state::closed) != audio_port_state::closed) + { + to_free += utils::align(port.size, 0x10000) + 0x10000; + } + } + + dct.free(to_free); + // NOTE: Do not clear event queues here. They are handled independently. g_audio.init = 0; @@ -1231,6 +1254,8 @@ error_code cellAudioPortOpen(vm::ptr audioParam, vm::ptrget(); + auto& dct = g_fxo->get(); + std::lock_guard lock(g_audio.mutex); if (!g_audio.init) @@ -1298,6 +1323,9 @@ error_code cellAudioPortOpen(vm::ptr audioParam, vm::ptr(num_channels * num_blocks * AUDIO_BUFFER_SAMPLES * sizeof(f32)); + const u32 mem_page_size = utils::align(mem_size, 0x10000) + 0x10000; + // Open audio port const auto port = g_audio.open_port(); @@ -1306,13 +1334,20 @@ error_code cellAudioPortOpen(vm::ptr audioParam, vm::ptrstate.compare_and_swap_test(audio_port_state::opened, audio_port_state::closed)); + return CELL_AUDIO_ERROR_SHAREDMEMORY; + } + // TODO: is this necessary in any way? (Based on libaudio.prx) //const u64 num_channels_non_0 = std::max(1, num_channels); port->num_channels = ::narrow(num_channels); port->num_blocks = ::narrow(num_blocks); port->attr = attr; - port->size = ::narrow(num_channels * num_blocks * AUDIO_BUFFER_SAMPLES * sizeof(f32)); + port->size = mem_size; port->cur_pos = 0; port->global_counter = g_audio.m_counter; port->active_counter = 0; @@ -1431,10 +1466,14 @@ error_code cellAudioPortClose(u32 portNum) switch (auto state = g_audio.ports[portNum].state.exchange(audio_port_state::closed)) { case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - case audio_port_state::started: return CELL_OK; - case audio_port_state::opened: return CELL_OK; + case audio_port_state::started: break; + case audio_port_state::opened: break; default: fmt::throw_exception("Invalid port state (%d: %d)", portNum, static_cast(state)); } + + const u32 mem_page_size = utils::align(g_audio.ports[portNum].size, 0x10000) + 0x10000; + g_fxo->get().free(mem_page_size); + return CELL_OK; } error_code cellAudioPortStop(u32 portNum) diff --git a/rpcs3/Emu/Cell/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp index 3a33c4b8deab..5fa8fbc935bd 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -6,6 +6,9 @@ #include "sceNp2.h" #include "Emu/NP/np_handler.h" #include "Emu/NP/np_contexts.h" +#include "Emu/Cell/Modules/sysPrxForUser.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_sync.h" #include "cellSysutil.h" LOG_CHANNEL(sceNp2); @@ -174,9 +177,9 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr param); +error_code sceNpMatching2Init2(ppu_thread& ppu, u64 stackSize, s32 priority, vm::ptr param); error_code sceNpMatching2Term(ppu_thread& ppu); -error_code sceNpMatching2Term2(); +error_code sceNpMatching2Term2(ppu_thread& ppu); error_code generic_match2_error_check(const named_thread& nph, SceNpMatching2ContextId ctxId, vm::cptr reqParam, vm::ptr assignedReqId) { @@ -229,13 +232,33 @@ error_code sceNp2Init(u32 poolsize, vm::ptr poolptr) return CELL_OK; } -error_code sceNpMatching2Init(u32 stackSize, s32 priority) +error_code sceNpMatching2Init(ppu_thread& ppu, u32 stackSize, s32 priority) { sceNp2.todo("sceNpMatching2Init(stackSize=0x%x, priority=%d)", stackSize, priority); - return sceNpMatching2Init2(stackSize, priority, vm::null); // > SDK 2.4.0 + return sceNpMatching2Init2(ppu, stackSize, priority, vm::null); // > SDK 2.4.0 } -error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr param) +static void s_matching2_thread_func(ppu_thread& ppu) +{ + lv2_obj::sleep(ppu); + auto& nph = g_fxo->get>(); + + while (nph.is_NP2_Match2_init && thread_ctrl::state() != thread_state::aborting && !ppu.is_stopped()) + { + thread_ctrl::wait_on(nph.is_NP2_Match2_init, true); + } + + if (!nph.is_NP2_Match2_init) + { + ppu_execute<&sys_ppu_thread_exit>(ppu, 0); + } + else + { + ppu.state += cpu_flag::again; + } +} + +error_code sceNpMatching2Init2(ppu_thread& ppu, u64 stackSize, s32 priority, vm::ptr param) { sceNp2.todo("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param); @@ -252,9 +275,18 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr _tid; + vm::var _name = vm::make_str("SceNpMatching2ScCb"); + + const u32 stack_size = stackSize ? stackSize : 0x4000; + + // TODO: error checking + ensure(ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, g_fxo->get().func_addr(FIND_FUNC(s_matching2_thread_func)), 0, priority, stack_size, SYS_PPU_THREAD_CREATE_JOINABLE, +_name) == CELL_OK); + + nph.np2_match2_thread_id = static_cast(*_tid); nph.is_NP2_Match2_init = true; @@ -285,13 +317,13 @@ error_code sceNp2Term(ppu_thread& ppu) return CELL_OK; } -error_code sceNpMatching2Term(ppu_thread&) +error_code sceNpMatching2Term(ppu_thread& ppu) { sceNp2.warning("sceNpMatching2Term()"); - return sceNpMatching2Term2(); // > SDK 2.4.0 + return sceNpMatching2Term2(ppu); // > SDK 2.4.0 } -error_code sceNpMatching2Term2() +error_code sceNpMatching2Term2(ppu_thread& ppu) { sceNp2.warning("sceNpMatching2Term2()"); @@ -310,6 +342,9 @@ error_code sceNpMatching2Term2() } nph.is_NP2_Match2_init = false; + nph.is_NP2_Match2_init.notify_one(); + + ensure(sys_ppu_thread_join(ppu, nph.np2_match2_thread_id, +vm::var{}) == CELL_OK); } // TODO: for all contexts: sceNpMatching2DestroyContext @@ -1738,8 +1773,8 @@ error_code sceNpAuthGetAuthorizationCode2() return CELL_OK; } -DECLARE(ppu_module_manager::sceNp2) -("sceNp2", []() { +DECLARE(ppu_module_manager::sceNp2)("sceNp2", []() +{ REG_FUNC(sceNp2, sceNpMatching2DestroyContext); REG_FUNC(sceNp2, sceNpMatching2LeaveLobby); REG_FUNC(sceNp2, sceNpMatching2RegisterLobbyMessageCallback); @@ -1821,4 +1856,6 @@ DECLARE(ppu_module_manager::sceNp2) REG_FUNC(sceNp2, sceNpAuthAbortOAuthRequest); REG_FUNC(sceNp2, sceNpAuthGetAuthorizationCode); REG_FUNC(sceNp2, sceNpAuthGetAuthorizationCode2); + + REG_HIDDEN_FUNC(s_matching2_thread_func); }); diff --git a/rpcs3/Emu/Cell/Modules/sys_io_.cpp b/rpcs3/Emu/Cell/Modules/sys_io_.cpp index abbdb53cd53a..70cd8d20c545 100644 --- a/rpcs3/Emu/Cell/Modules/sys_io_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_io_.cpp @@ -2,6 +2,10 @@ #include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_sync.h" +#include "Emu/Cell/Modules/sysPrxForUser.h" + LOG_CHANNEL(sys_io); @@ -12,17 +16,37 @@ extern void cellMouse_init(); struct libio_sys_config { shared_mutex mtx; - s32 init_ctr = 0; - u32 stack_addr = 0; + atomic_t init_ctr = 0; + u32 ppu_id = 0; +}; + +static void s_evt_hndlr_thread_func(ppu_thread& ppu) +{ + lv2_obj::sleep(ppu); - ~libio_sys_config() noexcept + auto& cfg = g_fxo->get(); + + while (thread_ctrl::state() != thread_state::aborting && !ppu.is_stopped()) { - if (stack_addr) + const s32 ctr = cfg.init_ctr; + + if (!ctr) { - ensure(vm::dealloc(stack_addr, vm::stack)); + break; } + + thread_ctrl::wait_on(cfg.init_ctr, ctr); } -}; + + if (!cfg.init_ctr) + { + ppu_execute<&sys_ppu_thread_exit>(ppu, 0); + } + else + { + ppu.state += cpu_flag::again; + } +} // Only exists internally (has no name) extern void libio_sys_config_init() @@ -34,7 +58,10 @@ extern void libio_sys_config_init() if (cfg.init_ctr++ == 0) { // Belongs to "_cfg_evt_hndlr" thread (8k stack) - cfg.stack_addr = ensure(vm::alloc(0x2000, vm::stack, 4096)); + vm::var _tid; + vm::var _name = vm::make_str("_cfg_evt_hndlr"); + ensure(ppu_execute<&sys_ppu_thread_create>(*cpu_thread::get_current(), +_tid, g_fxo->get().func_addr(FIND_FUNC(s_evt_hndlr_thread_func)), 0, 3071, 0x2000, SYS_PPU_THREAD_CREATE_JOINABLE, +_name) == CELL_OK); + cfg.ppu_id = static_cast(*_tid); } } @@ -46,7 +73,8 @@ extern void libio_sys_config_end() if (cfg.init_ctr-- == 1) { - ensure(vm::dealloc(std::exchange(cfg.stack_addr, 0), vm::stack)); + cfg.init_ctr.notify_one(); + ensure(sys_ppu_thread_join(*cpu_thread::get_current(), cfg.ppu_id, +vm::var{}) == CELL_OK); } } @@ -114,4 +142,6 @@ DECLARE(ppu_module_manager::sys_io)("sys_io", []() REG_FUNC(sys_io, sys_config_register_service); REG_FUNC(sys_io, sys_config_unregister_io_error_handler); REG_FUNC(sys_io, sys_config_unregister_service); + + REG_HIDDEN_FUNC(s_evt_hndlr_thread_func); }); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 430338662b06..103d0cc0bb6e 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1142,7 +1142,7 @@ const char* get_prx_name_by_cia(u32 addr) return nullptr; } -std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::string& path, s64 file_offset, utils::serial* ar) +std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::string& path, s64 file_offset, bool is_hle, utils::serial* ar) { if (elf != elf_error::ok) { @@ -1416,7 +1416,11 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri ppu_loader.warning("Library %s (rtoc=0x%x):", lib_name, lib_info->toc); - prx->specials = ppu_load_exports(&link, lib_info->exports_start, lib_info->exports_end); + if (!is_hle) + { + prx->specials = ppu_load_exports(&link, lib_info->exports_start, lib_info->exports_end); + } + prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end); std::stable_sort(prx->relocs.begin(), prx->relocs.end()); toc = lib_info->toc; @@ -1434,6 +1438,7 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri prx->name = path.substr(path.find_last_of('/') + 1); prx->path = path; prx->offset = file_offset; + prx->is_hle = is_hle; g_fxo->need(); g_fxo->get().install(prx->name, *prx); @@ -1532,10 +1537,13 @@ void ppu_unload_prx(const lv2_prx& prx) // Format patch name std::string hash = fmt::format("PRX-%s", fmt::base57(prx.sha1)); + u32 segs_size = 0; + for (auto& seg : prx.segs) { if (!seg.size) continue; + segs_size += utils::align(seg.size, 0x10000); vm::dealloc(seg.addr, vm::main); const std::string hash_seg = fmt::format("%s-%u", hash, &seg - prx.segs.data()); @@ -1549,6 +1557,11 @@ void ppu_unload_prx(const lv2_prx& prx) g_fxo->get().unload(Emu.GetTitleID() + '-' + hash_seg); } } + + if (prx.mem_ct) + { + ensure(prx.mem_ct->free(segs_size)); + } } bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar) @@ -1622,6 +1635,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar) } error_handler{_main}; + u32 segs_size = 0; + // Allocate memory at fixed positions for (const auto& prog : elf.progs) { @@ -1694,6 +1709,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar) // Store only LOAD segments (TODO) _main.segs.emplace_back(_seg); + segs_size += utils::align(size + (addr % 0x10000), 0x10000); } } @@ -2036,7 +2052,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar) { ppu_loader.warning("Loading library: %s", name); - auto prx = ppu_load_prx(obj, lle_dir + name, 0, nullptr); + auto prx = ppu_load_prx(obj, lle_dir + name, 0, false, nullptr); if (prx->funcs.empty()) { @@ -2144,7 +2160,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar) ppu->gpr[1] -= Emu.data.size(); } - ensure(g_fxo->get().take(primary_stacksize)); + ensure(g_fxo->get().take(primary_stacksize + segs_size)); ppu->cmd_push({ppu_cmd::initialize, 0}); diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index 416ab2d0bad8..1928b9ae80c3 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -294,7 +294,7 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args) return func(ppu, args...); } -#define BIND_FUNC_WITH_BLR(func) BIND_FUNC(func, ppu.cia = static_cast(ppu.lr) & ~3) +#define BIND_FUNC_WITH_BLR(func) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast(ppu.lr) & ~3) #define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func), ppu_generate_id(nid)) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 74a462feea15..9b8ead4dd3d9 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -24,6 +24,7 @@ #include "lv2/sys_prx.h" #include "lv2/sys_overlay.h" #include "lv2/sys_process.h" +#include "lv2/sys_memory.h" #include "lv2/sys_spu.h" #ifdef LLVM_AVAILABLE @@ -161,7 +162,7 @@ extern bool ppu_initialize(const ppu_module& info, bool = false); static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name); extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, const std::string& path, s64 file_offset, utils::serial* = nullptr); extern void ppu_unload_prx(const lv2_prx&); -extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&, s64 file_offset, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&, s64 file_offset, bool is_hle = false, utils::serial* = nullptr); extern void ppu_execute_syscall(ppu_thread& ppu, u64 code); static void ppu_break(ppu_thread&, ppu_opcode_t, be_t*, ppu_intrp_func*); @@ -3176,6 +3177,24 @@ extern void ppu_initialize() compile_fw = false; } + if (!Emu.DeserialManager()) + { + // Moved here for backwards compatibility with savestates + + u32 segs_size = 0; + + for (auto& seg : _module.segs) + { + segs_size += utils::align(seg.size, 0x10000); + } + + if (segs_size) + { + _module.mem_ct = g_fxo->try_get(); + ensure(_module.mem_ct->take(segs_size)); + } + } + module_list.emplace_back(&_module); }); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index e31393acb3d7..b4e9bab7ac33 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -13,9 +13,10 @@ #include "sys_fs.h" #include "sys_process.h" #include "sys_memory.h" +#include "util/asm.hpp" #include -extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&, s64, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&, s64, bool is_hle, utils::serial* = nullptr); extern void ppu_unload_prx(const lv2_prx& prx); extern bool ppu_initialize(const ppu_module&, bool = false); extern void ppu_finalize(const ppu_module&); @@ -170,7 +171,7 @@ extern const std::map g_prx_list { "libwmadec.sprx", 0 }, }; -static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr /*pOpt*/, fs::file src = {}, s64 file_offset = 0) +static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr /*pOpt*/ = vm::null, u32 mem_ct = SYS_MEMORY_CONTAINER_ID_INVALID, fs::file src = {}, s64 file_offset = 0) { if (flags != 0) { @@ -235,17 +236,14 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr(); - prx->name = std::move(name); - prx->path = std::move(path); - - sys_prx.warning(u8"Ignored module: “%s” (id=0x%x)", vpath, idm::last_id()); - + prx->path = path; + prx->name = path.substr(path.find_last_of(fs::delim) + 1); return not_an_error(idm::last_id()); }; if (ignore) { - return hle_load(); + sys_prx.warning(u8"Ignored module: “%s” (id=0x%x)", vpath, idm::last_id()); } if (!src) @@ -275,15 +273,52 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr(::narrow(prog.p_memsz), 0x10000); + } + + auto& dct = g_fxo->get(); + const auto idm_ct = idm::get(mem_ct); + + const auto ct = mem_ct == SYS_MEMORY_CONTAINER_ID_INVALID ? &g_fxo->get() : idm_ct.get(); + + if (!ct) + { + //return CELL_ESRCH; + } + + // TODO: It hasn't been confirmed the memory container is actually used, nor what happens on illegal one + if (ct == &dct && !ct->take(segs_size)) + { + return CELL_ENOMEM; + } + + const auto prx = ppu_load_prx(obj, path, file_offset, ignore); obj.clear(); if (!prx) { + if (prx->mem_ct) + { + prx->mem_ct->free(segs_size); + } + return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } + prx->mem_ct = ct == &dct ? ct : nullptr; + ppu_initialize(*prx); sys_prx.success(u8"Loaded module: “%s” (id=0x%x)", vpath, idm::last_id()); @@ -299,6 +334,16 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) const s64 offset = ar; const u32 state = ar; + const s32 ver = GET_SERIALIZATION_VERSION(lv2_prx_overlay); + + bool is_hle = false; + u32 mem_id = 0; + + if (ver >= 2) + { + ar(is_hle, mem_id); + } + usz seg_count = 0; ar.deserialize_vle(seg_count); @@ -309,6 +354,7 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) prx = std::make_shared(); prx->path = path; prx->name = path.substr(path.find_last_of(fs::delim) + 1); + prx->is_hle = true; }; if (seg_count) @@ -319,7 +365,8 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) { u128 klic = g_fxo->get().last_key(); file = make_file_view(std::move(file), offset); - prx = ppu_load_prx(ppu_prx_object{ decrypt_self(std::move(file), reinterpret_cast(&klic)) }, path, 0, &ar); + prx = ppu_load_prx(ppu_prx_object{ decrypt_self(std::move(file), reinterpret_cast(&klic)) }, path, 0, is_hle, &ar); + prx->mem_ct = mem_id ? lv2_memory_container::search(mem_id) : nullptr; ensure(prx); } else @@ -352,6 +399,8 @@ void lv2_prx::save(utils::serial& ar) ar(vfs::retrieve(path), offset, state); + ar(is_hle, mem_ct ? mem_ct->id : 0); + // Save segments count ar.serialize_vle(segs.size()); @@ -389,7 +438,7 @@ error_code _sys_prx_load_module_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u64 f return CELL_EBADF; } - return prx_load_module(offset ? fmt::format("%s_x%x", file->name.data(), offset) : file->name.data(), flags, pOpt, lv2_file::make_view(file, offset), offset); + return prx_load_module(offset ? fmt::format("%s_x%x", file->name.data(), offset) : file->name.data(), flags, pOpt, SYS_MEMORY_CONTAINER_ID_INVALID, lv2_file::make_view(file, offset), offset); } error_code _sys_prx_load_module_on_memcontainer_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u32 mem_ct, u64 flags, vm::ptr pOpt) @@ -398,10 +447,24 @@ error_code _sys_prx_load_module_on_memcontainer_by_fd(ppu_thread& ppu, s32 fd, u sys_prx.warning("_sys_prx_load_module_on_memcontainer_by_fd(fd=%d, offset=0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, mem_ct, flags, pOpt); - return _sys_prx_load_module_by_fd(ppu, fd, offset, flags, pOpt); + const auto file = idm::get(fd); + + if (!file) + { + return CELL_EBADF; + } + + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + + return prx_load_module(offset ? fmt::format("%s_x%x", file->name.data(), offset) : file->name.data(), flags, pOpt, mem_ct, lv2_file::make_view(file, offset), offset); } -static error_code prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr path_list, u32 /*mem_ct*/, u64 flags, vm::ptr pOpt, vm::ptr id_list) +static error_code prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr path_list, u32 mem_ct, u64 flags, vm::ptr pOpt, vm::ptr id_list) { if (flags != 0) { @@ -420,7 +483,7 @@ static error_code prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr path_list, u32 mem_ct, u64 flags, vm::ptr pOpt, vm::ptr id_list) { ppu.state += cpu_flag::wait; @@ -464,7 +528,7 @@ error_code _sys_prx_load_module_on_memcontainer(ppu_thread& ppu, vm::cptr sys_prx.warning("_sys_prx_load_module_on_memcontainer(path=%s, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", path, mem_ct, flags, pOpt); - return prx_load_module(path.get_ptr(), flags, pOpt); + return prx_load_module(path.get_ptr(), flags, pOpt, mem_ct); } error_code _sys_prx_load_module(ppu_thread& ppu, vm::cptr path, u64 flags, vm::ptr pOpt) diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index 2df2328f624d..cc87736c4a6d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -171,6 +171,8 @@ enum : u32 PRX_STATE_STOPPED, // Last state, the module cannot be restarted }; +struct lv2_memory_container; + struct lv2_prx final : lv2_obj, ppu_module { static const u32 id_base = 0x23000000; @@ -190,6 +192,9 @@ struct lv2_prx final : lv2_obj, ppu_module u8 module_info_version[2]; be_t module_info_attributes; + lv2_memory_container* mem_ct{}; + bool is_hle = false; + lv2_prx() noexcept = default; lv2_prx(utils::serial&) {} static std::shared_ptr load(utils::serial&); diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index 0b64950edcc1..7589b777d7b6 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -391,6 +391,11 @@ namespace np np_memory.save(ar); + if (GET_SERIALIZATION_VERSION(sceNp) >= 2) + { + ar(np2_match2_thread_id); + } + // TODO: IDM-tied objects are not yet saved } @@ -430,6 +435,8 @@ namespace np ar(is_NP_Lookup_init, is_NP_Score_init, is_NP2_init, is_NP2_Match2_init, is_NP_Auth_init, manager_cb, manager_cb_arg, std::as_bytes(std::span(&basic_handler, 1)), is_connected, is_psn_active, hostname, ether_address, local_ip_addr, public_ip_addr, dns_ip); np_memory.save(ar); + + ar(np2_match2_thread_id); } void memory_allocator::save(utils::serial& ar) diff --git a/rpcs3/Emu/NP/np_handler.h b/rpcs3/Emu/NP/np_handler.h index d1762250586e..9969032838ef 100644 --- a/rpcs3/Emu/NP/np_handler.h +++ b/rpcs3/Emu/NP/np_handler.h @@ -107,6 +107,8 @@ namespace np vm::ptr manager_cb{}; // Connection status and tickets vm::ptr manager_cb_arg{}; + u32 np2_match2_thread_id = 0; + // Basic event handler; struct { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 3ce6c6973f8f..682ac29f676a 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -76,7 +76,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector ppu_load_prx(const ppu_prx_object&, const std::string&, s64 = 0, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&, s64 = 0, bool = false, utils::serial* = nullptr); extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, const std::string& path, s64 = 0, utils::serial* = nullptr); extern bool ppu_load_rel_exec(const ppu_rel_object&); extern bool is_savestate_version_compatible(const std::vector>& data, bool is_boot_check); diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 1c1d00d5bb23..e498879dace7 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -42,7 +42,7 @@ SERIALIZATION_VER(lv2_sync, 3, 1) SERIALIZATION_VER(lv2_vm, 4, 1) SERIALIZATION_VER(lv2_net, 5, 1) SERIALIZATION_VER(lv2_fs, 6, 1) -SERIALIZATION_VER(lv2_prx_overlay, 7, 1) +SERIALIZATION_VER(lv2_prx_overlay, 7, 1, 2/*Add HLE memory allocs*/) SERIALIZATION_VER(lv2_memory, 8, 1) SERIALIZATION_VER(lv2_config, 9, 1) @@ -53,7 +53,7 @@ namespace rsx namespace np { - SERIALIZATION_VER(sceNp, 11, 1) + SERIALIZATION_VER(sceNp, 11, 1, 2/*PPU match2 ID*/) } #ifdef _MSC_VER