#include "stdafx.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/lv2/sys_mutex.h" #include "Emu/Cell/lv2/sys_process.h" #include "sysPrxForUser.h" LOG_CHANNEL(sysPrxForUser); extern vm::gvar g_ppu_exit_mutex; extern vm::gvar> g_ppu_atexitspawn; extern vm::gvar> g_ppu_at_Exitspawn; static u32 get_string_array_size(vm::cpptr list, u32& out_count) { //out_count = 0; u32 result = 8; for (u32 i = 0; list; i++) { if (const vm::cptr str = list[i]) { out_count++; result += ((static_cast(std::strlen(str.get_ptr())) + 0x10) & -0x10) + 8; continue; } break; } return result; } static u32 get_exitspawn_size(vm::cptr path, vm::cpptr argv, vm::cpptr envp, u32& arg_count, u32& env_count) { arg_count = 1; env_count = 0; u32 result = ((static_cast(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 = static_cast(std::strlen(list[i].get_ptr())); std::memcpy(str.get_ptr(), list[i].get_ptr(), len + 1); pstr[i] = str; str += (len + 0x10) & -0x10; } pstr[count] = vm::null; } 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; const u32 len = static_cast(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) { 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); } alloc_size += 0x30; if (data_size > 0) { alloc_size += 0x1030; } 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(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); } error_code sys_game_board_storage_read() { sysPrxForUser.todo("sys_game_board_storage_read()"); return CELL_OK; } error_code sys_game_board_storage_write() { sysPrxForUser.todo("sys_game_board_storage_write()"); return CELL_OK; } error_code sys_game_get_rtc_status() { sysPrxForUser.todo("sys_game_get_rtc_status()"); return CELL_OK; } error_code sys_game_get_system_sw_version() { sysPrxForUser.todo("sys_game_get_system_sw_version()"); return CELL_OK; } error_code sys_game_get_temperature() { sysPrxForUser.todo("sys_game_get_temperature()"); return CELL_OK; } error_code sys_game_watchdog_clear() { sysPrxForUser.todo("sys_game_watchdog_clear()"); return CELL_OK; } error_code sys_game_watchdog_start() { sysPrxForUser.todo("sys_game_watchdog_start()"); return CELL_OK; } error_code sys_game_watchdog_stop() { sysPrxForUser.todo("sys_game_watchdog_stop()"); return CELL_OK; } void sysPrxForUser_sys_game_init() { REG_FUNC(sysPrxForUser, sys_game_process_exitspawn2); REG_FUNC(sysPrxForUser, sys_game_process_exitspawn); REG_FUNC(sysPrxForUser, sys_game_board_storage_read); REG_FUNC(sysPrxForUser, sys_game_board_storage_write); REG_FUNC(sysPrxForUser, sys_game_get_rtc_status); REG_FUNC(sysPrxForUser, sys_game_get_system_sw_version); REG_FUNC(sysPrxForUser, sys_game_get_temperature); REG_FUNC(sysPrxForUser, sys_game_watchdog_clear); REG_FUNC(sysPrxForUser, sys_game_watchdog_start); REG_FUNC(sysPrxForUser, sys_game_watchdog_stop); }