diff --git a/rpcs3/Emu/ARMv7/ARMv7Callback.h b/rpcs3/Emu/ARMv7/ARMv7Callback.h new file mode 100644 index 0000000000..4f9c72d1e0 --- /dev/null +++ b/rpcs3/Emu/ARMv7/ARMv7Callback.h @@ -0,0 +1,18 @@ +#pragma once +#include "Emu/Memory/Memory.h" +#include "Emu/ARMv7/PSVFuncList.h" + +namespace vm +{ + template + __forceinline RT _ptr_base::operator()(ARMv7Context& context, T... args) const + { + return psv_func_detail::func_caller::call(context, vm::cast(this->addr()), args...); + } +} + +template +__forceinline RT cb_call(ARMv7Context& context, u32 addr, T... args) +{ + return psv_func_detail::func_caller::call(context, addr, args...); +} \ No newline at end of file diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index 491c00f9d7..c474dc6e6d 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -29,7 +29,9 @@ struct ARMv7Context void write_pc(u32 value); u32 read_pc(); + void put_stack_arg(u32 shift, u32 value); u32 get_stack_arg(u32 pos); + void fast_call(u32 addr); union { diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index c9e04f786b..abd6b2791f 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -20,11 +20,21 @@ u32 ARMv7Context::read_pc() return thread.PC; } +void ARMv7Context::put_stack_arg(u32 shift, u32 value) +{ + vm::psv::write32(SP + shift, value); +} + u32 ARMv7Context::get_stack_arg(u32 pos) { return vm::psv::read32(SP + sizeof(u32) * (pos - 5)); } +void ARMv7Context::fast_call(u32 addr) +{ + return thread.FastCall(addr); +} + ARMv7Thread::ARMv7Thread() : CPUThread(CPU_THREAD_ARMv7) , context(*this) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index ff7eb1df4f..73a6f864e3 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -327,6 +327,10 @@ s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr pExitStatus, vm::ps psv_log_base sceLibKernel("sceLibKernel", []() { + sceLibKernel.on_load = nullptr; + sceLibKernel.on_unload = nullptr; + sceLibKernel.on_stop = nullptr; + //REG_FUNC(0x23EAA62, sceKernelPuts); //REG_FUNC(0xB0335388, sceClibToupper); //REG_FUNC(0x4C5471BC, sceClibTolower); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 0a63907a63..8bca615fcf 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -3,29 +3,51 @@ #include "Emu/System.h" #include "Emu/Memory/Memory.h" #include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Callback.h" extern psv_log_base sceLibc; +vm::psv::ptr g_dso; + +typedef void(*atexit_func_t)(vm::psv::ptr); + +std::vector> g_atexit; + namespace sce_libc_func { - void __cxa_atexit() + void __cxa_atexit(vm::psv::ptr func, vm::psv::ptr arg, vm::psv::ptr dso) { - sceLibc.Todo(__FUNCTION__); - Emu.Pause(); + sceLibc.Error("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso); + + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) + { + func(context, arg); + }); } - void __aeabi_atexit() + void __aeabi_atexit(vm::psv::ptr arg, vm::psv::ptr func, vm::psv::ptr dso) { - sceLibc.Todo(__FUNCTION__); - Emu.Pause(); + sceLibc.Error("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso); + + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) + { + func(context, arg); + }); } - void exit() + void exit(ARMv7Context& context) { sceLibc.Error("exit()"); - Emu.Pause(); + + for (auto func : g_atexit) + { + func(context); + } + + g_atexit.clear(); sceLibc.Success("Process finished"); + CallAfter([]() { Emu.Stop(); @@ -95,9 +117,11 @@ namespace sce_libc_func LOG_NOTICE(TTY, result); } - void __cxa_set_dso_handle_main() + void __cxa_set_dso_handle_main(vm::psv::ptr dso) { - sceLibc.Error("__cxa_set_dso_handle_main()"); + sceLibc.Error("__cxa_set_dso_handle_main(dso=0x%x)", dso); + + g_dso = dso; } void memcpy(vm::psv::ptr dst, vm::psv::ptr src, u32 size) @@ -127,6 +151,13 @@ namespace sce_libc_func psv_log_base sceLibc("SceLibc", []() { + g_dso.set(0); + g_atexit.clear(); + + sceLibc.on_load = nullptr; + sceLibc.on_unload = nullptr; + sceLibc.on_stop = nullptr; + REG_FUNC(0xE4531F85, _Assert); //REG_FUNC(0xE71C5CDE, _Stoul); //REG_FUNC(0x7A5CA6A3, _Stoulx); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp index ae85794c24..db7745f9f3 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp @@ -14,6 +14,10 @@ namespace sce_libm_func psv_log_base sceLibm("SceLibm", []() { + sceLibm.on_load = nullptr; + sceLibm.on_unload = nullptr; + sceLibm.on_stop = nullptr; + //REG_FUNC(0xC73FE76D, _Exp); //REG_FUNC(0xFF4EAE04, _FExp); //REG_FUNC(0xB363D7D4, _LExp); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp index 7846ec1c0d..ef215f0971 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp @@ -30,6 +30,10 @@ namespace sce_libstdcxx_func psv_log_base sceLibstdcxx("SceLibstdcxx", []() { + sceLibstdcxx.on_load = nullptr; + sceLibstdcxx.on_unload = nullptr; + sceLibstdcxx.on_stop = nullptr; + //REG_FUNC(0x52B0C625, std::bad_typeid::what() const); //REG_FUNC(0x64D7D074, std::bad_typeid::_Doraise() const); //REG_FUNC(0x15FB88E2, std::logic_error::what() const); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index 784ff534fd..bd17628f20 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -3,6 +3,7 @@ #include "PSVFuncList.h" std::vector g_psv_func_list; +std::vector g_psv_modules; void add_psv_func(psv_func& data) { @@ -48,33 +49,53 @@ extern psv_log_base sceLibm; extern psv_log_base sceLibstdcxx; extern psv_log_base sceLibKernel; -void list_known_psv_modules() +void initialize_psv_modules() { - if (!g_psv_func_list.size()) + assert(!g_psv_func_list.size() && !g_psv_modules.size()); + + // fill module list + g_psv_modules.push_back(&sceLibc); + g_psv_modules.push_back(&sceLibm); + g_psv_modules.push_back(&sceLibstdcxx); + g_psv_modules.push_back(&sceLibKernel); + + // setup special functions (without NIDs) + psv_func unimplemented; + unimplemented.nid = 0; + unimplemented.name = "Special function (unimplemented stub)"; + unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) { - // setup special functions (without NIDs) - psv_func unimplemented; - unimplemented.nid = 0; - unimplemented.name = "Special function (unimplemented stub)"; - unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) - { - context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4); - throw "Unimplemented function executed"; - })); - g_psv_func_list.push_back(unimplemented); + context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4); + throw "Unimplemented function executed"; + })); + g_psv_func_list.push_back(unimplemented); - psv_func hle_return; - hle_return.nid = 1; - hle_return.name = "Special function (return from HLE)"; - hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) - { - context.thread.FastStop(); - })); - g_psv_func_list.push_back(hle_return); + psv_func hle_return; + hle_return.nid = 1; + hle_return.name = "Special function (return from HLE)"; + hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) + { + context.thread.FastStop(); + })); + g_psv_func_list.push_back(hle_return); - sceLibc.Init(); - sceLibm.Init(); - sceLibstdcxx.Init(); - sceLibKernel.Init(); + // load functions + for (auto module : g_psv_modules) + { + module->Init(); } } + +void finalize_psv_modules() +{ + for (auto module : g_psv_modules) + { + if (module->on_stop) + { + module->on_stop(); + } + } + + g_psv_func_list.clear(); + g_psv_modules.clear(); +} diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index 2562670c08..195460de5f 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -7,6 +7,11 @@ class psv_log_base : public LogBase std::string m_name; void(*m_init_func)(); +public: + std::function on_load; + std::function on_unload; + std::function on_stop; + public: psv_log_base(const std::string& name, void(*init_func)()) : m_name(name) @@ -422,6 +427,8 @@ namespace psv_func_detail ARG_STACK, }; + static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h + template struct bind_arg; @@ -430,10 +437,15 @@ namespace psv_func_detail { static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL"); - static __forceinline T func(ARMv7Context& context) + __forceinline static T get_arg(ARMv7Context& context) { return cast_from_armv7_gpr(context.GPR[g_count - 1]); } + + __forceinline static void put_arg(ARMv7Context& context, const T& arg) + { + context.GPR[g_count - 1] = cast_to_armv7_gpr(arg); + } }; template @@ -442,7 +454,11 @@ namespace psv_func_detail static_assert(f_count <= 0, "TODO: Unsupported argument type (float)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static __forceinline T func(ARMv7Context& context) + __forceinline static T get_arg(ARMv7Context& context) + { + } + + __forceinline static void put_arg(ARMv7Context& context, const T& arg) { } }; @@ -453,7 +469,11 @@ namespace psv_func_detail static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); - static __forceinline T func(ARMv7Context& context) + __forceinline static T get_arg(ARMv7Context& context) + { + } + + __forceinline static void put_arg(ARMv7Context& context, const T& arg) { } }; @@ -465,11 +485,19 @@ namespace psv_func_detail static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)"); static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK"); - static __forceinline T func(ARMv7Context& context) + __forceinline static T get_arg(ARMv7Context& context) { // TODO: check - const u32 res = context.get_stack_arg(g_count); - return cast_from_armv7_gpr(res); + return cast_from_armv7_gpr(context.get_stack_arg(g_count)); + } + + __forceinline static void put_arg(ARMv7Context& context, const T& arg) + { + // TODO: check + const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); + + context.write_stack_arg(stack_pos, cast_to_armv7_gpr(arg)); } }; @@ -481,7 +509,12 @@ namespace psv_func_detail static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL"); - static __forceinline void func(ARMv7Context& context, const T& result) + __forceinline static T get_result(ARMv7Context& context) + { + return cast_from_armv7_gpr(context.GPR[0]); + } + + __forceinline static void put_result(ARMv7Context& context, const T& result) { context.GPR[0] = cast_to_armv7_gpr(result); } @@ -492,7 +525,7 @@ namespace psv_func_detail //{ // static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - // static __forceinline void func(ARMv7Context& context, const T& result) + // static __forceinline void put_result(ARMv7Context& context, const T& result) // { // } //}; @@ -502,11 +535,21 @@ namespace psv_func_detail //{ // static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - // static __forceinline void func(ARMv7Context& context, const T& result) + // static __forceinline void put_result(ARMv7Context& context, const T& result) // { // } //}; + template + struct result_type + { + static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); + 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); + }; + template struct call_impl { @@ -554,18 +597,35 @@ namespace psv_func_detail const int f = f_count + (is_float ? 1 : 0); const int v = v_count + (is_vector ? 1 : 0); - return std::tuple_cat(std::tuple(bind_arg::func(context)), iterate(context)); + return std::tuple_cat(std::tuple(bind_arg::get_arg(context)), iterate(context)); } - template - struct result_type + template + __forceinline static bool put_func_args(ARMv7Context& context) { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - 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); - }; + // terminator + return false; + } + + template + __forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args) + { + static_assert(!std::is_pointer::value, "Invalid callback argument type (pointer)"); + static_assert(!std::is_reference::value, "Invalid callback argument type (reference)"); + // 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 + ? ((f_count >= 4) ? ARG_STACK : ARG_FLOAT) + : (is_vector ? ((v_count >= 4) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 4) ? 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); + + bind_arg::put_arg(context, arg); + // return true if stack was used + return put_func_args(context, args...) || (t == ARG_STACK); + } template class func_binder; @@ -623,7 +683,7 @@ namespace psv_func_detail virtual void operator()(ARMv7Context& context) { - bind_result::value>::func(context, call(m_call, iterate<0, 0, 0, T...>(context))); + bind_result::value>::put_result(context, call(m_call, iterate<0, 0, 0, T...>(context))); } }; @@ -642,7 +702,36 @@ namespace psv_func_detail virtual void operator()(ARMv7Context& context) { - bind_result::value>::func(context, call(m_call, std::tuple_cat(std::tuple(context), iterate<0, 0, 0, T...>(context)))); + bind_result::value>::put_result(context, call(m_call, std::tuple_cat(std::tuple(context), iterate<0, 0, 0, T...>(context)))); + } + }; + + template + struct func_caller + { + __forceinline static RT call(ARMv7Context& context, u32 addr, T... args) + { + func_caller::call(context, addr, args...); + + return bind_result::value>::get_result(context); + } + }; + + template + struct func_caller + { + __forceinline static void call(ARMv7Context& context, u32 addr, T... args) + { + if (put_func_args<0, 0, 0, T...>(context, args...)) + { + context.SP -= FIXED_STACK_FRAME_SIZE; + context.fast_call(addr); + context.SP += FIXED_STACK_FRAME_SIZE; + } + else + { + context.fast_call(addr); + } } }; } @@ -673,4 +762,5 @@ psv_func* get_psv_func_by_nid(u32 nid); u32 get_psv_func_index(psv_func* func); void execute_psv_func_by_index(ARMv7Context& context, u32 index); -void list_known_psv_modules(); +void initialize_psv_modules(); +void finalize_psv_modules(); diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 5915a52a05..23c7123b2d 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -1,6 +1,7 @@ #pragma once class CPUThread; +struct ARMv7Context; namespace vm { @@ -332,9 +333,11 @@ namespace vm public: typedef RT(*type)(T...); - RT operator()(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context + RT operator()(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified PPU thread context - RT operator()(T... args) const; // defined in CB_FUNC.h, call using current CPU thread context + RT operator()(ARMv7Context& context, T... args) const; // defined in ARMv7Callback.h, passing context is mandatory + + RT operator()(T... args) const; // defined in CB_FUNC.h, call using current PPU thread context AT addr() const { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 9944a5860f..9e17b56ddf 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -5,6 +5,7 @@ #include "Emu/System.h" #include "Emu/GameInfo.h" +#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/SysCalls/Static.h" #include "Emu/SysCalls/ModuleManager.h" #include "Emu/Cell/PPUThread.h" @@ -361,6 +362,7 @@ void Emulator::Stop() LOG_NOTICE(HLE, "All threads stopped..."); + finalize_psv_modules(); m_rsx_callback = 0; // TODO: check finalization order diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index cb9be62759..988d1d779c 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -89,7 +89,7 @@ namespace loader case MACHINE_MIPS: break; case MACHINE_ARM: { - list_known_psv_modules(); + initialize_psv_modules(); auto armv7_thr_stop_data = vm::psv::ptr::make(Memory.PSV.RAM.AllocAlign(3 * 4)); armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb) diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 001fcfc477..e68b19b861 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -266,6 +266,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 681270e3d6..3537bdfbf0 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1285,5 +1285,8 @@ Emu\CPU\ARMv7 + + Emu\CPU\ARMv7 + \ No newline at end of file