sys_ppu_thread_create: read function descriptor immediately and save it

This commit is contained in:
Eladash 2020-04-08 14:26:31 +03:00 committed by Ivan
parent 8c838698af
commit c948c9305c
8 changed files with 39 additions and 15 deletions

View File

@ -137,7 +137,7 @@ error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 en
}
// Call the syscall
if (error_code res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname))
if (error_code res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ vm::cast(entry), tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname))
{
return res;
}

View File

@ -2,6 +2,8 @@
#include "Emu/Cell/PPUThread.h"
struct ppu_func_opd_t;
namespace ppu_cb_detail
{
enum _func_arg_type
@ -179,12 +181,18 @@ namespace vm
template<typename AT, typename RT, typename... T>
FORCE_INLINE RT _ptr_base<RT(T...), AT>::operator()(ppu_thread& CPU, T... args) const
{
const auto data = vm::_ptr<u32>(vm::cast(m_addr, HERE));
const u32 pc = data[0];
const u32 rtoc = data[1];
const auto data = vm::_ptr<ppu_func_opd_t>(vm::cast(m_addr, HERE));
const u32 pc = data->addr;
const u32 rtoc = data->rtoc;
return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
}
template<typename AT, typename RT, typename... T>
FORCE_INLINE const ppu_func_opd_t& _ptr_base<RT(T...), AT>::opd() const
{
return vm::_ref<ppu_func_opd_t>(vm::cast(m_addr, HERE));
}
}
template<typename RT, typename... T> inline RT cb_call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)

View File

@ -602,6 +602,12 @@ void ppu_thread::cpu_task()
cmd_pop(), ppu_function_manager::get().at(arg)(*this);
break;
}
case ppu_cmd::opd_call:
{
const ppu_func_opd_t opd = cmd_get(1).as<ppu_func_opd_t>();
cmd_pop(1), fast_call(opd.addr, opd.rtoc);
break;
}
case ppu_cmd::ptr_call:
{
const ppu_function_t func = cmd_get(1).as<ppu_function_t>();
@ -747,6 +753,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
, stack_size(param.stack_size)
, stack_addr(param.stack_addr)
, joiner(detached != 0 ? ppu_join_status::detached : ppu_join_status::joinable)
, entry_func(param.entry)
, start_time(get_guest_system_time())
, ppu_tname(stx::shared_cptr<std::string>::make(name))
{
@ -760,14 +767,9 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
cmd_list
({
{ppu_cmd::set_args, 2}, param.arg0, param.arg1,
{ppu_cmd::lle_call, param.entry},
{ppu_cmd::opd_call, 0}, std::bit_cast<u64>(entry_func),
});
}
else
{
// Save entry for further use (interrupt handler workaround)
gpr[2] = param.entry;
}
// Trigger the scheduler
state += cpu_flag::suspend;

View File

@ -16,6 +16,7 @@ enum class ppu_cmd : u32
lle_call, // Load addr and rtoc at *arg or *gpr[arg] and execute
hle_call, // Execute function by index (arg)
ptr_call, // Execute function by pointer
opd_call, // Execute function by provided rtoc and address (unlike lle_call, does not read memory)
initialize, // ppu_initialize()
sleep,
reset_stack, // resets stack address
@ -35,13 +36,20 @@ enum class ppu_syscall_code : u64
{
};
// ppu function descriptor
struct ppu_func_opd_t
{
be_t<u32> addr;
be_t<u32> rtoc;
};
// ppu_thread constructor argument
struct ppu_thread_params
{
vm::addr_t stack_addr;
u32 stack_size;
u32 tls_addr;
u32 entry;
ppu_func_opd_t entry;
u64 arg0;
u64 arg1;
};
@ -192,6 +200,7 @@ public:
cmd64 cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
cmd64 cmd_get(u32 index) { return cmd_queue[cmd_queue.peek() + index].load(); }
const ppu_func_opd_t entry_func;
u64 start_time{0}; // Sleep start timepoint
alignas(64) u64 syscall_args[4]{0}; // Last syscall arguments stored
const char* current_function{}; // Current function name for diagnosis, optimized for speed.

View File

@ -15,7 +15,7 @@ void lv2_int_serv::exec()
({
{ ppu_cmd::reset_stack, 0 },
{ ppu_cmd::set_args, 2 }, arg1, arg2,
{ ppu_cmd::lle_call, 2 },
{ ppu_cmd::opd_call, 0 }, std::bit_cast<u64>(thread->entry_func),
{ ppu_cmd::sleep, 0 }
});

View File

@ -5,6 +5,7 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUCallback.h"
#include "sys_event.h"
#include "sys_process.h"
#include "sys_mmapper.h"
@ -362,6 +363,8 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
return CELL_EPERM;
}
const ppu_func_opd_t entry = param->entry.opd();
// Clean some detached thread (hack)
g_fxo->get<ppu_thread_cleaner>()->clean(0);
@ -408,7 +411,7 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
p.stack_addr = stack_base;
p.stack_size = stack_size;
p.tls_addr = param->tls;
p.entry = param->entry;
p.entry = entry;
p.arg0 = arg;
p.arg1 = unk;
@ -423,7 +426,7 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
}
*thread_id = tid;
sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x)", ppu_name, tid);
sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x, func=*0x%x, rtoc=0x%x)", ppu_name, tid, entry.addr, entry.rtoc);
return CELL_OK;
}

View File

@ -26,7 +26,7 @@ struct sys_ppu_thread_stack_t
struct ppu_thread_param_t
{
be_t<u32> entry; // vm::bptr<void(u64)>
vm::bptr<void(u64)> entry;
be_t<u32> tls; // vm::bptr<void>
};

View File

@ -5,6 +5,7 @@
#include "vm.h"
class ppu_thread;
struct ppu_func_opd_t;
namespace vm
{
@ -262,6 +263,7 @@ namespace vm
// Callback; defined in PPUCallback.h, passing context is mandatory
RT operator()(ppu_thread& ppu, T... args) const;
const ppu_func_opd_t& opd() const;
};
template<typename AT, typename RT, typename... T>