PRX/savestates/VSH: Associate PRX with library, fix VSH browser (#13221)

* PRX/savestate:s Associate PRX with library

* VFS/Savestates: Fix host_root resolving

* Savestates: Fix segfault in ppu_initialize

* SPU: Avoid some log spam

* VSH/sys_vm: Fix limit on root processes
This commit is contained in:
Elad Ashkenazi 2023-01-15 22:12:54 +02:00 committed by GitHub
parent 1852b370d7
commit e6a7597444
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 92 additions and 37 deletions

View File

@ -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<lv2_prx> 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);

View File

@ -3208,6 +3208,11 @@ extern void ppu_initialize()
idm::select<lv2_obj, lv2_prx>([&](u32, lv2_prx& _module)
{
if (_module.funcs.empty())
{
return;
}
if (_module.path.starts_with(firmware_sprx_path))
{
// Postpone testing

View File

@ -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
{

View File

@ -308,11 +308,12 @@ std::shared_ptr<void> lv2_prx::load(utils::serial& ar)
if (seg_count)
{
std::basic_string<bool> loaded_flags;
std::basic_string<bool> 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<void> 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<u8*>(&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<bool> 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<bool> 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<char> name, vm::ptr<void> opt)
@ -864,7 +874,39 @@ error_code _sys_prx_register_library(ppu_thread& ppu, vm::ptr<void> library)
return CELL_EFAULT;
}
ppu_manual_load_imports_exports(0, 0, library.addr(), 0x1c, *std::make_unique<std::basic_string<bool>>());
constexpr u32 sizeof_lib = 0x1c;
std::array<char, sizeof_lib> mem_copy{};
std::memcpy(mem_copy.data(), library.get_ptr(), sizeof_lib);
std::basic_string<bool> flags;
ppu_manual_load_imports_exports(0, 0, library.addr(), sizeof_lib, flags);
if (flags.front())
{
const bool success = idm::select<lv2_obj, lv2_prx>([&](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<bool>::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;
}

View File

@ -72,7 +72,7 @@ struct sys_prx_module_info_t
be_t<u32> all_segments_num; // 0x34
vm::bptr<char> filename; // 0x38
be_t<u32> filename_size; // 0x3c
vm::bptr<sys_prx_segment_info_t> segments; // 0x40
vm::bptr<sys_prx_segment_info_t> segments; // 0x40
be_t<u32> segments_num; // 0x44
};
@ -196,6 +196,7 @@ struct lv2_prx final : lv2_obj, ppu_module
u32 exports_end = 0;
std::basic_string<bool> m_loaded_flags;
std::basic_string<bool> m_external_loaded_flags;
void load_exports(); // (Re)load exports
void restore_exports(); // For savestates

View File

@ -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<sys_vm_global_t>().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;
}

View File

@ -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))
{

View File

@ -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<std::string_view> 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();

View File

@ -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)

View File

@ -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)") },
})
{
}