diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp index 3d4180bc0e..280473adb9 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -179,31 +179,29 @@ s32 sceNpDrmGetTimelimit(vm::cptr path, vm::ptr time_remain) return CELL_OK; } -s32 sceNpDrmProcessExitSpawn(vm::cptr klicensee, vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) +s32 sceNpDrmProcessExitSpawn(ppu_thread& ppu, vm::cptr klicensee, vm::cptr path, vm::cpptr argv, vm::cpptr 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 klicensee, vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) +s32 sceNpDrmProcessExitSpawn2(ppu_thread& ppu, vm::cptr klicensee, vm::cptr path, vm::cpptr argv, vm::cpptr 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; } diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index 9384bd9e96..15424290ae 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -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 sys_prx_version; // ??? +vm::gvar> g_ppu_atexitspawn; +vm::gvar> g_ppu_at_Exitspawn; +extern vm::gvar 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 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 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); diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h index b6345be9e3..18cbe33375 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h @@ -53,5 +53,5 @@ error_code sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr lwcond, u error_code sys_lwcond_wait(ppu_thread& CPU, vm::ptr lwcond, u64 timeout); void sys_ppu_thread_exit(ppu_thread& CPU, u64 val); -void sys_game_process_exitspawn(vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags); -void sys_game_process_exitspawn2(vm::cptr 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 path, vm::cpptr argv, vm::cpptr envp, u32 data, u32 data_size, s32 prio, u64 flags); +void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr path, vm::cpptr argv, vm::cpptr envp, u32 data, u32 data_size, s32 prio, u64 flags); diff --git a/rpcs3/Emu/Cell/Modules/sys_game.cpp b/rpcs3/Emu/Cell/Modules/sys_game.cpp index 87c2047988..76f41e3e05 100644 --- a/rpcs3/Emu/Cell/Modules/sys_game.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_game.cpp @@ -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 g_ppu_exit_mutex; +extern vm::gvar> g_ppu_atexitspawn; +extern vm::gvar> g_ppu_at_Exitspawn; -void sys_game_process_exitspawn(vm::cptr 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 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 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 argv; - std::vector env; - - if (argv_addr) - { - auto argvp = vm::cpptr::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::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 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 path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) +static u32 get_exitspawn_size(vm::cptr path, vm::cpptr argv, vm::cpptr 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 pstr, vm::ptr& str, u32 count, vm::cpptr 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 argv; - std::vector env; +static void put_exitspawn(vm::ptr out, vm::cptr path, u32 argc, vm::cpptr argv, u32 envc, vm::cpptr envp) +{ + vm::pptr pstr = vm::cast(out.addr()); + vm::ptr str = vm::static_ptr_cast(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 path, vm::cpptr argv, vm::cpptr 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::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::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 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(data_size, 0x1000)); + } + + vm::ptr 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 path, vm::cpptr argv, vm::cpptr 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 path, vm::cpptr argv, vm::cpptr 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() diff --git a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index a27544bd08..8e0fb24b81 100644 --- a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -13,6 +13,7 @@ extern logs::channel sysPrxForUser; vm::gvar g_ppu_atexit_lwm; vm::gvar[8]> g_ppu_atexit; +vm::gvar g_ppu_exit_mutex; // sys_process_exit2 mutex vm::gvar g_ppu_once_mutex; vm::gvar 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); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 234cc2b635..4ed70a340f 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -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(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 args = { Emu.GetPath()/*, "-emu"s*/ }; + auto args = vm::ptr::make(vm::alloc(SIZE_32(u64) * (::size32(Emu.argv) + ::size32(Emu.envp) + 2), vm::main)); + auto argv = args; - auto argv = vm::ptr::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main)); - auto envp = vm::ptr::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("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 }, diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 8f069c391e..bfdeaebc82 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -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 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 argv; + std::vector 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 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(); } diff --git a/rpcs3/Emu/Cell/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h index 1b38637157..e38b804680 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.h +++ b/rpcs3/Emu/Cell/lv2/sys_process.h @@ -23,6 +23,16 @@ enum : u32 SYS_EVENT_FLAG_OBJECT = 0x98, }; +struct sys_exit2_param +{ + be_t x0; // 0x85 + be_t this_size; // 0x30 + be_t next_size; + be_t prio; + be_t flags; + vm::ps3::bpptr 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 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 arg, u32 arg_size, u32 arg4); diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index 29efeb07ea..37de3862e3 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -587,7 +587,7 @@ void arm_load_exec(const arm_exec_object& elf) // Initialize args std::vector 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'); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b0d5df24b7..ea0f7beaeb 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -228,12 +228,6 @@ void Emulator::Init() fxm::make_always()->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) diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index be23267557..b1c86f66d8 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -177,7 +177,6 @@ class Emulator final atomic_t 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 argv; + std::vector envp; + std::vector data; const std::string& GetBoot() const { diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index 55b4a904f0..cd51970606 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -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(); }); } diff --git a/rpcs3/rpcs3_api.cpp b/rpcs3/rpcs3_api.cpp index 499431b83b..71e3aff589 100644 --- a/rpcs3/rpcs3_api.cpp +++ b/rpcs3/rpcs3_api.cpp @@ -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; } diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index 5f5a71ae44..7bb658cf92 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -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) diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 6bcc157262..8b3b410249 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -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; } } }