Files
AnyPS5/docs/dev/debt/libkernel_sys.md
T
2026-10-27 10:29:18 +13:00

21 KiB

libkernel_sys technical debt

Silent stubs

  • fchmodat (libkernel_sys) - AT_SYMLINK_NOFOLLOW on a symbolic link (on Windows and Linux)

Unknown function info

  • sceKernelGetCompiledSdkVersion (libkernel_sys) - which SDK version the console returns is unmeasured. The PS5 payload SDK declares the process parameters with a 32-bit PS4 SDK version at offset 0x10 and a 32-bit PS5 SDK version at 0x14; this export returns the field at 0x10, the one libSceHmd2 reads and the one shadPS4 (PS4, a single 64-bit sdk_version there) reads from the eboot. The int (int32_t*) signature and EINVAL (0x80020016) for a null output follow shadPS4. Closes when: measured on a PS5
  • scePthreadCondattrGetclock (libkernel_sys) - the int (const PthreadCondattr*, KernelClockid*) signature and checks follow FreeBSD 11.4 libthr's _pthread_condattr_getclock with the error code of libkernel's scePthreadCondattrSetclock: a null or destroyed attribute returns SCE_KERNEL_ERROR_EINVAL, and a null clock pointer throws, since libthr writes through it unchecked. Console behaviour is unverified

Functional

  • sched_rr_get_interval (libkernel_sys) accepts pid 0 or the host-backed guest pid and reports the FreeBSD 11 ULE default time slice for the usual AMD64 clock rates (94 ms); other pids return ESRCH, and a null interval returns EFAULT. AnyPS5 does not run a guest ULE scheduler or track a per-process configured quantum, so this reports the modeled default and does not reflect runtime scheduling. Console-specific clock rates and quantum configuration are unverified
  • fchdir (libkernel_sys) changes the guest working directory to the descriptor's directory: on Windows through the path recorded when the descriptor was opened, on Linux through the /proc/self/fd link target. It returns EBADF for a descriptor that is not open, EINVAL for a pipe or socket, as FreeBSD getvnode does for a descriptor without a vnode, and ENOTDIR for any other descriptor that is not a directory. Outside Windows it checks search permission on the directory with faccessat, which fails with EACCES as FreeBSD change_dir does; on Windows that check is not modelled. A directory renamed after it was opened is still reached through the recorded path. Console behaviour is unverified
  • openat, _openat (libkernel_sys) pass AT_FDCWD (-100) and absolute paths to open. Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. They return EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. As with open, O_NONBLOCK is ignored. PPSA99003 opens directory entries through openat. Console behaviour is unverified
  • fchmodat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to chmod; any other relative path is joined to the descriptor's host directory the same way as for openat, so guest path aliases and case-insensitive name matching do not apply to it and a .. component is not kept inside the guest root. A flag other than 0 or AT_SYMLINK_NOFOLLOW (0x200) returns EINVAL; the mode is masked to 07777. With AT_SYMLINK_NOFOLLOW a symbolic link returns success silently on Windows and Linux, since the host cannot change a link's own mode, while a regular file is changed either way. The mode maps to the host file mode, which on Windows is only the CRT's read-only bit. PPSA99621 calls it through std::filesystem::permissions. Console behaviour is unverified
  • lchmod (libkernel_sys) throws for a symbolic link on Windows and Linux, whose hosts cannot change a link's own mode; on macOS the link's mode is changed. Anything else goes to fchmodat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW), as FreeBSD 11.4's sys_lchmod does, so a file or directory is changed as by chmod, with fchmodat's path lookup and Windows mode mapping. On Windows any reparse point counts as a link. Console behaviour is unverified
  • pathconf, fpathconf, _fpathconf (libkernel_sys) answer every file and directory as the console's UFS mount /system_data does in a payload process on a PS5 (firmware 13.60). Other mounts differ: /data and /user give _PC_LINK_MAX 1, _PC_SYMLINK_MAX 0, _PC_NO_TRUNC EINVAL and 255 for _PC_MAX_CANON, _PC_MAX_INPUT and _PC_VDISABLE; /, /system, /hostapp and /update answer only four names; tmpfs gives _PC_FILESIZEBITS 0 and _PC_SYNC_IO 1. What a title sees under /app0, /savedata0, /temp0 and /download0 is not known. fpathconf and _fpathconf answer _PC_ASYNC_IO 200112 and, for a pipe, only _PC_PIPE_BUF 512, as FreeBSD 11's kern_fpathconf does; a guest socket fails fstat with EBADF
  • mkdirat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to mkdir. Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. On Windows, mode is ignored. Console behaviour is unverified
  • readlink (libkernel_sys) on Windows reads a symbolic link's target from its reparse data and returns it with / separators, only when the target is relative, as symlink creates them. A symbolic link with an absolute target returns its print name, or its substitute name when the print name is empty, without a \??\ or \\?\ prefix. A directory junction returns the same kind of name when it is a drive path (X:\...), using the print name when that is a drive path and the substitute name otherwise. A mounted volume (\??\Volume{GUID}\), any other name surrogate and every reparse point without the name surrogate bit (WOF compression, deduplication, cloud files) return EINVAL, as FreeBSD does for a file that is not a link and as CPython's os.readlink, which reads only symbolic links and junctions, does
  • aio_read, aio_write, aio_fsync, aio_error, aio_return, aio_suspend, aio_waitcomplete, aio_cancel (libkernel_sys) - a request with SIGEV_SIGNAL, SIGEV_THREAD_ID or SIGEV_KEVENT completion, or on a socket, throws, because delivering a guest signal or kevent and socket aio are not modelled. One worker thread runs the process's requests one at a time in submission order, so a request is cancellable only until that thread takes it. A queued request keeps the descriptor number, not the open file: closing or reusing the descriptor before it runs changes what it reaches. Pipes fail with EOPNOTSUPP, as FreeBSD 11 does with vfs.aio.enable_unsafe 0; the console's setting is unverified. Waits are not interrupted by signals (EINTR), and timeouts under 1 ms round up to 1 ms (hz 1000). Otherwise the rules follow FreeBSD 11 vfs_aio.c
  • readlinkat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to readlink. Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. Console behaviour is unverified
  • link (libkernel_sys) on Windows resolves a symbolic link source through the host, which follows longer chains than FreeBSD: a chain of 40 links is linked, where FreeBSD 11.4 returns ELOOP after 32 (MAXSYMLINKS). A loop returns ELOOP as on FreeBSD
  • pthread_attr_setcreatesuspend_np, pthread_resume_np, pthread_resume_all_np, pthread_multi_np, scePthreadAttrSetcreatesuspend, scePthreadResume, scePthreadResumeAll and scePthreadMulti (libkernel_sys) - when a thread created suspended stops relative to its signal mask is unmeasured on a console. Return values and errors follow FreeBSD 11.4 libthr (thr_attr.c, thr_resume_np.c, thr_multi_np.c) and the code of firmware 13.42's libkernel_sys.sprx (#9573), where the sce forms add 0x80020000 to a non-zero errno
  • fstatat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to stat, or to lstat with AT_SYMLINK_NOFOLLOW (0x200). Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory, and flags other than AT_SYMLINK_NOFOLLOW return EINVAL. PPSA74126 imports it. Console behaviour is unverified
  • uuidgen (libkernel_sys) - the node is 48 random bits with the multicast bit set, chosen once per process, where the console's kernel uses the address of its first Ethernet interface; that the PS5 kernel registers one is assumed, not measured. Otherwise it follows FreeBSD 11's kern_uuidgen and sys_uuidgen: version 1 UUIDs with consecutive timestamps from the guest CLOCK_REALTIME, a random 14-bit clock sequence that is incremented when the clock has not passed the last batch, and EINVAL for a count outside 1 to 2048. A null store returns EFAULT after the state advances, as copyout fails there; other invalid addresses are not detected
  • unlinkat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to rmdir (with AT_REMOVEDIR, 0x800) or unlink. Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. Removing a directory without AT_REMOVEDIR fails with EPERM, removing . or .. with AT_REMOVEDIR fails with EINVAL, and flags other than AT_REMOVEDIR fail with EINVAL. Console behaviour is unverified
  • renameat (libkernel_sys) passes AT_FDCWD (-100) and absolute paths to rename. Any other relative path is joined to its descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to relative descriptors, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. Console behaviour is unverified
  • fork (libkernel_sys) throws: creating a child process is not supported. PPSA19111 imports it and fails to load without it. Its engine calls fork in Posix_Daemonize, only with -daemonize, and in Platform_ShellExecute before execvp("xdg-open"), which the main menu's Previews button reaches, so pressing Previews ends in this throw. setsid fails with EPERM, as FreeBSD's does for a process group leader, since the guest is taken to lead its own process group (see kill). umask keeps the guest's mask (initially 022, masked to 07777) and returns the previous one, Linux named shared-memory creation applies it, but ordinary files are still created with the host process's mask
  • sceKernelGetModuleInfoInternal, sceKernelGetModuleListInternal and sceKernelLoadStartModuleForSysmodule (libkernel_sys) answer for every loaded module, system modules included. sceKernelGetModuleInfoInternal fills the 0x1A8-byte SceKernelModuleInfoEx of a module handle the way sceKernelGetModuleInfoFromAddr does for an address, with shadPS4's checks in their order: EFAULT for a null pointer, EINVAL when st_size is not 0x1A8, ESRCH for an unknown handle. sceKernelGetModuleListInternal returns the same list as sceKernelGetModuleList, as fpPS4 does; fpPS4 marks that as a guess, and neither is checked on a PS5. sceKernelLoadStartModuleForSysmodule forwards to sceKernelLoadStartModule
  • chroot (libkernel_sys) follows FreeBSD 11.4's sys_chroot and pwd_chroot for a root caller: EFAULT for a null path, ENOENT for an empty or missing one, ENAMETOOLONG for a path of 1024 bytes or more or a component over 255, and ENOTDIR for a path that is not a directory or passes through a file. A directory that is the guest root (/, /.., or . after fchdir to a descriptor of /) succeeds and changes nothing, as the root stays the same directory; the guest is taken never to have changed its root, so open directory descriptors do not make it fail with EPERM (kern.chroot_allow_open_directories 1). Any other directory throws, naming the path: the guest path resolver has a fixed root and mount aliases (/app0, /savedata0) that do not move with it. On the console a title starts in a sandbox root, where pwd_chroot refuses with EPERM while a directory is open; whether that holds for titles, and whether a title holds PRIV_VFS_CHROOT, are unverified. Porpoise (PPSA99764) weak-imports it and calls it only as fchdir to its saved descriptor of / then chroot("."), to put its sandbox root back after a jailbreak daemon replaced it (put_root_back)
  • Console identity (libkernel_sys) - get_authinfo errors and capability bits remain unverified on PS5; they follow shadPS4, leaving the authority ID and other capability, attribute and credential words zero. The host models a retail unit (IsCEX 1, IsDevKit 0). The system OpenPSID reuses the ordinary ID; firmware 13.42 reads a separate machdep.openpsid_for_sys, whose value is unknown. Null returns positive 22 per the module report.
  • fchown (libkernel_sys) - ownership is not modelled: the guest's own owner and group (0) and the unchanged value (-1) are accepted, a descriptor that is not open fails with EBADF, and any other owner or group throws, naming it. The check reads the descriptor with fstat, ignoring the CRT's invalid-parameter handler on Windows as DescriptorControl does. The console's ownership rules are unverified. Morrowind (mshivam019/morrowind-ps5) imports it
  • chown, lchown and fchownat (libkernel_sys) - ownership is not modelled, as for fchown: owner and group 0 and the unchanged value (-1) are accepted, and any other owner or group throws, naming it. The path is looked up first, as in FreeBSD 11's kern_fchownat, with stat, with lstat for lchown, and with fstatat for fchownat, so a lookup error is returned before the owner is checked and nothing is changed on the host. fchownat flags other than AT_SYMLINK_NOFOLLOW (0x200) return EINVAL, as in FreeBSD 11. The console's ownership rules are unverified
  • linkat (libkernel_sys) resolves AT_FDCWD (-100) and absolute paths as link does, and flags other than AT_SYMLINK_FOLLOW (0x400) return EINVAL, as in FreeBSD 11. Any other relative path is joined to the descriptor's host directory, found the same way as for fchdir, so guest path aliases and case-insensitive name matching do not apply to it, and a .. component is not kept inside the guest root. It returns EBADF for a descriptor that is not open and ENOTDIR for one that is not a directory. A symbolic link as the source without AT_SYMLINK_FOLLOW throws, where FreeBSD links the symbolic link itself. Console behaviour is unverified
  • pthread_set_defaultstacksize_np and scePthreadSetDefaultstacksize (libkernel_sys) set the stack size that scePthreadAttrInit and a thread created without attributes use, as fpPS4's pthread_set_defaultstacksize_np does: a size of 16384 bytes or less fails with EINVAL (0x80020016 from the sce form) and there is no upper limit, so a default the host cannot allocate fails only when a thread is created. Attributes initialised earlier keep their size. Not checked on a PS5
  • sceKernelTitleWorkaroundIsEnabled (libkernel_sys) - not measured on a console; the {version, align, ids[2]} layout, the bit test and the limit of 0x3A bits follow shadPS4, which notes that the limit changes between firmwares. A negative bit is EINVAL here; shadPS4 compares it signed and reads outside ids. Titles usually pass the title_workaround block of sceKernelGetAppInfo, which does not write that block here, so the bits read are whatever the caller's memory held
  • sceKernelGetProcessType (libkernel_sys) - not measured on a console; as in shadPS4, the title's own pid, -1 and 0 are type 0 (big application) and any other pid is ESRCH

Unknown function info