From 6c7a2cbe695ed80e30f83c1ec2a5f752c0ccabfc Mon Sep 17 00:00:00 2001 From: Achraf Reyani Date: Sun, 11 Oct 2026 20:31:39 +0900 Subject: [PATCH] feat(libkernel): export _ioctl and getsid Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libkernel/CMakeLists.txt | 9 +++++++ core/libs/prx/libkernel/File/src/Open.cpp | 9 +++++++ .../libs/prx/libkernel/System/src/Process.cpp | 6 +++++ core/libs/tests/GuestIoctlGetsid.cpp | 25 +++++++++++++++++++ docs/dev/TechnicalDebt.md | 1 + 5 files changed, 50 insertions(+) create mode 100644 core/libs/tests/GuestIoctlGetsid.cpp diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index db2752fa4..edce24d54 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -517,6 +517,15 @@ if(BUILD_TESTING) set_tests_properties(guest_signals PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_ioctl_getsid_tests ${LIBS_INCLUDE_DIR}/tests/GuestIoctlGetsid.cpp) + target_include_directories(guest_ioctl_getsid_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_ioctl_getsid_tests PRIVATE libkernel libc) + configure_windows_unwind(guest_ioctl_getsid_tests) + add_test(NAME guest_ioctl_getsid COMMAND guest_ioctl_getsid_tests) + if(WIN32) + set_tests_properties(guest_ioctl_getsid PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_test_executable(guest_sigtimedwait_tests ${LIBS_INCLUDE_DIR}/tests/GuestSigtimedwait.cpp) target_include_directories(guest_sigtimedwait_tests PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(guest_sigtimedwait_tests PRIVATE libkernel libc) diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp index 93151b4d6..2acd24e4e 100644 --- a/core/libs/prx/libkernel/File/src/Open.cpp +++ b/core/libs/prx/libkernel/File/src/Open.cpp @@ -11,6 +11,7 @@ #include "SceTypes.hpp" #include +#include #include #include #include @@ -294,4 +295,12 @@ int APS5_VABI sceKernelFcntl(int d, int command, ...) { return result < 0 ? SceKernelError(*__error_nid_postfix()) : result; } +int APS5_VABI _ioctl_nid_postfix(int d, unsigned long request, ...) { + (void)d; + char name[40]; + std::snprintf(name, sizeof(name), "_ioctl: request 0x%lx", request); + NotImplemented_nid_no_patch(name); + return -1; +} + } diff --git a/core/libs/prx/libkernel/System/src/Process.cpp b/core/libs/prx/libkernel/System/src/Process.cpp index 45528cd7a..152606d35 100644 --- a/core/libs/prx/libkernel/System/src/Process.cpp +++ b/core/libs/prx/libkernel/System/src/Process.cpp @@ -200,6 +200,12 @@ int APS5_VABI getpid_nid_postfix(void) { return static_cast(pid); } +int APS5_VABI getsid_nid_postfix(int pid) { + (void)pid; + NotImplemented_nid_no_patch("getsid: process sessions"); + return -1; +} + int APS5_VABI getppid_nid_postfix(void) { #ifdef _WIN32 const DWORD self = GetCurrentProcessId(); diff --git a/core/libs/tests/GuestIoctlGetsid.cpp b/core/libs/tests/GuestIoctlGetsid.cpp new file mode 100644 index 000000000..8a58fab3b --- /dev/null +++ b/core/libs/tests/GuestIoctlGetsid.cpp @@ -0,0 +1,25 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include +extern "C" { +int APS5_VABI _ioctl_nid_postfix(int, unsigned long, ...); +int APS5_VABI getsid_nid_postfix(int); +} +static void Require(bool value) { if (!value) std::abort(); } +template +static bool ReportsNotImplemented(Call call, const std::string& message) { + try { + call(); + } catch (const std::runtime_error& error) { + return error.what() == message; + } + return false; +} +int main() { + int value = 0; + Require(ReportsNotImplemented([&] { _ioctl_nid_postfix(0, 0x402c7413ul, &value); }, "_ioctl: request 0x402c7413 not implemented")); + Require(ReportsNotImplemented([&] { _ioctl_nid_postfix(3, 0x2000745eul); }, "_ioctl: request 0x2000745e not implemented")); + Require(ReportsNotImplemented([] { getsid_nid_postfix(0); }, "getsid: process sessions not implemented")); + Require(ReportsNotImplemented([] { getsid_nid_postfix(1); }, "getsid: process sessions not implemented")); +} diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index fee67c41b..26a9dc907 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -587,6 +587,7 @@ Throughout the project, every function at every stage either **does exactly what - [syslog](../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:] `, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER`, and errno is preserved. `openlog`, `setlogmask` and `closelog` are not implemented, so the identity, options and mask they set are not applied - [daemon](../../core/libs/prx/libc/src/Process.cpp) (libc) throws: forking into the background is not supported. PPSA85300 imports it and fails to load without it. VLC 3.0 calls it only when its `daemon` option is set ([libvlc.c](https://github.com/videolan/vlc/blob/6de05adcbaf2e8b85fe86aad4169393098628119/src/libvlc.c#L190-L197)), and the title starts libVLC with `--ignore-config` and without `--daemon` ([player.cc](https://github.com/ZiZc3/VLC/blob/f3253020a64368153233ede29183014c0b6c8979/src/player.cc#L960-L981)) - [sigtimedwait](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) throws: guest signals are delivered when raised and never left pending, so there is nothing to wait for or take. PPSA85300 imports it and fails to load without it. Its only call site is VLC's `vlc_writev` ([filesystem.c](https://github.com/videolan/vlc/blob/6de05adcbaf2e8b85fe86aad4169393098628119/src/posix/filesystem.c#L243-L278)), which polls with a zero timeout to drain a `SIGPIPE` only after `writev` fails with `EPIPE` +- [_ioctl](../../core/libs/prx/libkernel/File/src/Open.cpp) and [getsid](../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) throw, naming the ioctl request: no device control requests or process sessions are modelled. PPSA74126 imports both and fails to load without them. Its `_ioctl` call sites are the SDK libc's `termios` wrappers (`TIOCGETA`, `TIOCSETA`, `TIOCDRAIN`, `TIOCFLUSH` and the like); the title made no call to either in a 60 s run - [sigaction](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records the handler, flags and mask of every signal from 1 to 128 and reports them back, following FreeBSD's `sigaction` (`EINVAL` for other signals, and for a handler on `SIGKILL` or `SIGSTOP`); `signal` records its handler with `SA_RESTART`, as FreeBSD's libc does. Only handlers without `SA_SIGINFO` on the signals `signal` already delivers (`SIGINT`, `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM`) run, the same way `signal` handlers do; their mask and flags are not applied. `SA_SIGINFO` handlers are recorded but never called, since that needs FreeBSD's `siginfo_t` and `ucontext_t`, and neither are the handlers of other signals (`SIGBUS`, `SIGHUP`, ...), whether they are set by `sigaction` or by `signal`, which records them too (every number from 1 to 128, with `SA_RESTART` and an empty mask replacing what `sigaction` stored; `SIGKILL` and `SIGSTOP` accept only the default handler in both calls, as in FreeBSD's `kern_sigaction`). `raise` of an `SA_SIGINFO` handler on a signal `signal` delivers throws instead of terminating, and `raise` and `kill` of the other signals still fail with `EINVAL`, recorded handler or not - [kill](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) follows FreeBSD's `kern_kill` and `killpg1` for the only guest process: `EINVAL` for signals outside 0 to 128, signal 0 only checks that the target exists, and its own pid, 0 and minus its own pid (the guest is taken to lead its own process group) signal it through `raise`, so they share `raise`'s limits above. Any other pid, and -1, which skips the caller, report `ESRCH`, so `EPERM` is never reported - [sceKernelFcntl](../../core/libs/prx/libkernel/File/src/Open.cpp) (libkernel) handles socket descriptors through the POSIX `fcntl` export (`F_GETFL`, `F_SETFL` with `O_NONBLOCK`) and returns its guest errno as `SCE_KERNEL_ERROR_*`, the form the other `sceKernel` file exports use; the command semantics follow FreeBSD's [fcntl](https://github.com/freebsd/freebsd-src/blob/stable/11/sys/kern/kern_descrip.c), and a closed descriptor returns `SCE_KERNEL_ERROR_EBADF`. File descriptors throw: their open flags are not tracked, and `F_DUPFD`, `F_GETFD` and `F_SETFD` are unsupported on all descriptors. The return values and error codes are unverified on a console