mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
Exitspawn support renewal
Implemented _sys_process_exit2 syscall Rewritten sys_game_process_exitspawn Rewritten sys_game_process_exitspawn2 Implemented _sys_process_atexitspawn Implemented _sys_process_at_Exitspawn And some other changes
This commit is contained in:
parent
18d472b7e1
commit
519f21db18
15 changed files with 285 additions and 198 deletions
|
@ -179,31 +179,29 @@ s32 sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpDrmProcessExitSpawn(vm::cptr<u8> klicensee, vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
|
||||
s32 sceNpDrmProcessExitSpawn(ppu_thread& ppu, vm::cptr<u8> klicensee, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags)
|
||||
{
|
||||
sceNp.warning("sceNpDrmProcessExitSpawn(klicensee=*0x%x, path=%s, argv=*0x%x, envp=*0x%x, data=*0x%x, data_size=0x%x, prio=%u, flags=0x%x)",
|
||||
klicensee, path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
|
||||
sceNp.warning("sceNpDrmProcessExitSpawn(klicensee=*0x%x, path=%s, argv=**0x%x, envp=**0x%x, data=*0x%x, data_size=0x%x, prio=%d, flags=0x%x)", klicensee, path, argv, envp, data, data_size, prio, flags);
|
||||
|
||||
if (s32 error = npDrmIsAvailable(klicensee, path))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
sys_game_process_exitspawn(path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
|
||||
sys_game_process_exitspawn(ppu, path, argv, envp, data, data_size, prio, flags);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpDrmProcessExitSpawn2(vm::cptr<u8> klicensee, vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
|
||||
s32 sceNpDrmProcessExitSpawn2(ppu_thread& ppu, vm::cptr<u8> klicensee, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags)
|
||||
{
|
||||
sceNp.warning("sceNpDrmProcessExitSpawn2(klicensee=*0x%x, path=%s, argv=*0x%x, envp=*0x%x, data=*0x%x, data_size=0x%x, prio=%u, flags=0x%x)",
|
||||
klicensee, path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
|
||||
sceNp.warning("sceNpDrmProcessExitSpawn2(klicensee=*0x%x, path=%s, argv=**0x%x, envp=**0x%x, data=*0x%x, data_size=0x%x, prio=%d, flags=0x%x)", klicensee, path, argv, envp, data, data_size, prio, flags);
|
||||
|
||||
if (s32 error = npDrmIsAvailable(klicensee, path))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
sys_game_process_exitspawn2(path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
|
||||
sys_game_process_exitspawn2(ppu, path, argv, envp, data, data_size, prio, flags);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_mutex.h"
|
||||
#include "Emu/Cell/lv2/sys_interrupt.h"
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
@ -13,6 +14,9 @@ extern u64 get_system_time();
|
|||
extern fs::file g_tty;
|
||||
|
||||
vm::gvar<s32> sys_prx_version; // ???
|
||||
vm::gvar<vm::ptr<void()>> g_ppu_atexitspawn;
|
||||
vm::gvar<vm::ptr<void()>> g_ppu_at_Exitspawn;
|
||||
extern vm::gvar<u32> g_ppu_exit_mutex;
|
||||
|
||||
s64 sys_time_get_system_time()
|
||||
{
|
||||
|
@ -21,33 +25,34 @@ s64 sys_time_get_system_time()
|
|||
return get_system_time();
|
||||
}
|
||||
|
||||
s32 sys_process_exit(ppu_thread& ppu, s32 status)
|
||||
void sys_process_exit(ppu_thread& ppu, s32 status)
|
||||
{
|
||||
vm::temporary_unlock(ppu);
|
||||
|
||||
sysPrxForUser.warning("sys_process_exit(status=%d)", status);
|
||||
|
||||
Emu.CallAfter([]()
|
||||
sys_mutex_lock(ppu, *g_ppu_exit_mutex, 0);
|
||||
|
||||
// TODO (process atexit)
|
||||
return _sys_process_exit(ppu, status, 0, 0);
|
||||
}
|
||||
|
||||
void _sys_process_atexitspawn(vm::ptr<void()> func)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_process_atexitspawn(0x%x)", func);
|
||||
|
||||
if (!*g_ppu_atexitspawn)
|
||||
{
|
||||
sysPrxForUser.success("Process finished");
|
||||
Emu.Stop();
|
||||
});
|
||||
|
||||
thread_ctrl::eternalize();
|
||||
|
||||
return CELL_OK;
|
||||
*g_ppu_atexitspawn = func;
|
||||
}
|
||||
}
|
||||
|
||||
s64 _sys_process_atexitspawn()
|
||||
void _sys_process_at_Exitspawn(vm::ptr<void()> func)
|
||||
{
|
||||
sysPrxForUser.todo("_sys_process_atexitspawn()");
|
||||
return CELL_OK;
|
||||
}
|
||||
sysPrxForUser.warning("_sys_process_at_Exitspawn(0x%x)", func);
|
||||
|
||||
s64 _sys_process_at_Exitspawn()
|
||||
{
|
||||
sysPrxForUser.todo("_sys_process_at_Exitspawn");
|
||||
return CELL_OK;
|
||||
if (!*g_ppu_at_Exitspawn)
|
||||
{
|
||||
*g_ppu_at_Exitspawn = func;
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_process_is_stack(u32 p)
|
||||
|
@ -244,6 +249,8 @@ DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []()
|
|||
sysPrxForUser_sys_rsxaudio_init();
|
||||
|
||||
REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf
|
||||
REG_VAR(sysPrxForUser, g_ppu_atexitspawn).flag(MFF_HIDDEN);
|
||||
REG_VAR(sysPrxForUser, g_ppu_at_Exitspawn).flag(MFF_HIDDEN);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_time_get_system_time);
|
||||
|
||||
|
|
|
@ -53,5 +53,5 @@ error_code sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u
|
|||
error_code sys_lwcond_wait(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
|
||||
void sys_ppu_thread_exit(ppu_thread& CPU, u64 val);
|
||||
void sys_game_process_exitspawn(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags);
|
||||
void sys_game_process_exitspawn2(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags);
|
||||
void sys_game_process_exitspawn(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
|
||||
void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
|
||||
|
|
|
@ -2,148 +2,153 @@
|
|||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_mutex.h"
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
extern vm::gvar<u32> g_ppu_exit_mutex;
|
||||
extern vm::gvar<vm::ptr<void()>> g_ppu_atexitspawn;
|
||||
extern vm::gvar<vm::ptr<void()>> g_ppu_at_Exitspawn;
|
||||
|
||||
void sys_game_process_exitspawn(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
|
||||
static u32 get_string_array_size(vm::cpptr<char> list, u32& out_count)
|
||||
{
|
||||
std::string _path = path.get_ptr();
|
||||
const std::string& from = "//";
|
||||
const std::string& to = "/";
|
||||
//out_count = 0;
|
||||
u32 result = 8;
|
||||
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = _path.find(from, start_pos)) != std::string::npos) {
|
||||
_path.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length();
|
||||
for (u32 i = 0; list; i++)
|
||||
{
|
||||
if (const vm::cptr<char> str = list[i])
|
||||
{
|
||||
out_count++;
|
||||
result += (((u32)std::strlen(str.get_ptr()) + 0x10) & -0x10) + 8;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sysPrxForUser.todo("sys_game_process_exitspawn()");
|
||||
sysPrxForUser.warning("path: %s", _path.c_str());
|
||||
sysPrxForUser.warning("argv: 0x%x", argv_addr);
|
||||
sysPrxForUser.warning("envp: 0x%x", envp_addr);
|
||||
sysPrxForUser.warning("data: 0x%x", data_addr);
|
||||
sysPrxForUser.warning("data_size: 0x%x", data_size);
|
||||
sysPrxForUser.warning("prio: %d", prio);
|
||||
sysPrxForUser.warning("flags: %d", flags);
|
||||
|
||||
std::vector<std::string> argv;
|
||||
std::vector<std::string> env;
|
||||
|
||||
if (argv_addr)
|
||||
{
|
||||
auto argvp = vm::cpptr<char>::make(argv_addr);
|
||||
while (argvp && *argvp)
|
||||
{
|
||||
argv.push_back(argvp[0].get_ptr());
|
||||
argvp++;
|
||||
}
|
||||
|
||||
for (auto &arg : argv)
|
||||
{
|
||||
sysPrxForUser.trace("argument: %s", arg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (envp_addr)
|
||||
{
|
||||
auto envp = vm::cpptr<char>::make(envp_addr);
|
||||
while (envp && *envp)
|
||||
{
|
||||
env.push_back(envp[0].get_ptr());
|
||||
envp++;
|
||||
}
|
||||
|
||||
for (auto &en : env)
|
||||
{
|
||||
sysPrxForUser.trace("env_argument: %s", en.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: execute the file in <path> with the args in argv
|
||||
// and the environment parameters in envp and copy the data
|
||||
// from data_addr into the adress space of the new process
|
||||
// then kill the current process
|
||||
|
||||
Emu.Pause();
|
||||
sysPrxForUser.success("Process finished");
|
||||
|
||||
Emu.CallAfter([=, path = vfs::get(_path)]()
|
||||
{
|
||||
Emu.Stop();
|
||||
Emu.BootGame(path, true);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void sys_game_process_exitspawn2(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
|
||||
static u32 get_exitspawn_size(vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32& arg_count, u32& env_count)
|
||||
{
|
||||
std::string _path = path.get_ptr();
|
||||
const std::string& from = "//";
|
||||
const std::string& to = "/";
|
||||
arg_count = 1;
|
||||
env_count = 0;
|
||||
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = _path.find(from, start_pos)) != std::string::npos) {
|
||||
_path.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length();
|
||||
u32 result = (((u32)std::strlen(path.get_ptr()) + 0x10) & -0x10) + 8;
|
||||
result += get_string_array_size(argv, arg_count);
|
||||
result += get_string_array_size(envp, env_count);
|
||||
|
||||
if ((arg_count + env_count) % 2)
|
||||
{
|
||||
result += 8;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void put_string_array(vm::pptr<char, u32, u64> pstr, vm::ptr<char>& str, u32 count, vm::cpptr<char> list)
|
||||
{
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
const u32 len = (u32)std::strlen(list[i].get_ptr());
|
||||
std::memcpy(str.get_ptr(), list[i].get_ptr(), len + 1);
|
||||
pstr[i] = str;
|
||||
str += (len + 0x10) & -0x10;
|
||||
}
|
||||
|
||||
sysPrxForUser.warning("sys_game_process_exitspawn2()");
|
||||
sysPrxForUser.warning("path: %s", _path.c_str());
|
||||
sysPrxForUser.warning("argv: 0x%x", argv_addr);
|
||||
sysPrxForUser.warning("envp: 0x%x", envp_addr);
|
||||
sysPrxForUser.warning("data: 0x%x", data_addr);
|
||||
sysPrxForUser.warning("data_size: 0x%x", data_size);
|
||||
sysPrxForUser.warning("prio: %d", prio);
|
||||
sysPrxForUser.warning("flags: %d", flags);
|
||||
pstr[count] = vm::null;
|
||||
}
|
||||
|
||||
std::vector<std::string> argv;
|
||||
std::vector<std::string> env;
|
||||
static void put_exitspawn(vm::ptr<void> out, vm::cptr<char> path, u32 argc, vm::cpptr<char> argv, u32 envc, vm::cpptr<char> envp)
|
||||
{
|
||||
vm::pptr<char, u32, u64> pstr = vm::cast(out.addr());
|
||||
vm::ptr<char> str = vm::static_ptr_cast<char>(out) + (argc + envc + (argc + envc) % 2) * 8 + 0x10;
|
||||
|
||||
if (argv_addr)
|
||||
const u32 len = (u32)std::strlen(path.get_ptr());
|
||||
std::memcpy(str.get_ptr(), path.get_ptr(), len + 1);
|
||||
*pstr++ = str;
|
||||
str += (len + 0x10) & -0x10;
|
||||
|
||||
put_string_array(pstr, str, argc - 1, argv);
|
||||
put_string_array(pstr + argc, str, envc, envp);
|
||||
}
|
||||
|
||||
static void exitspawn(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 _flags)
|
||||
{
|
||||
sys_mutex_lock(ppu, *g_ppu_exit_mutex, 0);
|
||||
|
||||
u32 arg_count = 0;
|
||||
u32 env_count = 0;
|
||||
u32 alloc_size = get_exitspawn_size(path, argv, envp, arg_count, env_count);
|
||||
|
||||
if (alloc_size > 0x1000)
|
||||
{
|
||||
auto argvp = vm::cpptr<char>::make(argv_addr);
|
||||
while (argvp && *argvp)
|
||||
{
|
||||
argv.push_back(argvp[0].get_ptr());
|
||||
argvp++;
|
||||
}
|
||||
|
||||
for (auto &arg : argv)
|
||||
{
|
||||
sysPrxForUser.trace("argument: %s", arg.c_str());
|
||||
}
|
||||
argv = vm::null;
|
||||
envp = vm::null;
|
||||
arg_count = 0;
|
||||
env_count = 0;
|
||||
alloc_size = get_exitspawn_size(path, vm::null, vm::null, arg_count, env_count);
|
||||
}
|
||||
|
||||
if (envp_addr)
|
||||
{
|
||||
auto envp = vm::cpptr<char>::make(envp_addr);
|
||||
while (envp && *envp)
|
||||
{
|
||||
env.push_back(envp[0].get_ptr());
|
||||
envp++;
|
||||
}
|
||||
alloc_size += 0x30;
|
||||
|
||||
for (auto &en : env)
|
||||
{
|
||||
sysPrxForUser.trace("env_argument: %s", en.c_str());
|
||||
}
|
||||
if (data_size > 0)
|
||||
{
|
||||
alloc_size += 0x1030;
|
||||
}
|
||||
|
||||
// TODO: execute the file in <path> with the args in argv
|
||||
// and the environment parameters in envp and copy the data
|
||||
// from data_addr into the adress space of the new process
|
||||
// then kill the current process
|
||||
u32 alloc_addr = vm::alloc(alloc_size, vm::main);
|
||||
|
||||
Emu.Pause();
|
||||
sysPrxForUser.success("Process finished");
|
||||
|
||||
Emu.CallAfter([=, path = vfs::get(_path)]()
|
||||
if (!alloc_addr)
|
||||
{
|
||||
Emu.Stop();
|
||||
Emu.BootGame(path, true);
|
||||
});
|
||||
// TODO (process atexit)
|
||||
return _sys_process_exit(ppu, CELL_ENOMEM, 0, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
put_exitspawn(vm::cast(alloc_addr + 0x30), path, arg_count, argv, env_count, envp);
|
||||
|
||||
if (data_size)
|
||||
{
|
||||
std::memcpy(vm::base(alloc_addr + alloc_size - 0x1000), vm::base(data), std::min<u32>(data_size, 0x1000));
|
||||
}
|
||||
|
||||
vm::ptr<sys_exit2_param> arg = vm::cast(alloc_addr);
|
||||
arg->x0 = 0x85;
|
||||
arg->this_size = 0x30;
|
||||
arg->next_size = alloc_size - 0x30;
|
||||
arg->prio = prio;
|
||||
arg->flags = _flags;
|
||||
arg->args = vm::cast(alloc_addr + 0x30);
|
||||
|
||||
if ((_flags >> 62) == 0 && *g_ppu_atexitspawn)
|
||||
{
|
||||
// Execute atexitspawn
|
||||
g_ppu_atexitspawn->operator()(ppu);
|
||||
}
|
||||
|
||||
if ((_flags >> 62) == 1 && *g_ppu_at_Exitspawn)
|
||||
{
|
||||
// Execute at_Exitspawn
|
||||
g_ppu_at_Exitspawn->operator()(ppu);
|
||||
}
|
||||
|
||||
// TODO (process atexit)
|
||||
return _sys_process_exit2(ppu, 0, arg, alloc_size, 0x10000000);
|
||||
}
|
||||
|
||||
void sys_game_process_exitspawn(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags)
|
||||
{
|
||||
sysPrxForUser.warning("sys_game_process_exitspawn(path=%s, argv=**0x%x, envp=**0x%x, data=*0x%x, data_size=0x%x, prio=%d, flags=0x%x)", path, argv, envp, data, data_size, prio, flags);
|
||||
|
||||
return exitspawn(ppu, path, argv, envp, data, data_size, prio, (flags & 0xf0) | (1ull << 63));
|
||||
}
|
||||
|
||||
void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags)
|
||||
{
|
||||
sysPrxForUser.warning("sys_game_process_exitspawn2(path=%s, argv=**0x%x, envp=**0x%x, data=*0x%x, data_size=0x%x, prio=%d, flags=0x%x)", path, argv, envp, data, data_size, prio, flags);
|
||||
|
||||
return exitspawn(ppu, path, argv, envp, data, data_size, prio, (flags >> 62) >= 2 ? flags & 0xf0 : flags & 0xc0000000000000f0ull);
|
||||
}
|
||||
|
||||
s32 sys_game_board_storage_read()
|
||||
|
|
|
@ -13,6 +13,7 @@ extern logs::channel sysPrxForUser;
|
|||
|
||||
vm::gvar<sys_lwmutex_t> g_ppu_atexit_lwm;
|
||||
vm::gvar<vm::ptr<void()>[8]> g_ppu_atexit;
|
||||
vm::gvar<u32> g_ppu_exit_mutex; // sys_process_exit2 mutex
|
||||
vm::gvar<u32> g_ppu_once_mutex;
|
||||
vm::gvar<sys_lwmutex_t> g_ppu_prx_lwm;
|
||||
|
||||
|
@ -112,6 +113,10 @@ void sys_initialize_tls(ppu_thread& ppu, u64 main_thread_id, u32 tls_seg_addr, u
|
|||
attr->name_u64 = "_lv2ppu\0"_u64;
|
||||
sys_mutex_create(g_ppu_once_mutex, attr);
|
||||
|
||||
attr->recursive = SYS_SYNC_RECURSIVE;
|
||||
attr->name_u64 = "_lv2tls\0"_u64;
|
||||
sys_mutex_create(g_ppu_exit_mutex, attr);
|
||||
|
||||
lwa->protocol = SYS_SYNC_PRIORITY;
|
||||
lwa->recursive = SYS_SYNC_RECURSIVE;
|
||||
lwa->name_u64 = "_lv2prx\0"_u64;
|
||||
|
@ -270,6 +275,7 @@ void sysPrxForUser_sys_ppu_thread_init()
|
|||
REG_VAR(sysPrxForUser, g_ppu_once_mutex).flag(MFF_HIDDEN);
|
||||
REG_VAR(sysPrxForUser, g_ppu_atexit).flag(MFF_HIDDEN);
|
||||
REG_VAR(sysPrxForUser, g_ppu_prx_lwm).flag(MFF_HIDDEN);
|
||||
REG_VAR(sysPrxForUser, g_ppu_exit_mutex).flag(MFF_HIDDEN);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_initialize_tls).args = {"main_thread_id", "tls_seg_addr", "tls_seg_size", "tls_mem_size"}; // Test
|
||||
REG_FUNC(sysPrxForUser, sys_ppu_thread_create);
|
||||
|
|
|
@ -1360,7 +1360,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
|
||||
// Set path (TODO)
|
||||
_main->name = "";
|
||||
_main->path = vfs::get(Emu.GetPath());
|
||||
_main->path = vfs::get(Emu.argv[0]);
|
||||
|
||||
// Analyse executable (TODO)
|
||||
_main->analyse(0, static_cast<u32>(elf.header.e_entry));
|
||||
|
@ -1372,27 +1372,42 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
g_ps3_sdk_version = sdk_version;
|
||||
|
||||
// Initialize process arguments
|
||||
std::initializer_list<std::string> args = { Emu.GetPath()/*, "-emu"s*/ };
|
||||
auto args = vm::ptr<u64>::make(vm::alloc(SIZE_32(u64) * (::size32(Emu.argv) + ::size32(Emu.envp) + 2), vm::main));
|
||||
auto argv = args;
|
||||
|
||||
auto argv = vm::ptr<u64>::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main));
|
||||
auto envp = vm::ptr<u64>::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main));
|
||||
*envp = 0;
|
||||
|
||||
for (const auto& arg : args)
|
||||
for (const auto& arg : Emu.argv)
|
||||
{
|
||||
const u32 arg_size = ::align(::size32(arg) + 1, 0x10);
|
||||
const u32 arg_addr = vm::alloc(arg_size, vm::main);
|
||||
|
||||
std::memcpy(vm::base(arg_addr), arg.data(), arg_size);
|
||||
|
||||
*argv++ = arg_addr;
|
||||
*args++ = arg_addr;
|
||||
}
|
||||
|
||||
argv -= ::size32(args);
|
||||
*args++ = 0;
|
||||
auto envp = args;
|
||||
|
||||
for (const auto& arg : Emu.envp)
|
||||
{
|
||||
const u32 arg_size = ::align(::size32(arg) + 1, 0x10);
|
||||
const u32 arg_addr = vm::alloc(arg_size, vm::main);
|
||||
|
||||
std::memcpy(vm::base(arg_addr), arg.data(), arg_size);
|
||||
|
||||
*args++ = arg_addr;
|
||||
}
|
||||
|
||||
// Initialize main thread
|
||||
auto ppu = idm::make_ptr<ppu_thread>("main_thread", primary_prio, primary_stacksize);
|
||||
|
||||
// Write initial data (exitspawn)
|
||||
if (Emu.data.size())
|
||||
{
|
||||
std::memcpy(vm::base(ppu->stack_addr + ppu->stack_size - ::size32(Emu.data)), Emu.data.data(), Emu.data.size());
|
||||
ppu->gpr[1] -= Emu.data.size();
|
||||
}
|
||||
|
||||
ppu->cmd_push({ppu_cmd::initialize, 0});
|
||||
|
||||
// TODO: adjust for liblv2 loading option
|
||||
|
@ -1434,7 +1449,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
// Set command line arguments, run entry function
|
||||
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_args, 8 }, u64{Emu.argv.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{elf.header.e_entry},
|
||||
{ ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize},
|
||||
{ ppu_cmd::lle_call, entry },
|
||||
|
|
|
@ -233,7 +233,7 @@ s32 sys_process_detach_child(u64 unk)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3)
|
||||
void _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3)
|
||||
{
|
||||
vm::temporary_unlock(ppu);
|
||||
|
||||
|
@ -248,7 +248,60 @@ s32 _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3)
|
|||
thread_ctrl::eternalize();
|
||||
}
|
||||
|
||||
s32 _sys_process_exit2(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3, u32 arg4)
|
||||
void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr<sys_exit2_param> arg, u32 arg_size, u32 arg4)
|
||||
{
|
||||
fmt::throw_exception("_sys_process_exit2");
|
||||
sys_process.warning("_sys_process_exit2(status=%d, arg=*0x%x, arg_size=0x%x, arg4=0x%x)", status, arg, arg_size, arg4);
|
||||
|
||||
auto pstr = +arg->args;
|
||||
|
||||
std::vector<std::string> argv;
|
||||
std::vector<std::string> envp;
|
||||
|
||||
while (auto ptr = *pstr++)
|
||||
{
|
||||
argv.emplace_back(ptr.get_ptr());
|
||||
sys_process.notice(" *** arg: %s", ptr);
|
||||
}
|
||||
|
||||
while (auto ptr = *pstr++)
|
||||
{
|
||||
envp.emplace_back(ptr.get_ptr());
|
||||
sys_process.notice(" *** env: %s", ptr);
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
|
||||
if (arg_size > 0x1030)
|
||||
{
|
||||
data.resize(0x1000);
|
||||
std::memcpy(data.data(), vm::base(arg.addr() + arg_size - 0x1000), 0x1000);
|
||||
}
|
||||
|
||||
if (argv.empty())
|
||||
{
|
||||
return _sys_process_exit(ppu, status, 0, 0);
|
||||
}
|
||||
|
||||
// TODO: set prio, flags
|
||||
|
||||
std::string path = vfs::get(argv[0]);
|
||||
|
||||
vm::temporary_unlock(ppu);
|
||||
|
||||
Emu.CallAfter([path = std::move(path), argv = std::move(argv), envp = std::move(envp), data = std::move(data)]()
|
||||
{
|
||||
sys_process.success("Process finished -> %s", argv[0]);
|
||||
Emu.Stop();
|
||||
Emu.argv = std::move(argv);
|
||||
Emu.envp = std::move(envp);
|
||||
Emu.data = std::move(data);
|
||||
Emu.BootGame(path, true);
|
||||
|
||||
if (Emu.IsReady() && !g_cfg.misc.autostart)
|
||||
{
|
||||
Emu.Run();
|
||||
}
|
||||
});
|
||||
|
||||
thread_ctrl::eternalize();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@ enum : u32
|
|||
SYS_EVENT_FLAG_OBJECT = 0x98,
|
||||
};
|
||||
|
||||
struct sys_exit2_param
|
||||
{
|
||||
be_t<u64> x0; // 0x85
|
||||
be_t<u64> this_size; // 0x30
|
||||
be_t<u64> next_size;
|
||||
be_t<s64> prio;
|
||||
be_t<u64> flags;
|
||||
vm::ps3::bpptr<char, u64, u64> args;
|
||||
};
|
||||
|
||||
// Auxiliary functions
|
||||
s32 process_getpid();
|
||||
s32 process_get_sdk_version(u32 pid, s32& ver);
|
||||
|
@ -41,5 +51,5 @@ s32 sys_process_kill(u32 pid);
|
|||
s32 sys_process_wait_for_child(u32 pid, vm::ps3::ptr<u32> status, u64 unk);
|
||||
s32 sys_process_wait_for_child2(u64 unk1, u64 unk2, u64 unk3, u64 unk4, u64 unk5, u64 unk6);
|
||||
s32 sys_process_detach_child(u64 unk);
|
||||
s32 _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3);
|
||||
s32 _sys_process_exit2(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3, u32 arg4);
|
||||
void _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3);
|
||||
void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ps3::ptr<sys_exit2_param> arg, u32 arg_size, u32 arg4);
|
||||
|
|
|
@ -587,7 +587,7 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
// Initialize args
|
||||
std::vector<char> argv_data;
|
||||
|
||||
for (const auto& arg : { Emu.GetPath(), "-emu"s })
|
||||
for (const auto& arg : Emu.argv)
|
||||
{
|
||||
argv_data.insert(argv_data.end(), arg.begin(), arg.end());
|
||||
argv_data.insert(argv_data.end(), '\0');
|
||||
|
|
|
@ -228,12 +228,6 @@ void Emulator::Init()
|
|||
fxm::make_always<patch_engine>()->append(fs::get_config_dir() + "/patch.yml");
|
||||
}
|
||||
|
||||
void Emulator::SetPath(const std::string& path, const std::string& elf_path)
|
||||
{
|
||||
m_path = path;
|
||||
m_elf_path = elf_path;
|
||||
}
|
||||
|
||||
bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
|
||||
{
|
||||
static const char* boot_list[] =
|
||||
|
@ -246,7 +240,7 @@ bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
|
|||
|
||||
if (direct && fs::is_file(path))
|
||||
{
|
||||
SetPath(path);
|
||||
m_path = path;
|
||||
Load(add_only);
|
||||
|
||||
return true;
|
||||
|
@ -258,7 +252,7 @@ bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
|
|||
|
||||
if (fs::is_file(elf))
|
||||
{
|
||||
SetPath(elf);
|
||||
m_path = elf;
|
||||
Load(add_only);
|
||||
|
||||
return true;
|
||||
|
@ -380,7 +374,7 @@ void Emulator::Load(bool add_only)
|
|||
if (fs::rename(elf_dir + "/../../", hdd0_disc + elf_dir.substr(hdd0_game.size()) + "/../../", false))
|
||||
{
|
||||
LOG_SUCCESS(LOADER, "Disc game %s moved to special location /dev_hdd0/disc/", m_title_id);
|
||||
return SetPath(hdd0_disc + m_path.substr(hdd0_game.size())), Load();
|
||||
return m_path = hdd0_disc + m_path.substr(hdd0_game.size()), Load();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -460,7 +454,7 @@ void Emulator::Load(bool add_only)
|
|||
{
|
||||
// Booting game update
|
||||
LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id);
|
||||
return SetPath(hdd0_boot), Load();
|
||||
return m_path = hdd0_boot, Load();
|
||||
}
|
||||
|
||||
// Mount /host_root/ if necessary
|
||||
|
@ -528,25 +522,25 @@ void Emulator::Load(bool add_only)
|
|||
|
||||
vm::ps3::init();
|
||||
|
||||
if (m_elf_path.empty())
|
||||
if (argv.empty())
|
||||
{
|
||||
if (m_path.find(hdd0_game) != -1)
|
||||
{
|
||||
m_elf_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size());
|
||||
argv.emplace_back("/dev_hdd0/game/" + m_path.substr(hdd0_game.size()));
|
||||
}
|
||||
else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
|
||||
{
|
||||
//Disc games are on /dev_bdvd/
|
||||
size_t pos = m_path.rfind("PS3_GAME");
|
||||
m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
|
||||
// Disc games are on /dev_bdvd/
|
||||
const std::size_t pos = m_path.rfind("PS3_GAME");
|
||||
argv.emplace_back("/dev_bdvd/" + m_path.substr(pos));
|
||||
}
|
||||
else
|
||||
{
|
||||
//For homebrew
|
||||
m_elf_path = "/host_root/" + m_path;
|
||||
// For homebrew
|
||||
argv.emplace_back("/host_root/" + m_path);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
|
||||
LOG_NOTICE(LOADER, "Elf path: %s", argv[0]);
|
||||
}
|
||||
|
||||
ppu_load_exec(ppu_exec);
|
||||
|
@ -579,10 +573,10 @@ void Emulator::Load(bool add_only)
|
|||
GetCallbacks().on_ready();
|
||||
vm::psv::init();
|
||||
|
||||
if (m_elf_path.empty())
|
||||
if (argv.empty())
|
||||
{
|
||||
m_elf_path = "host_root:" + m_path;
|
||||
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
|
||||
argv.emplace_back("host_root:" + m_path);
|
||||
LOG_NOTICE(LOADER, "Elf path: %s", argv[0]);
|
||||
}
|
||||
|
||||
arm_load_exec(arm_exec);
|
||||
|
@ -794,6 +788,10 @@ void Emulator::Stop()
|
|||
extern void jit_finalize();
|
||||
jit_finalize();
|
||||
#endif
|
||||
|
||||
argv.clear();
|
||||
envp.clear();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
s32 error_code::error_report(const fmt_type_info* sup, u64 arg, const fmt_type_info* sup2, u64 arg2)
|
||||
|
|
|
@ -177,7 +177,6 @@ class Emulator final
|
|||
atomic_t<u64> m_pause_amend_time; // increased when resumed
|
||||
|
||||
std::string m_path;
|
||||
std::string m_elf_path;
|
||||
std::string m_cache_path;
|
||||
std::string m_title_id;
|
||||
std::string m_title;
|
||||
|
@ -210,12 +209,10 @@ public:
|
|||
}
|
||||
|
||||
void Init();
|
||||
void SetPath(const std::string& path, const std::string& elf_path = {});
|
||||
|
||||
const std::string& GetPath() const
|
||||
{
|
||||
return m_elf_path;
|
||||
}
|
||||
std::vector<std::string> argv;
|
||||
std::vector<std::string> envp;
|
||||
std::vector<u8> data;
|
||||
|
||||
const std::string& GetBoot() const
|
||||
{
|
||||
|
|
|
@ -60,8 +60,7 @@ int main(int argc, char** argv)
|
|||
// Ugly workaround
|
||||
QTimer::singleShot(2, [path = sstr(QFileInfo(parser.positionalArguments().at(0)).canonicalFilePath())]
|
||||
{
|
||||
Emu.SetPath(path);
|
||||
Emu.Load();
|
||||
Emu.BootGame(path, true);
|
||||
Emu.Run();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -140,8 +140,7 @@ UTILS_DLL_C_EXPORT ps3emu_api_error_code ps3emu_api_load_elf(const char *path)
|
|||
return ps3emu_api_not_found;
|
||||
}
|
||||
|
||||
Emu.SetPath(path);
|
||||
Emu.Load();
|
||||
Emu.BootGame(path, true);
|
||||
|
||||
return ps3emu_api_ok;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
|||
if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.IsStopped())) { Emu.Stop(); return; }
|
||||
break;
|
||||
case Qt::Key_R:
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.GetPath().empty())) { Emu.Stop(); Emu.Load(); return; }
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.GetBoot().empty())) { Emu.Stop(); Emu.Load(); return; }
|
||||
break;
|
||||
case Qt::Key_E:
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier)
|
||||
|
|
|
@ -61,7 +61,7 @@ auto Pause = []()
|
|||
if (Emu.IsReady()) Emu.Run();
|
||||
else if (Emu.IsPaused()) Emu.Resume();
|
||||
else if (Emu.IsRunning()) Emu.Pause();
|
||||
else if (!Emu.GetPath().empty()) Emu.Load();
|
||||
else if (!Emu.GetBoot().empty()) Emu.Load();
|
||||
};
|
||||
|
||||
/* An init method is used so that RPCS3App can create the necessary connects before calling init (specifically the stylesheet connect).
|
||||
|
@ -745,7 +745,7 @@ void main_window::RepaintToolBarIcons()
|
|||
{
|
||||
ui->toolbar_start->setIcon(m_icon_pause);
|
||||
}
|
||||
else if (Emu.IsStopped() && !Emu.GetPath().empty())
|
||||
else if (Emu.IsStopped() && !Emu.GetBoot().empty())
|
||||
{
|
||||
ui->toolbar_start->setIcon(m_icon_restart);
|
||||
}
|
||||
|
@ -817,7 +817,7 @@ void main_window::OnEmuStop()
|
|||
m_thumb_playPause->setIcon(m_icon_thumb_play);
|
||||
#endif
|
||||
EnableMenus(false);
|
||||
if (!Emu.GetPath().empty())
|
||||
if (!Emu.GetBoot().empty())
|
||||
{
|
||||
ui->toolbar_start->setEnabled(true);
|
||||
ui->toolbar_start->setIcon(m_icon_restart);
|
||||
|
@ -1564,7 +1564,7 @@ void main_window::keyPressEvent(QKeyEvent *keyEvent)
|
|||
case Qt::Key_E: if (Emu.IsPaused()) Emu.Resume(); else if (Emu.IsReady()) Emu.Run(); return;
|
||||
case Qt::Key_P: if (Emu.IsRunning()) Emu.Pause(); return;
|
||||
case Qt::Key_S: if (!Emu.IsStopped()) Emu.Stop(); return;
|
||||
case Qt::Key_R: if (!Emu.GetPath().empty()) { Emu.Stop(); Emu.Run(); } return;
|
||||
case Qt::Key_R: if (!Emu.GetBoot().empty()) { Emu.Stop(); Emu.Run(); } return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue