// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "common/assert.h" #include "common/debug.h" #include "common/logging/log.h" #include "common/polyfill_thread.h" #include "common/thread.h" #include "common/va_ctx.h" #include "core/file_sys/fs.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/debug.h" #include "core/libraries/kernel/equeue.h" #include "core/libraries/kernel/file_system.h" #include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/orbis_error.h" #include "core/libraries/kernel/posix_error.h" #include "core/libraries/kernel/process.h" #include "core/libraries/kernel/threads.h" #include "core/libraries/kernel/threads/exception.h" #include "core/libraries/kernel/time.h" #include "core/libraries/libs.h" #include "core/libraries/network/sys_net.h" #ifdef _WIN64 #include #else #include #endif #include #include #include #include "aio.h" namespace Libraries::Kernel { static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return boost::asio::io_context io_context; static std::mutex m_asio_req; static std::condition_variable_any cv_asio_req; static std::atomic asio_requests; static std::jthread service_thread; void KernelSignalRequest() { std::unique_lock lock{m_asio_req}; ++asio_requests; cv_asio_req.notify_one(); } static void KernelServiceThread(std::stop_token stoken) { Common::SetCurrentThreadName("shadPS4:KernelServiceThread"); while (!stoken.stop_requested()) { HLE_TRACE; { std::unique_lock lock{m_asio_req}; Common::CondvarWait(cv_asio_req, lock, stoken, [] { return asio_requests != 0; }); } if (stoken.stop_requested()) { break; } io_context.run(); io_context.restart(); asio_requests = 0; } } static PS4_SYSV_ABI void stack_chk_fail() { UNREACHABLE(); } static thread_local int g_posix_errno = 0; int* PS4_SYSV_ABI __Error() { return &g_posix_errno; } void ErrSceToPosix(int error) { g_posix_errno = error - ORBIS_KERNEL_ERROR_UNKNOWN; } int ErrnoToSceKernelError(int error) { return error + ORBIS_KERNEL_ERROR_UNKNOWN; } void SetPosixErrno(int e) { // Some error numbers are different between supported OSes switch (e) { case EPERM: g_posix_errno = POSIX_EPERM; break; case ENOENT: g_posix_errno = POSIX_ENOENT; break; case EDEADLK: g_posix_errno = POSIX_EDEADLK; break; case ENOMEM: g_posix_errno = POSIX_ENOMEM; break; case EACCES: g_posix_errno = POSIX_EACCES; break; case EFAULT: g_posix_errno = POSIX_EFAULT; break; case EINVAL: g_posix_errno = POSIX_EINVAL; break; case ENOSPC: g_posix_errno = POSIX_ENOSPC; break; case ERANGE: g_posix_errno = POSIX_ERANGE; break; case EAGAIN: g_posix_errno = POSIX_EAGAIN; break; case ETIMEDOUT: g_posix_errno = POSIX_ETIMEDOUT; break; default: LOG_WARNING(Kernel, "Unhandled errno {}", e); g_posix_errno = e; } } static uint64_t g_mspace_atomic_id_mask = 0; static uint64_t g_mstate_table[64] = {0}; struct HeapInfoInfo { uint64_t size = sizeof(HeapInfoInfo); uint32_t flag; uint32_t getSegmentInfo; uint64_t* mspace_atomic_id_mask; uint64_t* mstate_table; }; void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) { info->mspace_atomic_id_mask = &g_mspace_atomic_id_mask; info->mstate_table = g_mstate_table; info->getSegmentInfo = 0; } struct OrbisKernelUuid { u32 timeLow; u16 timeMid; u16 timeHiAndVersion; u8 clockSeqHiAndReserved; u8 clockSeqLow; u8 node[6]; }; static_assert(sizeof(OrbisKernelUuid) == 0x10); int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) { if (!orbisUuid) { return ORBIS_KERNEL_ERROR_EINVAL; } #ifdef _WIN64 UUID uuid; if (UuidCreate(&uuid) != RPC_S_OK) { return ORBIS_KERNEL_ERROR_EFAULT; } #else uuid_t uuid; uuid_generate(uuid); #endif std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid)); return ORBIS_OK; } int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(fd); if (file == nullptr) { LOG_INFO(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} file == nullptr", fd, cmd); g_posix_errno = POSIX_EBADF; return -1; } if (file->type != Core::FileSys::FileType::Device) { LOG_WARNING(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} file->type != Device", fd, cmd); g_posix_errno = ENOTTY; return -1; } VA_CTX(ctx); int result = file->device->ioctl(cmd, &ctx); LOG_TRACE(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} result = {}", fd, cmd, result); if (result < 0) { ErrSceToPosix(result); return -1; } return result; } const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() { const char* path = "sys"; return path; } int PS4_SYSV_ABI _sigprocmask() { return ORBIS_OK; } int PS4_SYSV_ABI posix_getpagesize() { return 16_KB; } int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) { auto* netcall = Common::Singleton::Instance(); auto sock = netcall->FindSocket(s); if (!sock) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } int returncode = sock->GetSocketAddress(addr, paddrlen); if (returncode >= 0) { LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode); return 0; } *Libraries::Kernel::__Error() = 0x20; LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } void RegisterKernel(Core::Loader::SymbolsResolver* sym) { service_thread = std::jthread{KernelServiceThread}; Libraries::Kernel::RegisterFileSystem(sym); Libraries::Kernel::RegisterTime(sym); Libraries::Kernel::RegisterThreads(sym); Libraries::Kernel::RegisterKernelEventFlag(sym); Libraries::Kernel::RegisterMemory(sym); Libraries::Kernel::RegisterEventQueue(sym); Libraries::Kernel::RegisterProcess(sym); Libraries::Kernel::RegisterException(sym); Libraries::Kernel::RegisterAio(sym); Libraries::Kernel::RegisterDebug(sym); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord); LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error); LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, sceLibcHeapGetTraceInfo); // network LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect); LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex); LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen); LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept); LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket); LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto); LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom); LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_setsockopt); // LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname); LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ... } } // namespace Libraries::Kernel