// Vita3K emulator project // Copyright (C) 2025 Vita3K team // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "SceProcessmgr.h" #include #include #include #include #include TRACY_MODULE_NAME(SceProcessmgr); template <> std::string to_debug_str(const MemState &mem, SceKernelPowerTickType type) { switch (type) { case SCE_KERNEL_POWER_TICK_DEFAULT: return "SCE_KERNEL_POWER_TICK_DEFAULT"; case SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND: return "SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND"; case SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF: return "SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF"; case SCE_KERNEL_POWER_TICK_DISABLE_OLED_DIMMING: return "SCE_KERNEL_POWER_TICK_DISABLE_OLED_DIMMING"; } return std::to_string(type); } struct VitaTimeval { uint32_t tv_sec; uint32_t tv_usec; }; struct VitaTimezone { int tz_minuteswest; int tz_dsttime; }; using VitaTime = uint32_t; struct VitaTM { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; static_assert(sizeof(VitaTM) == 36); static_assert(sizeof(VitaTM) <= sizeof(struct tm)); struct SceLibkernelAddresses { uint32_t size; Ptr sceKernelExitThread; Ptr sceKernelExitDeleteThread; Ptr _sceKernelExitCallback; Ptr field_0x10; Ptr field_0x14; Ptr field_0x18; }; EXPORT(int, _sceKernelExitProcessForUser) { TRACY_FUNC(_sceKernelExitProcessForUser); return UNIMPLEMENTED(); } EXPORT(int, _sceKernelGetTimer5Reg, Ptr *timer) { TRACY_FUNC(_sceKernelGetTimer5Reg, timer); *timer = alloc(emuenv.mem, "timer5reg"); *(*timer).get(emuenv.mem) = rtc_get_ticks(emuenv.kernel.base_tick.tick); return SCE_KERNEL_OK; } EXPORT(int, _sceKernelRegisterLibkernelAddresses, SceLibkernelAddresses *addresses) { TRACY_FUNC(_sceKernelRegisterLibkernelAddresses, addresses); return UNIMPLEMENTED(); } EXPORT(int, sceKernelCDialogSessionClose) { TRACY_FUNC(sceKernelCDialogSessionClose); return UNIMPLEMENTED(); } EXPORT(int, sceKernelCDialogSetLeaseLimit) { TRACY_FUNC(sceKernelCDialogSetLeaseLimit); return UNIMPLEMENTED(); } EXPORT(int, sceKernelCallAbortHandler, uint32_t param1, uint32_t param2) { TRACY_FUNC(sceKernelCallAbortHandler, param1, param2); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetCurrentProcess) { TRACY_FUNC(sceKernelGetCurrentProcess); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetExtraTty) { TRACY_FUNC(sceKernelGetExtraTty); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetProcessName, char *process_name, uint32_t len) { TRACY_FUNC(sceKernelGetProcessName, process_name, len); if (!process_name || len > 32 || len == 0) return RET_ERROR(SCE_KERNEL_ERROR_INVALID_ARGUMENT); strncpy(process_name, emuenv.kernel.process_param.get(emuenv.mem)->process_name.get(emuenv.mem), len); return 0; } EXPORT(Ptr, sceKernelGetProcessParam, void *args) { TRACY_FUNC(sceKernelGetProcessParam, args); return emuenv.kernel.process_param; } EXPORT(int, sceKernelGetProcessTimeCore) { TRACY_FUNC(sceKernelGetProcessTimeCore); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetProcessTimeLowCore) { TRACY_FUNC(sceKernelGetProcessTimeLowCore); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetProcessTimeWideCore) { TRACY_FUNC(sceKernelGetProcessTimeWideCore); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetProcessTitleId, char *title_id, uint32_t len) { TRACY_FUNC(sceKernelGetProcessTitleId, title_id, len); if (!title_id || len > 32 || len == 0) return RET_ERROR(SCE_KERNEL_ERROR_INVALID_ARGUMENT); strncpy(title_id, emuenv.io.title_id.c_str(), len); return 0; } EXPORT(int, sceKernelGetRemoteProcessTime) { TRACY_FUNC(sceKernelGetRemoteProcessTime); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetStderr) { TRACY_FUNC(sceKernelGetStderr); return open_file(emuenv.io, "tty0:", SCE_O_WRONLY, emuenv.pref_path, export_name); } EXPORT(int, sceKernelGetStdin) { TRACY_FUNC(sceKernelGetStdin); return open_file(emuenv.io, "tty0:", SCE_O_RDONLY, emuenv.pref_path, export_name); } EXPORT(int, sceKernelGetStdout) { TRACY_FUNC(sceKernelGetStdout); return open_file(emuenv.io, "tty0:", SCE_O_WRONLY, emuenv.pref_path, export_name); } EXPORT(int, sceKernelIsCDialogAvailable) { TRACY_FUNC(sceKernelIsCDialogAvailable); return UNIMPLEMENTED(); } EXPORT(int, sceKernelIsGameBudget) { TRACY_FUNC(sceKernelIsGameBudget); return UNIMPLEMENTED(); } EXPORT(VitaTime, sceKernelLibcClock) { TRACY_FUNC(sceKernelLibcClock); return static_cast(rtc_get_ticks(emuenv.kernel.base_tick.tick) - emuenv.kernel.start_tick); } EXPORT(int, sceKernelLibcGettimeofday, VitaTimeval *timeAddr, VitaTimezone *tzAddr) { TRACY_FUNC(sceKernelLibcGettimeofday, timeAddr, tzAddr); const auto ticks = rtc_get_ticks(emuenv.kernel.base_tick.tick) - RTC_OFFSET; if (timeAddr != nullptr) { timeAddr->tv_sec = static_cast(ticks / VITA_CLOCKS_PER_SEC); timeAddr->tv_usec = ticks % VITA_CLOCKS_PER_SEC; } if (tzAddr != nullptr) { std::time_t t = std::time(nullptr); tm localtime_tm = {}; SAFE_LOCALTIME(&t, &localtime_tm); std::time_t lt = mktime(&localtime_tm); tzAddr->tz_minuteswest = static_cast((lt - t) / 60); } return 0; } EXPORT(Ptr, sceKernelLibcGmtime_r, const VitaTime *time, Ptr date) { TRACY_FUNC(sceKernelLibcGmtime_r, time, date); const time_t plat_time = *time; auto dateIn = date.get(emuenv.mem); tm host_tm = {}; SAFE_GMTIME(&plat_time, &host_tm); memcpy(dateIn, &host_tm, sizeof(VitaTM)); return date; } EXPORT(Ptr, sceKernelLibcLocaltime_r, const VitaTime *time, Ptr date) { TRACY_FUNC(sceKernelLibcLocaltime_r, time, date); const time_t plat_time = *time; auto dateIn = date.get(emuenv.mem); tm host_tm = {}; SAFE_LOCALTIME(&plat_time, &host_tm); memcpy(dateIn, &host_tm, sizeof(VitaTM)); return date; } EXPORT(int, sceKernelLibcMktime, VitaTM *date, VitaTime *time, uint64_t *param_3) { TRACY_FUNC(sceKernelLibcMktime, date, time); // param_3 - result, 8 bytes, unused if (!date) { return RET_ERROR(SCE_KERNEL_ERROR_INVALID_ARGUMENT); } bool year_1900 = false; if (date->tm_year >= 1900) { date->tm_year -= 1900; year_1900 = true; } tm host_tm = {}; // Copy the input date to host_tm and use that on mktime instead of the input directly // to avoid stack corruption on systems where tm size is different memcpy(&host_tm, date, sizeof(VitaTM)); auto time_local = mktime(&host_tm); memcpy(date, &host_tm, sizeof(VitaTM)); if (year_1900) { date->tm_year += 1900; } if (time) *time = static_cast(time_local); if (param_3) *param_3 = time_local; return 0; } EXPORT(VitaTime, sceKernelLibcTime, VitaTime *time) { TRACY_FUNC(sceKernelLibcTime, time); const auto secs = (rtc_get_ticks(emuenv.kernel.base_tick.tick) - RTC_OFFSET) / VITA_CLOCKS_PER_SEC; if (time) { *time = static_cast(secs); } return static_cast(secs); } EXPORT(int, sceKernelPowerLock) { TRACY_FUNC(sceKernelPowerLock); return UNIMPLEMENTED(); } EXPORT(int, sceKernelPowerTick, SceKernelPowerTickType type) { TRACY_FUNC(sceKernelPowerTick, type); return SCE_KERNEL_OK; } EXPORT(int, sceKernelPowerUnlock) { TRACY_FUNC(sceKernelPowerUnlock); return UNIMPLEMENTED(); } EXPORT(int, sceKernelRegisterProcessTerminationCallback) { TRACY_FUNC(sceKernelRegisterProcessTerminationCallback); return UNIMPLEMENTED(); } EXPORT(int, sceKernelUnregisterProcessTerminationCallback) { TRACY_FUNC(sceKernelUnregisterProcessTerminationCallback); return UNIMPLEMENTED(); } EXPORT(int, sceKernelGetMainModuleSdkVersion) { TRACY_FUNC(sceKernelGetMainModuleSdkVersion); SceProcessParam *process_param = emuenv.kernel.process_param.get(emuenv.mem); if (process_param && (process_param->magic == '2PSP') && (process_param->version != 0)) { return process_param->fw_version; } else { return 0; } }