ARMv7Callback.h, psv modules initialization fixed

sceLibc: __cxa_atexit, __aeabi_atexit
This commit is contained in:
Nekotekina 2015-01-21 17:34:05 +03:00
parent 506951a5a4
commit 509e09c2c5
14 changed files with 251 additions and 58 deletions

View file

@ -0,0 +1,18 @@
#pragma once
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h"
namespace vm
{
template<typename AT, typename RT, typename... T>
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::operator()(ARMv7Context& context, T... args) const
{
return psv_func_detail::func_caller<RT, T...>::call(context, vm::cast(this->addr()), args...);
}
}
template<typename RT, typename... T>
__forceinline RT cb_call(ARMv7Context& context, u32 addr, T... args)
{
return psv_func_detail::func_caller<RT, T...>::call(context, addr, args...);
}

View file

@ -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
{

View file

@ -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)

View file

@ -327,6 +327,10 @@ s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr<s32> 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);

View file

@ -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<void> g_dso;
typedef void(*atexit_func_t)(vm::psv::ptr<void>);
std::vector<std::function<void(ARMv7Context&)>> g_atexit;
namespace sce_libc_func
{
void __cxa_atexit()
void __cxa_atexit(vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> arg, vm::psv::ptr<void> 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<void> arg, vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> 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<void> 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<void> dst, vm::psv::ptr<const void> 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);

View file

@ -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);

View file

@ -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);

View file

@ -3,6 +3,7 @@
#include "PSVFuncList.h"
std::vector<psv_func> g_psv_func_list;
std::vector<psv_log_base*> 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<void, ARMv7Context&>([](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<void, ARMv7Context&>([](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<void, ARMv7Context&>([](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<void, ARMv7Context&>([](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();
}

View file

@ -7,6 +7,11 @@ class psv_log_base : public LogBase
std::string m_name;
void(*m_init_func)();
public:
std::function<void()> on_load;
std::function<void()> on_unload;
std::function<void()> 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<typename T, bind_arg_type type, int g_count, int f_count, int v_count>
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<T>(context.GPR[g_count - 1]);
}
__forceinline static void put_arg(ARMv7Context& context, const T& arg)
{
context.GPR[g_count - 1] = cast_to_armv7_gpr<T>(arg);
}
};
template<typename T, int g_count, int f_count, int v_count>
@ -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<T, u128>::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<T>(res);
return cast_from_armv7_gpr<T>(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<T>(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<T>(context.GPR[0]);
}
__forceinline static void put_result(ARMv7Context& context, const T& result)
{
context.GPR[0] = cast_to_armv7_gpr<T>(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<T, u128>::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<typename RT>
struct result_type
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
template <typename RT, typename F, typename Tuple, bool Done, int Total, int... N>
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<T>(bind_arg<T, t, g, f, v>::func(context)), iterate<g, f, v, A...>(context));
return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::get_arg(context)), iterate<g, f, v, A...>(context));
}
template<typename RT>
struct result_type
template<int g_count, int f_count, int v_count>
__forceinline static bool put_func_args(ARMv7Context& context)
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
// terminator
return false;
}
template<int g_count, int f_count, int v_count, typename T1, typename... T>
__forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args)
{
static_assert(!std::is_pointer<T1>::value, "Invalid callback argument type (pointer)");
static_assert(!std::is_reference<T1>::value, "Invalid callback argument type (reference)");
// TODO: check calculations
const bool is_float = std::is_floating_point<T>::value;
const bool is_vector = std::is_same<T, u128>::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<T1, t, g, f, v>::put_arg(context, arg);
// return true if stack was used
return put_func_args<g, f, v>(context, args...) || (t == ARG_STACK);
}
template<typename RT, typename... T>
class func_binder;
@ -623,7 +683,7 @@ namespace psv_func_detail
virtual void operator()(ARMv7Context& context)
{
bind_result<RT, result_type<RT>::value>::func(context, call<RT>(m_call, iterate<0, 0, 0, T...>(context)));
bind_result<RT, result_type<RT>::value>::put_result(context, call<RT>(m_call, iterate<0, 0, 0, T...>(context)));
}
};
@ -642,7 +702,36 @@ namespace psv_func_detail
virtual void operator()(ARMv7Context& context)
{
bind_result<RT, result_type<RT>::value>::func(context, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Context&>(context), iterate<0, 0, 0, T...>(context))));
bind_result<RT, result_type<RT>::value>::put_result(context, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Context&>(context), iterate<0, 0, 0, T...>(context))));
}
};
template<typename RT, typename... T>
struct func_caller
{
__forceinline static RT call(ARMv7Context& context, u32 addr, T... args)
{
func_caller<void, T...>::call(context, addr, args...);
return bind_result<RT, result_type<RT>::value>::get_result(context);
}
};
template<typename... T>
struct func_caller<void, T...>
{
__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();

View file

@ -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
{

View file

@ -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

View file

@ -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<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb)

View file

@ -266,6 +266,7 @@
<ClInclude Include="Crypto\unself.h" />
<ClInclude Include="Crypto\utils.h" />
<ClInclude Include="define_new_memleakdetect.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Context.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Decoder.h" />
<ClInclude Include="Emu\ARMv7\ARMv7DisAsm.h" />

View file

@ -1285,5 +1285,8 @@
<ClInclude Include="Emu\ARMv7\ARMv7Context.h">
<Filter>Emu\CPU\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h">
<Filter>Emu\CPU\ARMv7</Filter>
</ClInclude>
</ItemGroup>
</Project>