mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
PRX: export functions on start()
This commit is contained in:
parent
0a35a62235
commit
b875a86e1d
@ -153,6 +153,7 @@ struct ppu_linkage_info
|
||||
|
||||
// Module map
|
||||
std::map<std::string, module_data> modules{};
|
||||
std::map<std::string, std::shared_ptr<atomic_t<bool>>, std::less<>> lib_lock;
|
||||
shared_mutex mutex;
|
||||
};
|
||||
|
||||
@ -628,8 +629,43 @@ extern u32 ppu_get_exported_func_addr(u32 fnid, const std::string& module_name)
|
||||
return g_fxo->get<ppu_linkage_info>().modules[module_name].functions[fnid].export_addr;
|
||||
}
|
||||
|
||||
extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib)
|
||||
{
|
||||
auto link = g_fxo->try_get<ppu_linkage_info>();
|
||||
|
||||
if (!link || libname.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
reader_lock lock(link->mutex);
|
||||
|
||||
if (auto it = std::as_const(link->lib_lock).find(libname); it != link->lib_lock.cend() && it->second)
|
||||
{
|
||||
return lock_lib ? !it->second->test_and_set() : it->second->test_and_reset();
|
||||
}
|
||||
|
||||
if (!lock_lib)
|
||||
{
|
||||
// If lock hasn't been installed it wasn't locked in the first place
|
||||
return false;
|
||||
}
|
||||
|
||||
lock.upgrade();
|
||||
|
||||
auto& lib_lock = link->lib_lock.emplace(std::string{libname}, nullptr).first->second;
|
||||
|
||||
if (!lib_lock)
|
||||
{
|
||||
lib_lock = std::make_shared<atomic_t<bool>>(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return !lib_lock->test_and_set();
|
||||
}
|
||||
|
||||
// Load and register exports; return special exports found (nameless module)
|
||||
static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end)
|
||||
static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false)
|
||||
{
|
||||
std::unordered_map<u32, u32> result;
|
||||
|
||||
@ -663,6 +699,12 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
|
||||
continue;
|
||||
}
|
||||
|
||||
if (for_observing_callbacks)
|
||||
{
|
||||
addr += lib.size ? lib.size : sizeof(ppu_prx_module_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string module_name(lib.name.get_ptr());
|
||||
|
||||
ppu_loader.notice("** Exported module '%s' (0x%x, 0x%x, 0x%x, 0x%x)", module_name, lib.vnids, lib.vstubs, lib.unk4, lib.unk5);
|
||||
@ -873,6 +915,12 @@ void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 ex
|
||||
auto& link = g_fxo->get<ppu_linkage_info>();
|
||||
|
||||
ppu_load_exports(&link, exports_start, exports_start + exports_size);
|
||||
|
||||
if (!imports_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ppu_load_imports(_main.relocs, &link, imports_start, imports_start + imports_size);
|
||||
}
|
||||
|
||||
@ -1419,10 +1467,13 @@ 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;
|
||||
|
||||
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);
|
||||
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
|
||||
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;
|
||||
@ -2055,6 +2106,8 @@ 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);
|
||||
prx->state = PRX_STATE_STARTED;
|
||||
prx->load_exports();
|
||||
|
||||
if (prx->funcs.empty())
|
||||
{
|
||||
|
@ -3192,6 +3192,13 @@ extern void ppu_initialize()
|
||||
if (ptr->path.starts_with(firmware_sprx_path))
|
||||
{
|
||||
compile_fw |= ppu_initialize(*ptr, true);
|
||||
|
||||
// Fixup for compatibility with old savestates
|
||||
if (Emu.DeserialManager() && ptr->name == "liblv2.sprx")
|
||||
{
|
||||
static_cast<lv2_prx*>(ptr)->state = PRX_STATE_STARTED;
|
||||
static_cast<lv2_prx*>(ptr)->load_exports();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +170,8 @@ extern const std::map<std::string_view, int> g_prx_list
|
||||
{ "libwmadec.sprx", 0 },
|
||||
};
|
||||
|
||||
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<sys_prx_load_module_option_t> /*pOpt*/, fs::file src = {}, s64 file_offset = 0)
|
||||
{
|
||||
if (flags != 0)
|
||||
@ -191,16 +193,6 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
|
||||
const std::string path = vfs::get(vpath, nullptr, &vpath0);
|
||||
const std::string name = vpath0.substr(vpath0.find_last_of('/') + 1);
|
||||
|
||||
const auto existing = idm::select<lv2_obj, lv2_prx>([&](u32, lv2_prx& prx)
|
||||
{
|
||||
return prx.path == path && prx.offset == file_offset;
|
||||
});
|
||||
|
||||
if (existing)
|
||||
{
|
||||
return CELL_PRX_ERROR_LIBRARY_FOUND;
|
||||
}
|
||||
|
||||
bool ignore = false;
|
||||
|
||||
constexpr std::string_view firmware_sprx_dir = "/dev_flash/sys/external/";
|
||||
@ -295,6 +287,8 @@ fs::file make_file_view(fs::file&& _file, u64 offset);
|
||||
|
||||
std::shared_ptr<void> lv2_prx::load(utils::serial& ar)
|
||||
{
|
||||
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(lv2_prx_overlay);
|
||||
|
||||
const std::string path = vfs::get(ar.operator std::string());
|
||||
const s64 offset = ar;
|
||||
const u32 state = ar;
|
||||
@ -320,6 +314,18 @@ std::shared_ptr<void> lv2_prx::load(utils::serial& ar)
|
||||
u128 klic = g_fxo->get<loaded_npdrm_keys>().last_key();
|
||||
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);
|
||||
|
||||
if (version >= 2 && state == PRX_STATE_STARTED)
|
||||
{
|
||||
ensure(ppu_register_library_lock(prx->module_info_name, true));
|
||||
prx->load_exports();
|
||||
}
|
||||
|
||||
if (version == 1)
|
||||
{
|
||||
prx->load_exports();
|
||||
}
|
||||
|
||||
ensure(prx);
|
||||
}
|
||||
else
|
||||
@ -498,9 +504,35 @@ error_code _sys_prx_start_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
std::lock_guard lock(prx->mutex);
|
||||
|
||||
if (prx->state != PRX_STATE_INITIALIZED)
|
||||
{
|
||||
if (prx->state == PRX_STATE_DESTROYED)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
return CELL_PRX_ERROR_ERROR;
|
||||
}
|
||||
|
||||
if (prx->exports_end > prx->exports_start && !ppu_register_library_lock(prx->module_info_name, true))
|
||||
{
|
||||
return {CELL_PRX_ERROR_LIBRARY_FOUND, +prx->module_info_name};
|
||||
}
|
||||
|
||||
prx->load_exports();
|
||||
|
||||
if (!prx->state.compare_and_swap_test(PRX_STATE_INITIALIZED, PRX_STATE_STARTING))
|
||||
{
|
||||
// The only error code here
|
||||
ensure(prx->exports_end <= prx->exports_start || ppu_register_library_lock(prx->module_info_name, false));
|
||||
|
||||
if (prx->state == PRX_STATE_DESTROYED)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
return CELL_PRX_ERROR_ERROR;
|
||||
}
|
||||
|
||||
@ -590,6 +622,7 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_
|
||||
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
||||
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
||||
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
||||
case PRX_STATE_DESTROYED: return CELL_ESRCH;
|
||||
case PRX_STATE_STARTED: break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid prx state (%d)", old);
|
||||
@ -607,6 +640,8 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_
|
||||
case 0:
|
||||
{
|
||||
// No error code on invalid state, so throw on unexpected state
|
||||
std::lock_guard lock(prx->mutex);
|
||||
ensure(prx->exports_end <= prx->exports_start || (prx->state == PRX_STATE_STOPPING && ppu_register_library_lock(prx->module_info_name, false)));
|
||||
ensure(prx->state.compare_and_swap_test(PRX_STATE_STOPPING, PRX_STATE_STOPPED));
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -628,6 +663,7 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_
|
||||
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
||||
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
||||
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
||||
case PRX_STATE_DESTROYED: return CELL_ESRCH;
|
||||
case PRX_STATE_STARTED: break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid prx state (%d)", old);
|
||||
@ -660,7 +696,16 @@ error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sy
|
||||
// Get the PRX, free the used memory and delete the object and its ID
|
||||
const auto prx = idm::withdraw<lv2_obj, lv2_prx>(id, [](lv2_prx& prx) -> CellPrxError
|
||||
{
|
||||
switch (prx.state)
|
||||
switch (prx.state.fetch_op([](u32& value)
|
||||
{
|
||||
if (value == PRX_STATE_INITIALIZED || value == PRX_STATE_STOPPED)
|
||||
{
|
||||
value = PRX_STATE_DESTROYED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}).first)
|
||||
{
|
||||
case PRX_STATE_INITIALIZED:
|
||||
case PRX_STATE_STOPPED:
|
||||
@ -683,6 +728,8 @@ error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sy
|
||||
|
||||
sys_prx.success("_sys_prx_unload_module(id=0x%x, flags=0x%x, pOpt=*0x%x): name='%s'", id, flags, pOpt, prx->name);
|
||||
|
||||
prx->mutex.lock_unlock();
|
||||
|
||||
ppu_unload_prx(*prx);
|
||||
|
||||
ppu_finalize(*prx);
|
||||
@ -694,6 +741,17 @@ error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sy
|
||||
|
||||
void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size);
|
||||
|
||||
void lv2_prx::load_exports()
|
||||
{
|
||||
if (exports_end <= exports_start)
|
||||
{
|
||||
// Nothing to load
|
||||
return;
|
||||
}
|
||||
|
||||
ppu_manual_load_imports_exports(0, 0, exports_start, exports_end - exports_start);
|
||||
}
|
||||
|
||||
error_code _sys_prx_register_module(ppu_thread& ppu, vm::cptr<char> name, vm::ptr<void> opt)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
@ -169,6 +169,7 @@ enum : u32
|
||||
PRX_STATE_STARTED,
|
||||
PRX_STATE_STOPPING, // In-between state between started and stopped (internal)
|
||||
PRX_STATE_STOPPED, // Last state, the module cannot be restarted
|
||||
PRX_STATE_DESTROYED, // Last state, the module cannot be restarted
|
||||
};
|
||||
|
||||
struct lv2_prx final : lv2_obj, ppu_module
|
||||
@ -176,6 +177,7 @@ struct lv2_prx final : lv2_obj, ppu_module
|
||||
static const u32 id_base = 0x23000000;
|
||||
|
||||
atomic_t<u32> state = PRX_STATE_INITIALIZED;
|
||||
shared_mutex mutex;
|
||||
|
||||
std::unordered_map<u32, u32> specials;
|
||||
std::unordered_map<u32, void*> imports;
|
||||
@ -190,6 +192,11 @@ struct lv2_prx final : lv2_obj, ppu_module
|
||||
u8 module_info_version[2];
|
||||
be_t<u16> module_info_attributes;
|
||||
|
||||
u32 exports_start = umax;
|
||||
u32 exports_end = 0;
|
||||
|
||||
void load_exports(); // (Re)load exports
|
||||
|
||||
lv2_prx() noexcept = default;
|
||||
lv2_prx(utils::serial&) {}
|
||||
static std::shared_ptr<void> load(utils::serial&);
|
||||
|
@ -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/*PRX dynamic exports*/)
|
||||
SERIALIZATION_VER(lv2_memory, 8, 1)
|
||||
SERIALIZATION_VER(lv2_config, 9, 1)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user