diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 68ed215102..28fbf52b59 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -699,6 +699,16 @@ static auto ppu_load_imports(std::vector& relocs, ppu_linkage_info* l return result; } +// For _sys_prx_register_module +void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size) +{ + auto& _main = g_fxo->get(); + auto& link = g_fxo->get(); + + ppu_load_exports(&link, exports_start, exports_start + exports_size); + ppu_load_imports(_main.relocs, &link, imports_start, imports_start + imports_size); +} + static void ppu_check_patch_spu_images(const ppu_segment& seg) { const std::string_view seg_view{vm::get_super_ptr(seg.addr), seg.size}; diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index f5ae0aec2b..2d8e150d5a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -608,11 +608,64 @@ error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr name, vm::ptr opt) { ppu.state += cpu_flag::wait; - sys_prx.todo("_sys_prx_register_module()"); + sys_prx.todo("_sys_prx_register_module(name=%s, opt=*0x%x)", name, opt); + + if (!opt) + { + return CELL_EINVAL; + } + + sys_prx_register_module_0x30_type_1_t info{}; + + switch (const u64 size_struct = vm::read64(opt.addr())) + { + case 0x1c: + case 0x20: + { + const auto _info = vm::static_ptr_cast(opt); + + sys_prx.todo("_sys_prx_register_module(): opt size is 0x%x", size_struct); + + // Rebuild info with corresponding members of old structures + // Weird that type is set to 0 because 0 means NO-OP in this syscall + info.size = 0x30; + info.lib_stub_size = _info->stubs_size; + info.lib_stub_ea = _info->stubs_ea; + info.error_handler = _info->error_handler; + info.type = 0; + break; + } + case 0x30: + { + std::memcpy(&info, opt.get_ptr(), sizeof(info)); + break; + } + default: return CELL_EINVAL; + } + + sys_prx.warning("opt: size=0x%x, type=0x%x, unk3=0x%x, unk4=0x%x, lib_entries_ea=%s, lib_entries_size=0x%x" + ", lib_stub_ea=%s, lib_stub_size=0x%x, error_handler=%s", info.size, info.type, info.unk3, info.unk4 + , info.lib_entries_ea, info.lib_entries_size, info.lib_stub_ea, info.lib_stub_size, info.error_handler); + + if (info.type & 0x1) + { + if (g_ps3_process_info.get_cellos_appname() == "vsh.self"sv) + { + ppu_manual_load_imports_exports(info.lib_stub_ea.addr(), info.lib_stub_size, info.lib_entries_ea.addr(), info.lib_entries_size); + } + else + { + // Only VSH is allowed to load it manually + return not_an_error(CELL_PRX_ERROR_ELF_IS_REGISTERED); + } + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index bbbbfa8c79..73a76dbac4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -118,6 +118,31 @@ struct sys_prx_get_module_list_option_t be_t unk; // 0 }; +struct sys_prx_register_module_0x20_t +{ + be_t size; // 0x0 + be_t toc; // 0x8 + be_t toc_size; // 0xC + vm::bptr stubs_ea; // 0x10 + be_t stubs_size; // 0x14 + vm::bptr error_handler; // 0x18 + char pad[4]; // 0x1C +}; + +struct sys_prx_register_module_0x30_type_1_t +{ + be_t size; // 0x0 + be_t type; // 0x8 + be_t unk3; // 0x10 + be_t unk4; // 0x14 + vm::bptr lib_entries_ea; // 0x18 + be_t lib_entries_size; // 0x1C + vm::bptr lib_stub_ea; // 0x20 + be_t lib_stub_size; // 0x24 + vm::bptr error_handler; // 0x28 + char pad[4]; // 0x2C +}; + enum : u32 { SYS_PRX_RESIDENT = 0, @@ -172,7 +197,7 @@ error_code _sys_prx_load_module(ppu_thread& ppu, vm::cptr path, u64 flags, error_code _sys_prx_start_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr pOpt); error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr pOpt); error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr pOpt); -error_code _sys_prx_register_module(ppu_thread& ppu); +error_code _sys_prx_register_module(ppu_thread& ppu, vm::cptr name, vm::ptr opt); error_code _sys_prx_query_module(ppu_thread& ppu); error_code _sys_prx_register_library(ppu_thread& ppu, vm::ptr library); error_code _sys_prx_unregister_library(ppu_thread& ppu, vm::ptr library);