diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 7e51422099..805193d284 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -678,10 +678,10 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo std::lock_guard lock(link->mutex); usz unload_index = 0; + ppu_prx_module_info lib{}; - for (u32 addr = exports_start; addr < exports_end; unload_index++) + for (u32 addr = exports_start; addr < exports_end; unload_index++, addr += lib.size ? lib.size : sizeof(ppu_prx_module_info)) { - ppu_prx_module_info lib{}; std::memcpy(&lib, vm::base(addr), sizeof(lib)); const bool is_library = !!(lib.attributes & PRX_EXPORT_LIBRARY_FLAG); @@ -712,20 +712,17 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo result.emplace(nid, addr); } - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); continue; } if (!is_library) { // Skipped if none of the flags is set - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); continue; } if (for_observing_callbacks) { - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); continue; } @@ -738,7 +735,6 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo ppu_register_library_lock(module_name, false); } - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); continue; } @@ -759,7 +755,6 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo if (!should_load) { ppu_loader.notice("** Skipped module '%s' (already loaded)", module_name); - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); continue; } @@ -861,8 +856,6 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo } } } - - addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); } return result; @@ -1516,10 +1509,20 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri prx->module_info_version[0] = lib_info->version[0]; prx->module_info_version[1] = lib_info->version[1]; prx->module_info_attributes = lib_info->attributes; - + prx->exports_start = lib_info->exports_start; prx->exports_end = lib_info->exports_end; + for (usz start = prx->exports_start, size = 0;; size++, start += vm::read8(start) ? vm::read8(start) : sizeof(ppu_prx_module_info)) + { + if (start >= prx->exports_end) + { + // Preallocate storage + prx->m_external_loaded_flags.resize(size); + break; + } + } + ppu_loader.warning("Library %s (rtoc=0x%x):", lib_name, lib_info->toc); prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 3d17622535..bc36fd4b37 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -3208,6 +3208,11 @@ extern void ppu_initialize() idm::select([&](u32, lv2_prx& _module) { + if (_module.funcs.empty()) + { + return; + } + if (_module.path.starts_with(firmware_sprx_path)) { // Postpone testing diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 525491bf73..ac0ef90149 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1267,7 +1267,7 @@ std::string spu_thread::dump_misc() const void spu_thread::cpu_on_stop() { - if (current_func) + if (current_func && is_stopped(state - cpu_flag::stop)) { if (start_time) { @@ -1496,7 +1496,7 @@ void spu_thread::cpu_task() unsavable = false; // Print some stats - spu_log.notice("Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure); + (!group || group->stop_count < 5 ? spu_log.notice : spu_log.trace)("Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure); } else { diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 9e1ee60882..b398eba3c3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -308,11 +308,12 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) if (seg_count) { - std::basic_string loaded_flags; + std::basic_string loaded_flags, external_flags; - if (version >= 3) + if (version >= 4) { ar(loaded_flags); + ar(external_flags); } fs::file file{path.substr(0, path.size() - (offset ? fmt::format("_x%x", offset).size() : 0))}; @@ -323,13 +324,14 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) 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->m_loaded_flags = std::move(loaded_flags); - - if (version == 2 && state == PRX_STATE_STARTED) + prx->m_external_loaded_flags = std::move(external_flags); + + if (version == 2 && (state == PRX_STATE_STARTED || state == PRX_STATE_STARTING)) { prx->load_exports(); } - if (version == 3 && state == PRX_STATE_STARTED) + if (version >= 4 && state <= PRX_STATE_STARTED) { prx->restore_exports(); } @@ -377,6 +379,7 @@ void lv2_prx::save(utils::serial& ar) if (!segs.empty()) { ar(m_loaded_flags); + ar(m_external_loaded_flags); } for (const ppu_segment& seg : segs) @@ -765,9 +768,9 @@ void lv2_prx::restore_exports() std::basic_string loaded_flags_empty; - for (usz start = exports_start, i = 0; start < exports_end; i++, start += sizeof_export_data) + for (usz start = exports_start, i = 0; start < exports_end; i++, start += vm::read8(start) ? vm::read8(start) : sizeof_export_data) { - if (::at32(m_loaded_flags, i)) + if (::at32(m_external_loaded_flags, i) || (!m_loaded_flags.empty() && ::at32(m_loaded_flags, i))) { loaded_flags_empty.clear(); ppu_manual_load_imports_exports(0, 0, start, sizeof_export_data, loaded_flags_empty); @@ -783,7 +786,14 @@ void lv2_prx::unload_exports() return; } - ppu_manual_load_imports_exports(0, 0, exports_start, exports_end - exports_start, m_loaded_flags); + std::basic_string merged = m_loaded_flags; + + for (usz i = 0; i < merged.size(); i++) + { + merged[i] |= ::at32(m_external_loaded_flags, i); + } + + ppu_manual_load_imports_exports(0, 0, exports_start, exports_end - exports_start, merged); } error_code _sys_prx_register_module(ppu_thread& ppu, vm::cptr name, vm::ptr opt) @@ -864,7 +874,39 @@ error_code _sys_prx_register_library(ppu_thread& ppu, vm::ptr library) return CELL_EFAULT; } - ppu_manual_load_imports_exports(0, 0, library.addr(), 0x1c, *std::make_unique>()); + constexpr u32 sizeof_lib = 0x1c; + + std::array mem_copy{}; + std::memcpy(mem_copy.data(), library.get_ptr(), sizeof_lib); + + std::basic_string flags; + ppu_manual_load_imports_exports(0, 0, library.addr(), sizeof_lib, flags); + + if (flags.front()) + { + const bool success = idm::select([&](u32 id, lv2_prx& prx) + { + if (prx.state == PRX_STATE_INITIALIZED) + { + for (u32 lib_addr = prx.exports_start, index = 0; lib_addr < prx.exports_end; index++, lib_addr += vm::read8(lib_addr) ? vm::read8(lib_addr) : sizeof_lib) + { + if (std::memcpy(vm::base(lib_addr), mem_copy.data(), sizeof_lib) == 0) + { + atomic_storage::release(prx.m_external_loaded_flags[index], true); + return true; + } + } + } + + return false; + }).ret; + + if (!success) + { + sys_prx.error("_sys_prx_register_library(): Failed to associate library to PRX!"); + } + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index fc7c6f4381..e700a3c99e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -72,7 +72,7 @@ struct sys_prx_module_info_t be_t all_segments_num; // 0x34 vm::bptr filename; // 0x38 be_t filename_size; // 0x3c - vm::bptr segments; // 0x40 + vm::bptr segments; // 0x40 be_t segments_num; // 0x44 }; @@ -196,6 +196,7 @@ struct lv2_prx final : lv2_obj, ppu_module u32 exports_end = 0; std::basic_string m_loaded_flags; + std::basic_string m_external_loaded_flags; void load_exports(); // (Re)load exports void restore_exports(); // For savestates diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 8f0470b1e9..99b01283d1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "sys_vm.h" +#include "sys_process.h" #include "Emu/IdManager.h" #include "Emu/Cell/ErrorCodes.h" @@ -70,7 +71,8 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 if (!g_fxo->get().total_vsize.fetch_op([vsize](u32& size) { // A single process can hold up to 256MB of virtual memory, even on DECR - if (0x10000000 - size < vsize) + // VSH can hold more + if ((g_ps3_process_info.has_root_perm() ? 0x1E000000 : 0x10000000) - size < vsize) { return false; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b1eac754eb..085c2552a3 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1077,10 +1077,10 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool m_path = disc; m_path += std::string_view(argv[0]).substr(9); } - else if (argv[0].starts_with("/host_root"sv)) + else if (argv[0].starts_with("/host_root/"sv)) { sys_log.error("Host root has been used in path redirection!"); - m_path = argv[0].substr(9); + m_path = argv[0].substr(11); } else if (argv[0].starts_with("/dev_hdd1"sv)) { diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 06ac0bf158..ef5a827f5f 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -75,6 +75,10 @@ bool vfs::mount(std::string_view vpath, std::string_view path, bool is_dir) list.back()->path += '/'; if (!is_dir && list.back()->path.ends_with('/')) vfs_log.error("File mounted with trailing /."); + + if (path == "/") // Special + list.back()->path = "/"; + vfs_log.notice("Mounted path \"%s\" to \"%s\"", vpath_backup, list.back()->path); return true; } @@ -376,21 +380,19 @@ std::string vfs::retrieve(std::string_view path, const vfs_directory* node, std: std::vector mount_path_empty; - if (std::string res = vfs::retrieve(path, &table.root, &mount_path_empty); !res.empty()) + const std::string rpath = Emu.GetCallbacks().resolve_path(path); + + if (!rpath.empty()) { - return res; + if (std::string res = vfs::retrieve(rpath, &table.root, &mount_path_empty); !res.empty()) + { + return res; + } } mount_path_empty.clear(); - const std::string rpath = Emu.GetCallbacks().resolve_path(path); - - if (rpath.empty()) - { - return {}; - } - - return vfs::retrieve(rpath, &table.root, &mount_path_empty); + return vfs::retrieve(path, &table.root, &mount_path_empty); } mount_path->emplace_back(); diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 21f91ae3a6..669d2675c2 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, 2/*RECV/SEND timeout*/) SERIALIZATION_VER(lv2_fs, 6, 1) -SERIALIZATION_VER(lv2_prx_overlay, 7, 1, 2/*PRX dynamic exports*/, 3/*Conditionally Loaded Local Exports*/) +SERIALIZATION_VER(lv2_prx_overlay, 7, 1, 2/*PRX dynamic exports*/, 4/*Conditionally Loaded Local Exports*/) SERIALIZATION_VER(lv2_memory, 8, 1) SERIALIZATION_VER(lv2_config, 9, 1) diff --git a/rpcs3/rpcs3qt/localized.cpp b/rpcs3/rpcs3qt/localized.cpp index f816c4b746..f0f176c5f0 100644 --- a/rpcs3/rpcs3qt/localized.cpp +++ b/rpcs3/rpcs3qt/localized.cpp @@ -72,7 +72,7 @@ Localized::sound::sound() Localized::title_t::title_t() : titles({ - { "vsh/module/vsh.self", tr("XMB (VSH)") }, + { "vsh/module/vsh.self", tr("The PS3 Interface (XMB, or VSH)") }, }) { }