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:
Nekotekina 2017-09-18 19:16:36 +03:00
parent 18d472b7e1
commit 519f21db18
15 changed files with 285 additions and 198 deletions

View File

@ -179,31 +179,29 @@ s32 sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain)
return CELL_OK; 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)", 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);
klicensee, path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
if (s32 error = npDrmIsAvailable(klicensee, path)) if (s32 error = npDrmIsAvailable(klicensee, path))
{ {
return error; 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; 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)", 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);
klicensee, path, argv_addr, envp_addr, data_addr, data_size, prio, flags);
if (s32 error = npDrmIsAvailable(klicensee, path)) if (s32 error = npDrmIsAvailable(klicensee, path))
{ {
return error; 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; return CELL_OK;
} }

View File

@ -2,6 +2,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPUModule.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_interrupt.h"
#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_process.h"
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
@ -13,6 +14,9 @@ extern u64 get_system_time();
extern fs::file g_tty; extern fs::file g_tty;
vm::gvar<s32> sys_prx_version; // ??? 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() s64 sys_time_get_system_time()
{ {
@ -21,33 +25,34 @@ s64 sys_time_get_system_time()
return 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); 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"); *g_ppu_atexitspawn = func;
Emu.Stop(); }
});
thread_ctrl::eternalize();
return CELL_OK;
} }
s64 _sys_process_atexitspawn() void _sys_process_at_Exitspawn(vm::ptr<void()> func)
{ {
sysPrxForUser.todo("_sys_process_atexitspawn()"); sysPrxForUser.warning("_sys_process_at_Exitspawn(0x%x)", func);
return CELL_OK;
}
s64 _sys_process_at_Exitspawn() if (!*g_ppu_at_Exitspawn)
{ {
sysPrxForUser.todo("_sys_process_at_Exitspawn"); *g_ppu_at_Exitspawn = func;
return CELL_OK; }
} }
s32 sys_process_is_stack(u32 p) s32 sys_process_is_stack(u32 p)
@ -244,6 +249,8 @@ DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []()
sysPrxForUser_sys_rsxaudio_init(); sysPrxForUser_sys_rsxaudio_init();
REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf 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); REG_FUNC(sysPrxForUser, sys_time_get_system_time);

View File

@ -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); 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_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_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(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(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);

View File

@ -2,148 +2,153 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_mutex.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
extern logs::channel sysPrxForUser; 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(); //out_count = 0;
const std::string& from = "//"; u32 result = 8;
const std::string& to = "/";
size_t start_pos = 0; for (u32 i = 0; list; i++)
while ((start_pos = _path.find(from, start_pos)) != std::string::npos) { {
_path.replace(start_pos, from.length(), to); if (const vm::cptr<char> str = list[i])
start_pos += to.length(); {
out_count++;
result += (((u32)std::strlen(str.get_ptr()) + 0x10) & -0x10) + 8;
continue;
}
break;
} }
sysPrxForUser.todo("sys_game_process_exitspawn()"); return result;
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);
});
} }
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(); arg_count = 1;
const std::string& from = "//"; env_count = 0;
const std::string& to = "/";
size_t start_pos = 0; u32 result = (((u32)std::strlen(path.get_ptr()) + 0x10) & -0x10) + 8;
while ((start_pos = _path.find(from, start_pos)) != std::string::npos) { result += get_string_array_size(argv, arg_count);
_path.replace(start_pos, from.length(), to); result += get_string_array_size(envp, env_count);
start_pos += to.length();
if ((arg_count + env_count) % 2)
{
result += 8;
} }
sysPrxForUser.warning("sys_game_process_exitspawn2()"); return result;
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; static void put_string_array(vm::pptr<char, u32, u64> pstr, vm::ptr<char>& str, u32 count, vm::cpptr<char> list)
std::vector<std::string> env; {
for (u32 i = 0; i < count; i++)
if (argv_addr)
{ {
auto argvp = vm::cpptr<char>::make(argv_addr); const u32 len = (u32)std::strlen(list[i].get_ptr());
while (argvp && *argvp) std::memcpy(str.get_ptr(), list[i].get_ptr(), len + 1);
{ pstr[i] = str;
argv.push_back(argvp[0].get_ptr()); str += (len + 0x10) & -0x10;
argvp++;
}
for (auto &arg : argv)
{
sysPrxForUser.trace("argument: %s", arg.c_str());
}
} }
if (envp_addr) pstr[count] = vm::null;
{ }
auto envp = vm::cpptr<char>::make(envp_addr);
while (envp && *envp)
{
env.push_back(envp[0].get_ptr());
envp++;
}
for (auto &en : 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)
{ {
sysPrxForUser.trace("env_argument: %s", en.c_str()); 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;
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)
{
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);
} }
// TODO: execute the file in <path> with the args in argv alloc_size += 0x30;
// 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(); if (data_size > 0)
sysPrxForUser.success("Process finished");
Emu.CallAfter([=, path = vfs::get(_path)]()
{ {
Emu.Stop(); alloc_size += 0x1030;
Emu.BootGame(path, true); }
});
return; u32 alloc_addr = vm::alloc(alloc_size, vm::main);
if (!alloc_addr)
{
// TODO (process atexit)
return _sys_process_exit(ppu, CELL_ENOMEM, 0, 0);
}
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() s32 sys_game_board_storage_read()

View File

@ -13,6 +13,7 @@ extern logs::channel sysPrxForUser;
vm::gvar<sys_lwmutex_t> g_ppu_atexit_lwm; vm::gvar<sys_lwmutex_t> g_ppu_atexit_lwm;
vm::gvar<vm::ptr<void()>[8]> g_ppu_atexit; 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<u32> g_ppu_once_mutex;
vm::gvar<sys_lwmutex_t> g_ppu_prx_lwm; 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; attr->name_u64 = "_lv2ppu\0"_u64;
sys_mutex_create(g_ppu_once_mutex, attr); 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->protocol = SYS_SYNC_PRIORITY;
lwa->recursive = SYS_SYNC_RECURSIVE; lwa->recursive = SYS_SYNC_RECURSIVE;
lwa->name_u64 = "_lv2prx\0"_u64; 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_once_mutex).flag(MFF_HIDDEN);
REG_VAR(sysPrxForUser, g_ppu_atexit).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_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_initialize_tls).args = {"main_thread_id", "tls_seg_addr", "tls_seg_size", "tls_mem_size"}; // Test
REG_FUNC(sysPrxForUser, sys_ppu_thread_create); REG_FUNC(sysPrxForUser, sys_ppu_thread_create);

View File

@ -1360,7 +1360,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Set path (TODO) // Set path (TODO)
_main->name = ""; _main->name = "";
_main->path = vfs::get(Emu.GetPath()); _main->path = vfs::get(Emu.argv[0]);
// Analyse executable (TODO) // Analyse executable (TODO)
_main->analyse(0, static_cast<u32>(elf.header.e_entry)); _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; g_ps3_sdk_version = sdk_version;
// Initialize process arguments // 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)); for (const auto& arg : Emu.argv)
auto envp = vm::ptr<u64>::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main));
*envp = 0;
for (const auto& arg : args)
{ {
const u32 arg_size = ::align(::size32(arg) + 1, 0x10); const u32 arg_size = ::align(::size32(arg) + 1, 0x10);
const u32 arg_addr = vm::alloc(arg_size, vm::main); const u32 arg_addr = vm::alloc(arg_size, vm::main);
std::memcpy(vm::base(arg_addr), arg.data(), arg_size); 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 // Initialize main thread
auto ppu = idm::make_ptr<ppu_thread>("main_thread", primary_prio, primary_stacksize); 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}); ppu->cmd_push({ppu_cmd::initialize, 0});
// TODO: adjust for liblv2 loading option // 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 // Set command line arguments, run entry function
ppu->cmd_list 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, 11 }, u64{elf.header.e_entry},
{ ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize}, { ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize},
{ ppu_cmd::lle_call, entry }, { ppu_cmd::lle_call, entry },

View File

@ -233,7 +233,7 @@ s32 sys_process_detach_child(u64 unk)
return CELL_OK; 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); vm::temporary_unlock(ppu);
@ -248,7 +248,60 @@ s32 _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3)
thread_ctrl::eternalize(); 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();
} }

View File

@ -23,6 +23,16 @@ enum : u32
SYS_EVENT_FLAG_OBJECT = 0x98, 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 // Auxiliary functions
s32 process_getpid(); s32 process_getpid();
s32 process_get_sdk_version(u32 pid, s32& ver); 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_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_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_detach_child(u64 unk);
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);
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::ps3::ptr<sys_exit2_param> arg, u32 arg_size, u32 arg4);

View File

@ -587,7 +587,7 @@ void arm_load_exec(const arm_exec_object& elf)
// Initialize args // Initialize args
std::vector<char> argv_data; 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(), arg.begin(), arg.end());
argv_data.insert(argv_data.end(), '\0'); argv_data.insert(argv_data.end(), '\0');

View File

@ -228,12 +228,6 @@ void Emulator::Init()
fxm::make_always<patch_engine>()->append(fs::get_config_dir() + "/patch.yml"); 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) bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
{ {
static const char* boot_list[] = 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)) if (direct && fs::is_file(path))
{ {
SetPath(path); m_path = path;
Load(add_only); Load(add_only);
return true; return true;
@ -258,7 +252,7 @@ bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
if (fs::is_file(elf)) if (fs::is_file(elf))
{ {
SetPath(elf); m_path = elf;
Load(add_only); Load(add_only);
return true; 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)) 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); 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 else
{ {
@ -460,7 +454,7 @@ void Emulator::Load(bool add_only)
{ {
// Booting game update // Booting game update
LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id); 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 // Mount /host_root/ if necessary
@ -528,25 +522,25 @@ void Emulator::Load(bool add_only)
vm::ps3::init(); vm::ps3::init();
if (m_elf_path.empty()) if (argv.empty())
{ {
if (m_path.find(hdd0_game) != -1) 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)) else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{ {
//Disc games are on /dev_bdvd/ // Disc games are on /dev_bdvd/
size_t pos = m_path.rfind("PS3_GAME"); const std::size_t pos = m_path.rfind("PS3_GAME");
m_elf_path = "/dev_bdvd/" + m_path.substr(pos); argv.emplace_back("/dev_bdvd/" + m_path.substr(pos));
} }
else else
{ {
//For homebrew // For homebrew
m_elf_path = "/host_root/" + m_path; 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); ppu_load_exec(ppu_exec);
@ -579,10 +573,10 @@ void Emulator::Load(bool add_only)
GetCallbacks().on_ready(); GetCallbacks().on_ready();
vm::psv::init(); vm::psv::init();
if (m_elf_path.empty()) if (argv.empty())
{ {
m_elf_path = "host_root:" + m_path; argv.emplace_back("host_root:" + m_path);
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); LOG_NOTICE(LOADER, "Elf path: %s", argv[0]);
} }
arm_load_exec(arm_exec); arm_load_exec(arm_exec);
@ -794,6 +788,10 @@ void Emulator::Stop()
extern void jit_finalize(); extern void jit_finalize();
jit_finalize(); jit_finalize();
#endif #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) s32 error_code::error_report(const fmt_type_info* sup, u64 arg, const fmt_type_info* sup2, u64 arg2)

View File

@ -177,7 +177,6 @@ class Emulator final
atomic_t<u64> m_pause_amend_time; // increased when resumed atomic_t<u64> m_pause_amend_time; // increased when resumed
std::string m_path; std::string m_path;
std::string m_elf_path;
std::string m_cache_path; std::string m_cache_path;
std::string m_title_id; std::string m_title_id;
std::string m_title; std::string m_title;
@ -210,12 +209,10 @@ public:
} }
void Init(); void Init();
void SetPath(const std::string& path, const std::string& elf_path = {});
const std::string& GetPath() const std::vector<std::string> argv;
{ std::vector<std::string> envp;
return m_elf_path; std::vector<u8> data;
}
const std::string& GetBoot() const const std::string& GetBoot() const
{ {

View File

@ -60,8 +60,7 @@ int main(int argc, char** argv)
// Ugly workaround // Ugly workaround
QTimer::singleShot(2, [path = sstr(QFileInfo(parser.positionalArguments().at(0)).canonicalFilePath())] QTimer::singleShot(2, [path = sstr(QFileInfo(parser.positionalArguments().at(0)).canonicalFilePath())]
{ {
Emu.SetPath(path); Emu.BootGame(path, true);
Emu.Load();
Emu.Run(); Emu.Run();
}); });
} }

View File

@ -140,8 +140,7 @@ UTILS_DLL_C_EXPORT ps3emu_api_error_code ps3emu_api_load_elf(const char *path)
return ps3emu_api_not_found; return ps3emu_api_not_found;
} }
Emu.SetPath(path); Emu.BootGame(path, true);
Emu.Load();
return ps3emu_api_ok; return ps3emu_api_ok;
} }

View File

@ -84,7 +84,7 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.IsStopped())) { Emu.Stop(); return; } if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.IsStopped())) { Emu.Stop(); return; }
break; break;
case Qt::Key_R: 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; break;
case Qt::Key_E: case Qt::Key_E:
if (keyEvent->modifiers() == Qt::ControlModifier) if (keyEvent->modifiers() == Qt::ControlModifier)

View File

@ -61,7 +61,7 @@ auto Pause = []()
if (Emu.IsReady()) Emu.Run(); if (Emu.IsReady()) Emu.Run();
else if (Emu.IsPaused()) Emu.Resume(); else if (Emu.IsPaused()) Emu.Resume();
else if (Emu.IsRunning()) Emu.Pause(); 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). /* 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); 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); ui->toolbar_start->setIcon(m_icon_restart);
} }
@ -817,7 +817,7 @@ void main_window::OnEmuStop()
m_thumb_playPause->setIcon(m_icon_thumb_play); m_thumb_playPause->setIcon(m_icon_thumb_play);
#endif #endif
EnableMenus(false); EnableMenus(false);
if (!Emu.GetPath().empty()) if (!Emu.GetBoot().empty())
{ {
ui->toolbar_start->setEnabled(true); ui->toolbar_start->setEnabled(true);
ui->toolbar_start->setIcon(m_icon_restart); 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_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_P: if (Emu.IsRunning()) Emu.Pause(); return;
case Qt::Key_S: if (!Emu.IsStopped()) Emu.Stop(); 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;
} }
} }
} }