diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index dfc3d6ea244f..6163ce77b963 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -4,6 +4,8 @@ #include "Emu/Cell/PPUModule.h" #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 @@ -1203,6 +1205,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); @@ -1211,6 +1214,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); @@ -1232,6 +1241,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); @@ -1240,6 +1250,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; @@ -1252,6 +1275,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) @@ -1319,6 +1344,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 audio_port* port = g_audio.open_port(); @@ -1327,13 +1355,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; @@ -1452,10 +1487,14 @@ error_code cellAudioPortClose(u32 portNum) switch (audio_port_state 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 cebda52426f6..c50d70da497e 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -7,6 +7,9 @@ #include "Emu/NP/np_handler.h" #include "Emu/NP/np_contexts.h" #include "Emu/NP/np_helpers.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); @@ -175,9 +178,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) { @@ -230,13 +233,53 @@ 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 (thread_ctrl::state() != thread_state::aborting) + { + const auto state = +ppu.state; + + if (!nph.is_NP2_Match2_init) + { + // Guard against pending awake call + nph.mutex_status.lock_unlock(); + ppu_execute<&sys_ppu_thread_exit>(ppu, 0); + return; + } + + if (state & cpu_flag::signal) + { + if (ppu.state.test_and_reset(cpu_flag::signal)) + { + ppu_execute<&sys_ppu_thread_exit>(ppu, 0); + return; + } + + continue; + } + + if (::is_stopped(state)) + { + break; + } + + thread_ctrl::wait_on(ppu.state, state); + } + + ppu.state += cpu_flag::again; +} + +error_code sceNpMatching2Init2(ppu_thread& ppu, u64 stackSize, s32 priority, vm::ptr param) { sceNp2.warning("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param); @@ -253,9 +296,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; @@ -286,18 +338,19 @@ 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()"); auto& nph = g_fxo->get>(); + u32 ppu_id = 0; { std::lock_guard lock(nph.mutex_status); if (!nph.is_NP2_init) @@ -311,8 +364,15 @@ error_code sceNpMatching2Term2() } nph.is_NP2_Match2_init = false; + + ppu_id = ensure(std::exchange(nph.np2_match2_thread_id, 0)); + + const auto ptr = ensure(idm::get>(ppu_id)); + lv2_obj::awake(ptr.get()); } + ensure(sys_ppu_thread_join(ppu, ppu_id, +vm::var{}) == CELL_OK); + // TODO: for all contexts: sceNpMatching2DestroyContext return CELL_OK; @@ -1789,8 +1849,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); @@ -1872,4 +1932,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/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h index 8870277d55ed..f9a4da7e57fb 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h @@ -62,6 +62,9 @@ error_code sys_lwcond_wait(ppu_thread& CPU, vm::ptr lwcond, u64 ti error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname); error_code sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih); +u32 _sys_malloc(ppu_thread& ppu, u32 size); +error_code _sys_free(ppu_thread& ppu, u32 addr); + void sys_ppu_thread_exit(ppu_thread& CPU, u64 val); void sys_game_process_exitspawn(ppu_thread& ppu, vm::cptr path, vm::cpptr argv, vm::cpptr envp, u32 data, u32 data_size, s32 prio, u64 flags); void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr path, vm::cpptr argv, vm::cpptr envp, u32 data, u32 data_size, s32 prio, u64 flags); diff --git a/rpcs3/Emu/Cell/Modules/sys_io_.cpp b/rpcs3/Emu/Cell/Modules/sys_io_.cpp index c9874f1ffa2e..ec9165f6949f 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" + #include "Emu/Cell/lv2/sys_event.h" #include "Emu/Cell/lv2/sys_ppu_thread.h" @@ -19,6 +23,7 @@ struct libio_sys_config s32 init_ctr = 0; u32 ppu_id = 0; u32 queue_id = 0; + u32 malloc_addr = 0; ~libio_sys_config() noexcept { @@ -38,6 +43,7 @@ void config_event_entry(ppu_thread& ppu) { if (ppu.is_stopped()) { + ppu.state += cpu_flag::again; return; } @@ -45,7 +51,11 @@ void config_event_entry(ppu_thread& ppu) thread_ctrl::wait_for(10000); // Wakeup - ppu.check_state(); + if (ppu.check_state()) + { + ppu.state += cpu_flag::again; + return; + } const u64 arg1 = ppu.gpr[5]; const u64 arg2 = ppu.gpr[6]; @@ -97,6 +107,7 @@ error_code sys_config_start(ppu_thread& ppu) attr->type = SYS_PPU_QUEUE; attr->name_u64 = 0; + ensure(!!(cfg.malloc_addr = ppu_execute<&_sys_malloc>(ppu, 0x7720 + + 0x28 + 0xe90 + 0x14))); ensure(CELL_OK == sys_event_queue_create(ppu, queue_id, attr, 0, 0x20)); ensure(CELL_OK == ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, g_fxo->get().func_addr(FIND_FUNC(config_event_entry)), 0, 512, 0x2000, SYS_PPU_THREAD_CREATE_JOINABLE, +_name)); @@ -119,6 +130,7 @@ error_code sys_config_stop(ppu_thread& ppu) { ensure(CELL_OK == sys_event_queue_destroy(ppu, cfg.queue_id, SYS_EVENT_QUEUE_DESTROY_FORCE)); ensure(CELL_OK == sys_ppu_thread_join(ppu, cfg.ppu_id, +vm::var{})); + ensure(CELL_OK == ppu_execute<&_sys_free>(ppu, cfg.malloc_addr)); } else { diff --git a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp index c5647dc0b221..d9870fd5477b 100644 --- a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp @@ -367,8 +367,10 @@ vm::cptr _sys_strrchr(vm::cptr str, char ch) return res; } -u32 _sys_malloc(u32 size) +u32 _sys_malloc(ppu_thread& ppu, u32 size) { + ppu.state += cpu_flag::wait; + sysPrxForUser.warning("_sys_malloc(size=0x%x)", size); return vm::alloc(size, vm::main); @@ -381,8 +383,10 @@ u32 _sys_memalign(u32 align, u32 size) return vm::alloc(size, vm::main, std::max(align, 0x10000)); } -error_code _sys_free(u32 addr) +error_code _sys_free(ppu_thread& ppu, u32 addr) { + ppu.state += cpu_flag::wait; + sysPrxForUser.warning("_sys_free(addr=0x%x)", addr); vm::dealloc(addr, vm::main); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 2d42accef6a3..92c159ef67d6 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1260,7 +1260,7 @@ const char* get_prx_name_by_cia(u32 addr) return nullptr; } -std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar) +std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, bool is_hle, utils::serial* ar) { if (elf != elf_error::ok) { @@ -1578,10 +1578,10 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo ppu_linkage_info dummy{}; - prx->specials = ppu_load_exports(*prx, virtual_load ? &dummy : &link, prx->exports_start, prx->exports_end, true); - prx->imports = ppu_load_imports(*prx, prx->relocs, virtual_load ? &dummy : &link, lib_info->imports_start, lib_info->imports_end); + prx->specials = ppu_load_exports(*prx, virtual_load || is_hle ? &dummy : &link, prx->exports_start, prx->exports_end); + prx->imports = ppu_load_imports(*prx, prx->relocs, virtual_load || is_hle ? &dummy : &link, lib_info->imports_start, lib_info->imports_end); - if (virtual_load) + if (virtual_load || is_hle) { prx->imports.clear(); } @@ -1602,6 +1602,7 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo 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); @@ -1720,10 +1721,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()); @@ -1737,6 +1741,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, bool virtual_load, const std::string& elf_path, utils::serial* ar) @@ -1818,6 +1827,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str const auto old_process_info = g_ps3_process_info; + u32 segs_size = 0; + // Allocate memory at fixed positions for (const auto& prog : elf.progs) { @@ -1903,6 +1914,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str ppu_register_range(addr, size); } + + segs_size += utils::align(size + (addr % 0x10000), 0x10000); } } @@ -2256,7 +2269,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str { ppu_loader.warning("Loading library: %s", name); - auto prx = ppu_load_prx(obj, false, lle_dir + name, 0, nullptr); + auto prx = ppu_load_prx(obj, false, lle_dir + name, 0, false, nullptr); prx->state = PRX_STATE_STARTED; prx->load_exports(); @@ -2367,7 +2380,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str 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/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index eb9f967fcee3..fa99bf536101 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 @@ -178,7 +179,7 @@ static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_pa extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr); extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, 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&, bool virtual_load, const std::string&, s64 file_offset, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, 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*); @@ -3665,6 +3666,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 4cde5d52e92f..4d16cc404245 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -15,9 +15,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&, bool virtual_load, const std::string&, s64, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64, bool is_hle = false, 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&); @@ -175,7 +176,7 @@ extern const std::map g_prx_list bool ppu_register_library_lock(std::string_view libname, bool lock_lib); -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) { @@ -230,17 +231,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) @@ -270,15 +268,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, false, 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()); @@ -296,6 +331,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); @@ -306,6 +351,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) @@ -320,7 +366,7 @@ 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)) }, false, path, 0, &ar); + prx = ppu_load_prx(ppu_prx_object{ decrypt_self(std::move(file), reinterpret_cast(&klic)) }, false, path, 0, is_hle, &ar); prx->m_loaded_flags = std::move(loaded_flags); prx->m_external_loaded_flags = std::move(external_flags); @@ -329,6 +375,7 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) prx->restore_exports(); } + prx->mem_ct = mem_id ? lv2_memory_container::search(mem_id) : nullptr; ensure(prx); } else @@ -361,6 +408,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()); @@ -404,7 +453,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) @@ -413,10 +462,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) { @@ -435,7 +498,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; @@ -479,7 +543,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 e700a3c99ed6..85fd339fc449 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -172,6 +172,8 @@ enum : u32 PRX_STATE_DESTROYED, // 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; @@ -202,6 +204,9 @@ struct lv2_prx final : lv2_obj, ppu_module void restore_exports(); // For savestates void unload_exports(); + 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 601beba07335..bec3af5cbe73 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -417,6 +417,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 } @@ -466,6 +471,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 043f26bd891c..9dbe86f4c58b 100644 --- a/rpcs3/Emu/NP/np_handler.h +++ b/rpcs3/Emu/NP/np_handler.h @@ -111,6 +111,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 4c909403d8c9..54840f573ec3 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -77,8 +77,8 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 = 0, utils::serial* = nullptr); extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 = 0, utils::serial* = nullptr); +extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 = 0, bool = false, 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); extern std::vector> read_used_savestate_versions(); diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 9b423ed415b7..4f6347991b41 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