diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 8df3099829..e915ba9128 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -1435,5 +1435,5 @@ DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []() REG_FUNC(cellGcmSys, cellGcmGpadCaptureSnapshot); // Special - REG_FNID(cellGcmSys, 0x00000000, cellGcmCallback); + REG_FUNC(cellGcmSys, cellGcmCallback).flags = MFF_HIDDEN; }); diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp index 82750c43cb..6d9790b89e 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -2149,6 +2149,8 @@ void PPUDisAsm::FCFID(ppu_opcode_t op) DisAsm_F2_RC("fcfid", op.frd, op.frb, op.rc); } +extern std::vector g_ppu_function_names; + void PPUDisAsm::UNK(ppu_opcode_t op) { if (op.opcode == dump_pc && ppu_function_manager::addr) @@ -2158,7 +2160,7 @@ void PPUDisAsm::UNK(ppu_opcode_t op) if (index < ppu_function_manager::get().size()) { - Write(fmt::format("Function : (index %u)", index)); + Write(fmt::format("Function : %s (index %u)", index < g_ppu_function_names.size() ? g_ppu_function_names[index].c_str() : "?", index)); return; } } diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index bf6a20e21f..7fa74e6c97 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -125,6 +125,8 @@ cfg::bool_entry g_cfg_load_libreq(cfg::root.core, "Load required libraries", tru cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries"); +extern cfg::map_entry g_cfg_ppu_decoder; + extern std::string ppu_get_function_name(const std::string& module, u32 fnid); extern std::string ppu_get_variable_name(const std::string& module, u32 vnid); extern void ppu_register_range(u32 addr, u32 size); @@ -136,6 +138,9 @@ extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32); extern u32 g_ps3_sdk_version; +// HLE function name cache +std::vector g_ppu_function_names; + extern u32 ppu_generate_id(const char* name) { // Symbol name suffix @@ -195,13 +200,16 @@ struct ppu_linkage_info { struct info { + bool hle = false; u32 export_addr = 0; std::set imports; }; // FNID -> (export; [imports...]) - std::map functions; - std::map variables; + std::unordered_map> functions; + std::unordered_map> variables; + + bool imported = false; }; // Module map @@ -209,7 +217,7 @@ struct ppu_linkage_info }; // Initialize static modules. -static void ppu_initialize_modules() +static void ppu_initialize_modules(const std::shared_ptr& link) { const std::initializer_list registered { @@ -312,23 +320,6 @@ static void ppu_initialize_modules() &ppu_module_manager::sys_lv2dbg, }; - // "Use" all the modules for correct linkage - for (auto& module : registered) - { - LOG_TRACE(LOADER, "Registered static module: %s", module->name); - - for (auto& function : module->functions) - { - LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); - } - - for (auto& variable : module->variables) - { - LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); - variable.second.var->set(0); - } - } - // Initialize double-purpose fake OPD array for HLE functions const auto& hle_funcs = ppu_function_manager::get(); @@ -352,6 +343,86 @@ static void ppu_initialize_modules() // Set memory protection to read-only vm::page_protect(ppu_function_manager::addr, ::align(::size32(hle_funcs) * 8, 0x1000), 0, 0, vm::page_writable); + + // Initialize function names + const bool is_first = g_ppu_function_names.empty(); + + if (is_first) + { + g_ppu_function_names.resize(hle_funcs.size()); + g_ppu_function_names[0] = "INVALID"; + g_ppu_function_names[1] = "HLE RETURN"; + } + + // For HLE variable allocation + u32 alloc_addr = 0; + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + + auto& linkage = link->modules[module->name]; + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + + if (is_first) + { + g_ppu_function_names[function.second.index] = fmt::format("%s.%s", module->name, function.second.name); + } + + if ((function.second.flags & MFF_HIDDEN) == 0) + { + auto& flink = linkage.functions[function.first]; + + flink.hle = true; + flink.export_addr = ppu_function_manager::addr + 8 * function.second.index; + } + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + + // Allocate HLE variable + if (variable.second.size >= 4096 || variable.second.align >= 4096) + { + variable.second.var->set(vm::alloc(variable.second.size, vm::main, std::max(variable.second.align, 4096))); + } + else + { + const u32 next = ::align(alloc_addr, variable.second.align); + const u32 end = next + variable.second.size; + + if (!next || (end >> 12 != alloc_addr >> 12)) + { + alloc_addr = vm::alloc(4096, vm::main); + } + else + { + alloc_addr = next; + } + + variable.second.var->set(alloc_addr); + alloc_addr += variable.second.size; + } + + LOG_TRACE(LOADER, "Allocated HLE variable %s.%s at 0x%x", module->name, variable.second.name, variable.second.var->addr()); + + // Initialize HLE variable + if (variable.second.init) + { + variable.second.init(); + } + + auto& vlink = linkage.variables[variable.first]; + + vlink.hle = true; + vlink.export_addr = variable.second.var->addr(); + } + } } // Link variable @@ -452,6 +523,9 @@ static auto ppu_load_exports(const std::shared_ptr& link, u32 // Static module const auto _sm = ppu_module_manager::get_module(module_name); + // Module linkage + auto& mlink = link->modules[module_name]; + const auto fnids = +lib.nids; const auto faddrs = +lib.addrs; @@ -463,13 +537,13 @@ static auto ppu_load_exports(const std::shared_ptr& link, u32 LOG_NOTICE(LOADER, "**** %s export: [%s] at 0x%x", module_name, ppu_get_function_name(module_name, fnid), faddr); // Function linkage info - auto& flink = link->modules[module_name].functions[fnid]; + auto& flink = mlink.functions[fnid]; - if (flink.export_addr) + if (flink.export_addr && !flink.hle) { - LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + LOG_ERROR(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); } - else + //else { // Static function const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr; @@ -499,6 +573,7 @@ static auto ppu_load_exports(const std::shared_ptr& link, u32 { // Set exported function flink.export_addr = faddr; + flink.hle = false; // Fix imports for (const u32 addr : flink.imports) @@ -521,16 +596,17 @@ static auto ppu_load_exports(const std::shared_ptr& link, u32 LOG_NOTICE(LOADER, "**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr); // Variable linkage info - auto& vlink = link->modules[module_name].variables[vnid]; + auto& vlink = mlink.variables[vnid]; - if (vlink.export_addr) + if (vlink.export_addr && !vlink.hle) { - LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + LOG_ERROR(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); } - else + //else { // Set exported variable vlink.export_addr = vaddr; + vlink.hle = false; // Fix imports for (const auto vref : vlink.imports) @@ -565,6 +641,9 @@ static void ppu_load_imports(const std::shared_ptr& link, u32 // Static module const auto _sm = ppu_module_manager::get_module(module_name); + // Module linkage + auto& mlink = link->modules[module_name]; + const auto fnids = +lib.nids; const auto faddrs = +lib.addrs; @@ -580,12 +659,17 @@ static void ppu_load_imports(const std::shared_ptr& link, u32 // Add new import flink.imports.emplace(faddr); + mlink.imported = true; // Link if available if (flink.export_addr) { vm::write32(faddr, flink.export_addr); } + else + { + vm::write32(faddr, ppu_function_manager::addr); + } //LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr); } @@ -604,6 +688,7 @@ static void ppu_load_imports(const std::shared_ptr& link, u32 // Add new import vlink.imports.emplace(vref); + mlink.imported = true; // Link if available if (vlink.export_addr) @@ -620,6 +705,12 @@ static void ppu_load_imports(const std::shared_ptr& link, u32 std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::string& name) { + if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm && name == "libfiber.sprx") + { + LOG_FATAL(PPU, "libfiber.sprx is not compatible with PPU LLVM Recompiler. Use PPU Interpreter."); + Emu.Pause(); + } + std::vector> segments; std::vector> sections; @@ -889,7 +980,7 @@ void ppu_load_exec(const ppu_exec_object& elf) } // Initialize HLE modules - ppu_initialize_modules(); + ppu_initialize_modules(link); // Load other programs for (auto& prog : elf.progs) @@ -1120,8 +1211,14 @@ void ppu_load_exec(const ppu_exec_object& elf) } } + // TODO: recursively scan all SPRX files in /app_home/ for imports for (const auto& pair : link->modules) { + if (!pair.second.imported) + { + continue; + } + for (auto range = sprx_map.equal_range(pair.first); range.first != range.second; ++range.first) { load_libs.emplace(range.first->second); @@ -1169,106 +1266,6 @@ void ppu_load_exec(const ppu_exec_object& elf) } } - // Check unlinked functions and variables - for (auto& module : link->modules) - { - const auto _sm = ppu_module_manager::get_module(module.first); - - if (!_sm) - { - LOG_ERROR(LOADER, "Unknown module '%s'", module.first); - } - else - { - // Allocate HLE variables (TODO) - for (auto& var : _sm->variables) - { - var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); - LOG_WARNING(LOADER, "Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module.first, var.second.var->addr()); - } - - // Initialize HLE variables (TODO) - for (auto& var : _sm->variables) - { - var.second.init(); - } - } - - for (auto& entry : module.second.functions) - { - const u32 fnid = entry.first; - const u32 faddr = entry.second.export_addr; - - if (faddr == 0) - { - const std::string fname = ppu_get_function_name(module.first, fnid); - - // Link HLE implementation if available - if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr) - { - LOG_NOTICE(LOADER, "Linking HLE function '%s' in module '%s' (index %u)", fname, module.first, _sf->index); - - for (const u32 import : entry.second.imports) - { - LOG_TRACE(LOADER, "** Linked at *0x%x (0x%x)", import, vm::read32(import)); - vm::write32(import, ppu_function_manager::addr + 8 * _sf->index); - } - } - else - { - LOG_ERROR(LOADER, "Unknown function '%s' in module '%s'", fname, module.first); - - for (const u32 import : entry.second.imports) - { - LOG_WARNING(LOADER, "** Not linked at *0x%x (0x%x)", import, vm::read32(import)); - vm::write32(import, ppu_function_manager::addr); - } - } - } - } - - for (auto& entry : module.second.variables) - { - const u32 vnid = entry.first; - const u32 vaddr = entry.second.export_addr; - - if (vaddr == 0) - { - const std::string vname = ppu_get_variable_name(module.first, vnid); - - // Link HLE variable if available - if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) - { - LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", vname, module.first, _sv->var->addr()); - - for (const u32 ref : entry.second.imports) - { - ppu_patch_variable_refs(ref, _sv->var->addr()); - LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref); - } - } - else - { - LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", vname, module.first); - - for (const u32 ref : entry.second.imports) - { - LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref); - } - } - } - else - { - // Retro-link LLE variable (TODO: HLE must not be allocated/initialized in this case) - if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) - { - _sv->var->set(vaddr); - LOG_NOTICE(LOADER, "Linked LLE variable '%s' in module '%s' -> 0x%x", ppu_get_variable_name(module.first, vnid), module.first, vaddr); - } - } - } - } - { // Analyse executable std::vector main_funcs = ppu_analyse(segments, sections, 0, elf.header.e_entry); @@ -1307,7 +1304,9 @@ void ppu_load_exec(const ppu_exec_object& elf) ppu->cmd_push({ppu_cmd::initialize, 0}); // TODO: adjust for liblv2 loading option - if (!g_cfg_load_liblv2) + u32 entry = static_cast(elf.header.e_entry); + + if (!g_cfg_load_liblv2 || g_cfg_load_libreq) { // Set TLS args, call sys_initialize_tls ppu->cmd_list @@ -1316,6 +1315,13 @@ void ppu_load_exec(const ppu_exec_object& elf) { ppu_cmd::hle_call, FIND_FUNC(sys_initialize_tls) }, }); } + else + { + // Run liblv2.sprx entry point (TODO) + entry = loaded_modules[0]->start.addr(); + + loaded_modules.clear(); + } // Run start functions for (const auto& prx : loaded_modules) @@ -1337,9 +1343,9 @@ void ppu_load_exec(const ppu_exec_object& elf) ppu->cmd_list ({ { ppu_cmd::set_args, 8 }, u64{args.size()}, u64{argv.addr()}, u64{envp.addr()}, u64{0}, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize}, - { ppu_cmd::set_gpr, 11 }, u64{0xabadcafe}, + { ppu_cmd::set_gpr, 11 }, u64{elf.header.e_entry}, { ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize}, - { ppu_cmd::lle_call, static_cast(elf.header.e_entry) }, + { ppu_cmd::lle_call, entry }, }); // Set actual memory protection (experimental) diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index ddbad4a821..adb5eb1da4 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -14,6 +14,7 @@ enum ppu_static_function_flags : u32 { MFF_FORCED_HLE = (1 << 0), // Always call HLE function MFF_PERFECT = (1 << 1), // Indicates complete implementation and LLE interchangeability + MFF_HIDDEN = (1 << 2), // Invisible function for internal use (TODO) }; // HLE function information @@ -43,8 +44,8 @@ public: task_stack on_load; task_stack on_unload; - std::map functions; - std::map variables; + std::unordered_map> functions; + std::unordered_map> variables; public: ppu_static_module(const char* name); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 2b6712eb2f..727618bb61 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -82,13 +82,6 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -enum class ppu_decoder_type -{ - precise, - fast, - llvm, -}; - cfg::map_entry g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder", 1, { { "Interpreter (precise)", ppu_decoder_type::precise }, @@ -868,17 +861,6 @@ extern void ppu_initialize() return; } - if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm) - { - idm::select([](u32, lv2_prx& prx) - { - if (prx.name == "libfiber.sprx") - { - fmt::raw_error("libfiber.sprx is not compatible with PPU LLVM Recompiler."); - } - }); - } - std::size_t fpos = 0; while (fpos < _funcs->size()) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 4c9c46d11a..2ea6decde8 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -18,6 +18,13 @@ enum class ppu_cmd : u32 sleep, }; +enum class ppu_decoder_type +{ + precise, + fast, + llvm, +}; + class ppu_thread : public cpu_thread { public: diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 77a0f4af80..cd066b7cf1 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -363,7 +363,15 @@ void Emulator::Load() } debug::autopause::reload(); - if (g_cfg_autostart) Run(); + + if (g_cfg_autostart && IsReady()) + { + Run(); + } + else if (IsPaused()) + { + m_status = Ready; + } } catch (const std::exception& e) { @@ -412,7 +420,7 @@ bool Emulator::Pause() // Try to pause if (!m_status.compare_and_swap_test(Running, Paused)) { - return false; + return m_status.compare_and_swap_test(Ready, Paused); } rpcs3::on_pause()(); diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index 625925dabe..7eaaaab886 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -193,7 +193,7 @@ void KernelExplorer::Update() case SYS_PRX_OBJECT: { auto& prx = static_cast(obj); - m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x", id)); + m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x '%s'", id, prx.name)); break; } case SYS_SPUPORT_OBJECT: