diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index 79fc5efdbe..220ca2c21d 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -9,22 +9,7 @@ u32 add_psv_func(psv_func data) { for (auto& f : g_psv_func_list) { - if (f.nid == data.nid) - { - const u32 index = (u32)(&f - g_psv_func_list.data()); - - if (index < SFI_MAX) - { - continue; - } - - if (data.func) - { - f.func = data.func; - } - - return index; - } + assert(f.nid != data.nid || (&f - g_psv_func_list.data()) < SFI_MAX); } g_psv_func_list.push_back(data); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index 2780e33a7b..811f33675a 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -38,7 +38,7 @@ typedef void(*psv_func_caller)(ARMv7Context&); // Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks namespace psv_func_detail { - enum bind_arg_type + enum arg_class { ARG_GENERAL, ARG_FLOAT, @@ -48,7 +48,7 @@ namespace psv_func_detail static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h - template + template struct bind_arg; template @@ -191,7 +191,7 @@ namespace psv_func_detail } }; - template + template struct bind_result { static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)"); @@ -265,7 +265,7 @@ namespace psv_func_detail static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; static const bool is_vector = std::is_same::value; - static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template @@ -281,7 +281,7 @@ namespace psv_func_detail static const int g_next = g_pos + g_align - 1; static const int f_value = !is_float ? f_count : f_count + 1; static const int v_value = !is_vector ? v_count : v_count + 1; - static const bind_arg_type value = is_float + static const arg_class value = is_float ? ((f_value > 9000) ? ARG_STACK : ARG_FLOAT) : (is_vector ? ((v_value > 9000) ? ARG_STACK : ARG_VECTOR) : ((g_pos > 4) ? ARG_STACK : ARG_GENERAL)); }; @@ -322,7 +322,7 @@ namespace psv_func_detail __forceinline std::tuple get_func_args(ARMv7Context& context) { typedef arg_type type; - const bind_arg_type t = type::value; + const arg_class t = type::value; const int g0 = type::g_pos; const int g1 = type::g_next; const int f = type::f_value; @@ -342,7 +342,7 @@ namespace psv_func_detail __forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args) { typedef arg_type type; - const bind_arg_type t = type::value; + const arg_class t = type::value; const int g0 = type::g_pos; const int g1 = type::g_next; const int f = type::f_value; @@ -435,9 +435,23 @@ namespace psv_func_detail struct psv_func { u32 nid; // Unique function ID (should be generated individually for each elf loaded) + u32 flags; const char* name; // Function name for information psv_func_caller func; // Function caller psv_log_base* module; // Module for information + + psv_func() + { + } + + psv_func(u32 nid, u32 flags, psv_log_base* module, const char* name, psv_func_caller func) + : nid(nid) + , flags(flags) + , name(name) + , func(func) + , module(module) + { + } }; enum psv_special_function_index : u16 @@ -450,23 +464,12 @@ enum psv_special_function_index : u16 // Do not call directly u32 add_psv_func(psv_func data); // Do not call directly -__forceinline static u32 add_psv_func(u32 nid, psv_log_base* module, const char* name, psv_func_caller func) -{ - psv_func f; - f.nid = nid; - f.name = name; - f.func = func; - f.module = module; - - return add_psv_func(f); -} -// Do not call directly template __forceinline void call_psv_func(ARMv7Context& context, RT(*func)(T...)) { psv_func_detail::func_binder::do_call(context, func); } -#define reg_psv_func(nid, module, name, func) add_psv_func(nid, module, name, [](ARMv7Context& context){ call_psv_func(context, func); }) +#define reg_psv_func(nid, module, name, func) add_psv_func(psv_func(nid, 0, module, name, [](ARMv7Context& context){ call_psv_func(context, func); })) // Find registered HLE function by NID psv_func* get_psv_func_by_nid(u32 nid, u32* out_index = nullptr); diff --git a/rpcs3/Emu/SysCalls/ModuleManager.cpp b/rpcs3/Emu/SysCalls/ModuleManager.cpp index 1639eceeed..64ae948afd 100644 --- a/rpcs3/Emu/SysCalls/ModuleManager.cpp +++ b/rpcs3/Emu/SysCalls/ModuleManager.cpp @@ -163,7 +163,6 @@ static const g_module_list[] = { 0xf053, "cellAdecAt3multi", nullptr }, { 0xf054, "cellLibatrac3multi", nullptr }, - { -1, "cellSync", &cellSync }, { -1, "cellSysmodule", &cellSysmodule }, { -1, "libmixer", &libmixer }, { -1, "sysPrxForUser", &sysPrxForUser }, diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index 5939cf47b4..e5b38d103b 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -17,22 +17,7 @@ u32 add_ppu_func(ModuleFunc func) { for (auto& f : g_ppu_func_list) { - if (f.id == func.id) - { - // partial update - - if (func.func) - { - f.func = func.func; - } - - if (func.lle_func) - { - f.lle_func = func.lle_func; - } - - return (u32)(&f - g_ppu_func_list.data()); - } + assert(f.id != func.id); } g_ppu_func_list.push_back(func); @@ -48,7 +33,7 @@ u32 add_ppu_func_sub(StaticFunc func) u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func) { StaticFunc sf; - sf.index = add_ppu_func(ModuleFunc(get_function_id(name), module, func)); + sf.index = add_ppu_func(ModuleFunc(get_function_id(name), MFF_DONT_SAVE_RTOC, module, func)); sf.name = name; sf.group = *(u64*)group; sf.found = 0; @@ -98,14 +83,18 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) { if (auto func = get_ppu_func_by_index(index)) { - // save RTOC - vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); + if ((!func->lle_func || CPU.PC != vm::read32(func->lle_func.addr())) && !(func->flags & MFF_DONT_SAVE_RTOC)) + { + // save RTOC if necessary + vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); + } auto old_last_syscall = CPU.m_last_syscall; CPU.m_last_syscall = func->id; - if (func->lle_func) + if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) { + // call LLE function if possible func->lle_func(CPU); } else if (func->func) diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 6b724a1619..f0bbca1e8a 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -6,15 +6,27 @@ class Module; +enum : u32 +{ + MFF_DONT_SAVE_RTOC = (1 << 0), // don't save RTOC before calling + MFF_FORCED_HLE = (1 << 1), // always call HLE function +}; + struct ModuleFunc { u32 id; + u32 flags; Module* module; ppu_func_caller func; vm::ptr lle_func; - ModuleFunc(u32 id, Module* module, ppu_func_caller func, vm::ptr lle_func = vm::ptr::make(0)) + ModuleFunc() + { + } + + ModuleFunc(u32 id, u32 flags, Module* module, ppu_func_caller func, vm::ptr lle_func = vm::ptr::make(0)) : id(id) + , flags(flags) , module(module) , func(func) , lle_func(lle_func) @@ -121,9 +133,10 @@ u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Mod void hook_ppu_funcs(u32* base, u32 size); -#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), &module, bind_func(name))) +#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, bind_func(name))) +#define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, bind_func(name))) -#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, &module, bind_func(_nid_##nid))) +#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, 0, &module, bind_func(_nid_##nid))) #define REG_SUB(module, group, name, ...) \ static const u64 name ## _table[] = {__VA_ARGS__ , 0}; \ diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 6e3f4af9dc..6874cd110b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -1081,7 +1081,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 s32 _cellSyncLFQueueGetPushPointer(vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { - cellSync.Todo("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)", + cellSync.Warning("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)", queue.addr(), pointer.addr(), isBlocking, useEventQueue); s32 pointer_value; @@ -1243,7 +1243,7 @@ s32 syncLFQueueCompletePushPointer(vm::ptr queue, s32 pointer, s32 _cellSyncLFQueueCompletePushPointer(vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { - cellSync.Todo("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)", + cellSync.Warning("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)", queue.addr(), pointer, fpSendSignal.addr()); return syncLFQueueCompletePushPointer(queue, pointer, fpSendSignal); @@ -1432,7 +1432,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i s32 _cellSyncLFQueueGetPopPointer(vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) { - cellSync.Todo("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", + cellSync.Warning("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue.addr(), pointer.addr(), isBlocking, arg4, useEventQueue); s32 pointer_value; @@ -1594,7 +1594,7 @@ s32 syncLFQueueCompletePopPointer(vm::ptr queue, s32 pointer, c s32 _cellSyncLFQueueCompletePopPointer(vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer) - cellSync.Todo("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)", + cellSync.Warning("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)", queue.addr(), pointer, fpSendSignal.addr(), noQueueFull); return syncLFQueueCompletePopPointer(queue, pointer, fpSendSignal, noQueueFull); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp index 6dce42e229..86f4b2032c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp @@ -504,7 +504,7 @@ s32 sys_net_free_thread_context() } // define additional macro for specific namespace -#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), &sys_net, bind_func(sys_net_func::name))) +#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &sys_net, bind_func(sys_net_func::name))) Module sys_net("sys_net", []() { diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index 84605cab03..562a174017 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -5,7 +5,7 @@ typedef void(*ppu_func_caller)(PPUThread&); namespace ppu_func_detail { - enum bind_arg_type + enum arg_class : u8 { ARG_GENERAL, ARG_FLOAT, @@ -13,50 +13,50 @@ namespace ppu_func_detail ARG_STACK, }; - template + template struct bind_arg; - template + template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return cast_from_ppu_gpr(CPU.GPR[g_count + 2]); } }; - template + template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return static_cast(CPU.FPR[f_count]); } }; - template + template struct bind_arg { static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return CPU.VPR[v_count + 1]; } }; - template + template struct bind_arg { static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { // TODO: check stack argument displacement const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); @@ -64,13 +64,13 @@ namespace ppu_func_detail } }; - template + template struct bind_result { static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.GPR[3] = cast_to_ppu_gpr(result); } @@ -81,7 +81,7 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.FPR[1] = static_cast(result); } @@ -92,12 +92,29 @@ namespace ppu_func_detail { static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.VPR[2] = result; } }; + struct arg_type_pack + { + arg_class type; + u8 g_count; + u8 f_count; + u8 v_count; + }; + + template + struct bind_arg_packed + { + static __forceinline T get_arg(PPUThread& CPU) + { + return bind_arg> 8, type_pack >> 16, type_pack >> 24>::get_arg(CPU); + } + }; + template struct call_impl { @@ -123,14 +140,14 @@ namespace ppu_func_detail return ppu_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } - template + template __forceinline std::tuple<> iterate(PPUThread& CPU) { // terminator return std::tuple<>(); } - template + template __forceinline std::tuple iterate(PPUThread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); @@ -138,14 +155,14 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float + const arg_class t = is_float ? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT) : (is_vector ? ((v_count >= 12) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 8) ? ARG_STACK : ARG_GENERAL)); - const int g = g_count + (is_float || is_vector ? 0 : 1); - const int f = f_count + (is_float ? 1 : 0); - const int v = v_count + (is_vector ? 1 : 0); + const u32 g = g_count + (is_float || is_vector ? 0 : 1); + const u32 f = f_count + (is_float ? 1 : 0); + const u32 v = v_count + (is_vector ? 1 : 0); - return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); + return std::tuple_cat(std::tuple(bind_arg::get_arg(CPU)), iterate(CPU)); } template @@ -155,7 +172,7 @@ namespace ppu_func_detail static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; static const bool is_vector = std::is_same::value; - static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template @@ -166,9 +183,9 @@ namespace ppu_func_detail { typedef void(*func_t)(PPUThread&, T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - call(_func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU))); + call(func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU))); } }; @@ -177,9 +194,9 @@ namespace ppu_func_detail { typedef void(*func_t)(T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - call(_func, iterate<0, 0, 0, T...>(CPU)); + call(func, iterate<0, 0, 0, T...>(CPU)); } }; @@ -188,9 +205,9 @@ namespace ppu_func_detail { typedef RT(*func_t)(PPUThread&, T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - bind_result::value>::func(CPU, call(_func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); + bind_result::value>::put_result(CPU, call(func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); } }; @@ -199,9 +216,9 @@ namespace ppu_func_detail { typedef RT(*func_t)(T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - bind_result::value>::func(CPU, call(_func, iterate<0, 0, 0, T...>(CPU))); + bind_result::value>::put_result(CPU, call(func, iterate<0, 0, 0, T...>(CPU))); } }; } diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 42de280949..9ea6b2b090 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -245,13 +245,8 @@ namespace loader { LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); - psv_func unimplemented; - unimplemented.nid = nid; - unimplemented.module = nullptr; - unimplemented.name = "UNKNOWN"; // TODO: set correct name if possible - unimplemented.func = nullptr; - - index = add_psv_func(unimplemented); + // TODO: set correct name if possible + index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr)); } vm::psv::write32(addr + 0, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index d1f646f72e..593590a666 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -398,7 +398,36 @@ namespace loader for (auto& f : m.second.exports) { - add_ppu_func(ModuleFunc(f.first, module, nullptr, vm::ptr::make(f.second))); + const u32 nid = f.first; + const u32 addr = f.second; + + u32 index; + + auto func = get_ppu_func_by_nid(nid, &index); + + if (!func) + { + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, vm::ptr::make(addr))); + } + else + { + func->lle_func.set(addr); + + if (func->flags & MFF_FORCED_HLE) + { + u32 i_addr = 0; + + if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 8)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' (opd=0x%x, 0x%x)", SysCalls::GetHLEFuncName(nid), addr, i_addr); + } + else + { + vm::write32(i_addr + 0, HACK(index)); + vm::write32(i_addr + 4, BLR()); + } + } + } } for (auto& f : m.second.imports) @@ -414,7 +443,7 @@ namespace loader { LOG_ERROR(LOADER, "Unimplemented function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); - index = add_ppu_func(ModuleFunc(nid, module, nullptr)); + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr)); } else { @@ -635,7 +664,7 @@ namespace loader { LOG_ERROR(LOADER, "Unimplemented function '%s' in '%s' module (0x%x)", SysCalls::GetHLEFuncName(nid), module_name, addr); - index = add_ppu_func(ModuleFunc(nid, module, nullptr)); + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr)); } else {