Files
AnyPS5/docs/dev/debt/libSceFios2.md
T

16 KiB

libSceFios2 technical debt

Functional

  • libSceFios2 prototypes (libSceFios2) - the implemented exports take the prototypes of RPCS3's Vita FIOS2 module (Emu/ARMv7/Modules/sceFios.h and sceFios.cpp, jacquesjk/RPCS-DX12 at 9b8b7c9eea446095f24af19182032013837e6ca5, 64-bit types substituted), checked against the PS4 headers and call sites of kalaposfos13/fios2 (src/fios2.h, ae6ca1d78e7a822c2528f7660959167b9b3d8b63), sonny-tel/libSceFios2 (sceFios2.h, 5d44f9e7a80ae00557af80fad335e4c74ef35d22), Inori/GPCS4 (SceFios2/sce_fios2.cpp) and SonicMastr/SceLibcPosix (src/internal/fios2.h, Vita, c2cd5e880a8770bdbfb58de761de11f396c1a2e7).

  • Layouts (libSceFios2) - The SceFiosOpAttr, SceFiosOpenParams, SceFiosStat and SceFiosDirEntry layouts and the SCE_FIOS_ERROR_* values (0x80820000 plus the enumeration order) come from the same sources; vascon-es, a PC port of a PS4 title (CUSA01176 and CUSA00935 version 01.24), at 57c3c202975ea48e574df2d1e4a620b4e18b7701, confirms the SceFiosStat and SceFiosDirEntry offsets and the fileSize, statFlags bit 0 (directory) and offsetToName reads from the call sites of a PS4 title. None of it was measured on a PS5. The SceFiosOpenParams buffer sits at offset 8 in kalaposfos13 and sonny-tel and at offset 0x10 in vascon-es; only openFlags is read

  • Operations (libSceFios2) - there are no I/O or decompressor threads. An operation runs on the calling thread and is complete when the export returns, and its callback fires there with SCE_FIOS_OPEVENT_COMPLETE; while sceFiosSuspend is in effect new operations queue and run on the thread whose sceFiosResume ends the suspension. deadline, priority, opflags, userTag, userPtr and the scheduler fields are stored and returned but have no effect, and SCE_FIOS_OPEVENT_START is never sent. The *Sync exports are the asynchronous export followed by sceFiosOpSyncWait, so they also fire the completion and SCE_FIOS_OPEVENT_DELETE callbacks.

  • Completion values and parameters (libSceFios2) - sceFiosOpSyncWait returns the error or the low 32 bits of the result (1 or 0 for the existence queries, as in kalaposfos13/fios2), sceFiosOpGetActualCount returns the result (the size for sceFiosFileGetSize) also for a failed operation, and sceFiosOpGetError returns 1 while an operation is queued; none of these is measured. Handles of operations, files and directories share one number space that starts at 1. Nothing requires sceFiosInitialize first, and SceFiosParams is stored as paramsSize bytes (the 15 bits at bit 1 of the first word) without interpretation, so the storage buffers, pathMax (1024 is used), thread and scheduler settings are ignored

  • sceFiosExists, sceFiosFileExists, sceFiosDirectoryExists, sceFiosFileGetSize, sceFiosStat and their Sync forms (libSceFios2) - paths go to sceKernelStat, so archive and alias mapping is the kernel's. A missing path is not an error for the existence queries. SceFiosStat carries only the sizes, the nanosecond dates as seconds since 1970 times 10^9 plus nanoseconds (the epoch and unit are not measured), statFlags bit 0 for a directory, and the kernel st_uid, st_gid, st_dev, st_ino and st_mode; other statFlags bits are 0. sceFiosFileExists and sceFiosDirectoryExists take the pOutExists argument of RPCS3's prototype, which kalaposfos13/fios2 omits, and sceFiosFileGetSize has no output pointer as in kalaposfos13/fios2 and sonny-tel (RPCS3 declares one)

  • sceFiosDelete, sceFiosFileDelete, sceFiosDirectoryCreate, sceFiosDirectoryDelete, sceFiosRename, sceFiosFileRead, sceFiosFileWrite, sceFiosFileTruncate and their Sync forms (libSceFios2) - behaviour is inferred from the export names; none of it is measured. They run on sceKernelStat, sceKernelOpen, sceKernelPread, sceKernelPwrite, sceKernelFtruncate, sceKernelMkdir, sceKernelRmdir, sceKernelUnlink and sceKernelRename, so guest path mapping and the read-only application directory are the kernel's. sceFiosFileWrite opens the file write-only with creation and no truncation, sceFiosFileTruncate does not create it, directories are created with mode 0777 and files with 0666, sceFiosDelete removes a file or an empty directory, and a negative length returns SCE_FIOS_ERROR_BAD_SIZE, a negative offset SCE_FIOS_ERROR_BAD_OFFSET.

  • Error mapping (libSceFios2) - A read stops at the end of the file and returns the bytes read. The mapping of kernel errors to SCE_FIOS_ERROR_* is chosen here: ENOENT and ENOTDIR to BAD_PATH, EPERM, EACCES and ENOTEMPTY to ACCESS, EROFS to READ_ONLY, EEXIST to ALREADY_EXISTS, EISDIR to NOT_A_FILE, EINVAL to BAD_OFFSET, ENFILE and EMFILE to CANT_ALLOCATE_FH, ENAMETOOLONG to PATH_TOO_LONG, EFAULT to BAD_PTR, and anything else to UNKNOWN. The prototypes follow RPCS3 (sceFios.cpp sceFiosFileWrite, sceFiosFileTruncate, sceFiosRename, sceFiosDelete) and kalaposfos13/fios2 (sceFiosFileRead)

  • sceFiosFHOpen, sceFiosFHOpenWithMode, sceFiosFHClose, sceFiosFHStat, sceFiosFHTruncate, sceFiosFHSync, sceFiosFHRead, sceFiosFHWrite, sceFiosFHPread, sceFiosFHPwrite, the vectored forms with their Sync forms, sceFiosFHSeek, sceFiosFHTell, sceFiosFHGetSize, sceFiosFHGetPath and sceFiosFHGetOpenParams (libSceFios2) - a file handle owns one kernel descriptor, and sceFiosFHRead, sceFiosFHWrite, sceFiosFHSeek and sceFiosFHTell use its kernel position.

  • File handle errors and lifetime (libSceFios2) - openFlags map as SCE_FIOS_O_READ 1, SCE_FIOS_O_WRITE 2, SCE_FIOS_O_APPEND 4, SCE_FIOS_O_CREAT 8 and SCE_FIOS_O_TRUNC 16 (sonny-tel/libSceFios2, SonicMastr/SceLibcPosix); SCE_FIOS_O_DIRECT (1 << 12) is ignored, no flags or null parameters open read-only, and the handle returns SCE_FIOS_ERROR_WRITE_ONLY or SCE_FIOS_ERROR_READ_ONLY for a transfer its flags exclude (the console result is not measured). The creation mode is 0777 unless sceFiosFHOpenWithMode is given one (-1 means the default, as in kalaposfos13/fios2).

  • Open flags and offsets (libSceFios2) - Opening a directory returns SCE_FIOS_ERROR_NOT_A_FILE. An invalid whence or a negative resulting position returns SCE_FIOS_ERROR_BAD_OFFSET, a vector count outside 1 to 1024 SCE_FIOS_ERROR_BAD_IOVCNT. The Readv and Writev exports transfer the vectors in order and stop at the first short one. sceFiosFHGetPath and sceFiosFHGetOpenParams return pointers that stay valid until the handle is closed; the stored SceFiosOpenParams has no buffer. The handle prototypes follow RPCS3's sceFios.cpp and kalaposfos13/fios2; sceFiosFHToFileno and sceFiosFilenoToFH have no source and keep throwing

  • sceFiosDHOpen, sceFiosDHRead, sceFiosDHClose, their Sync forms and sceFiosDHGetPath (libSceFios2) - the prototypes follow RPCS3 and kalaposfos13/fios2, with the SceFiosBuffer passed by value in two registers as in vascon-es. Opening reads the whole listing through sceKernelGetdirentries into host memory; the caller's buffer is never written. A title that opens with a null or too small buffer gets SCE_FIOS_ERROR_BAD_SIZE and the required size from sceFiosOpGetActualCount, the probe that vascon-es observes at the call sites of a PS4 title.

  • Required directory buffer size (libSceFios2) - The required size, 16 plus the name lengths plus one each, is chosen here and is not what the console reports, so a title that sizes its buffer from another source can get a false BAD_SIZE. . and .. are not listed (unverified), entries come in kernel order, the end of the listing returns SCE_FIOS_ERROR_EOF and sceFiosDHRead fills fileSize, statFlags bit 0, nameLength, fullPathLength, offsetToName and fullPath as vascon-es reads them, with fullPath the opened path, a slash and the name

  • sceFiosDateGetCurrent, sceFiosDateFromComponents, sceFiosDateToComponents, sceFiosTimeIntervalFromNanoseconds and sceFiosTimeIntervalToNanoseconds (libSceFios2) - a SceFiosDate is taken as nanoseconds since 1970-01-01 UTC and a SceFiosTimeInterval as nanoseconds (identity conversions), as in kalaposfos13/fios2 (src/fios2.cpp, time(nullptr) * 1000000000) and RPCS3 (sceFios.cpp, 64-bit unsigned date); neither is measured, and both may descend from one Vita SDK. kalaposfos13/fios2 converts components through local time, here they are UTC (sceFiosDateFromComponents normalizes out-of-range fields like timegm and returns 0 before 1970). Only the nine leading int fields of struct tm are read and written, so tm_gmtoff and tm_zone are left untouched. sceFiosTimeGetCurrent has no source for its clock and keeps throwing

  • Operation threading (libSceFios2) - an operation and its SCE_FIOS_OPEVENT_COMPLETE callback run inside the call that issues the operation, whereas on the console the callback runs on a FIOS I/O thread. A title that issues an operation while holding a lock its own callback takes deadlocks on its own thread, and a title that expects the output pointers (pOutFH, pOutExists, pOutStatus) to be written only after sceFiosOpWait is not tested. A worker thread was not added: guest callbacks need a guest thread (scePthreadCreate, as libSceJobManager uses) with its TLS and stack, the *Sync forms must stay synchronous on the caller, and moving completion to another thread changes every output-pointer, callback and teardown ordering in the library and its tests, which could not be validated here against a title or a console

  • Guest inputs (libSceFios2) - SceFiosOpAttr, SceFiosOpenParams, SceFiosParams, the vector arrays and struct tm are copied with GuestCopyIn_nid_no_patch; a failed copy returns SCE_FIOS_ERROR_BAD_PTR (the operation handle value itself for an unreadable SceFiosOpAttr), or is ignored by the void exports. That the console returns SCE_FIOS_ERROR_BAD_PTR for an unreadable pointer is not measured

  • sceFiosInitialize, sceFiosUpdateParameters and sceFiosIsInitialized (libSceFios2) - init accepts null/arbitrary sizes and stores raw parameters; updates replace the whole block. PS4 libSceFios2.sprx (init banner SDK 0x10710001), disassembly only: Initialize takes const SceFiosParams* and returns int32_t. Null returns BAD_PTR; size other than 0xb0, nonzero reserved fields or extraFlags beyond quiet return BAD_SIZE; schedulerAlgorithm >= 4 returns BAD_FLAGS. Repeated init returns 0 after UpdateParameters, which ignores calls before init or with another size, otherwise copying only maxChunk, pVprintf, pMemcpy, priorities and affinities. IsInitialized returns the init state and copies 0xb0 bytes to a non-null output only after successful init. PS5 and console behaviour remain unverified

  • SceFiosParams (libSceFios2) - forward-declared without a layout; the implementation does not apply the defaults below. The same module uses every offset of sonny-tel's 0xb0-byte layout and applies these defaults: pathMax 0 or above 1024 becomes 1024; ioThreadCount 0 becomes 1 and above 2 becomes 2; threadsPerScheduler 0 becomes 1 and above 3 becomes 3; maxChunk 0 becomes 0x80000; maxDecompressorThreadCount 0 becomes 2 and above 3 becomes 3; a null pVprintf or pMemcpy selects the library's own; a priority of -1 becomes 260, 700 and 260; stack sizes below 0x14000, 0x4000 and 0x4000 are raised to them. The op, FH and DH pools take elements of pathMax plus 0x100, 0x70 and 0x68 bytes, rounded up to 8

  • Kernel errors (libSceFios2) - FromKernelError differs from PS4: EFAULT becomes BAD_PTR, EINVAL BAD_OFFSET, ENOTDIR BAD_PATH, ENFILE/EMFILE (23/24) CANT_ALLOCATE_FH, ENAMETOOLONG (63) PATH_TOO_LONG, and unlisted errors UNKNOWN. The same module has no pre-init guard; file calls reach the kernel. Its shared mapper returns ACCESS for EPERM/EACCES/ENOTEMPTY; BAD_PATH for ENOENT/EINVAL/EOPNOTSUPP/ENAMETOOLONG/89; BAD_FH for EBADF; BUSY for EBUSY; ALREADY_EXISTS for EEXIST; MEDIA_GONE for ENODEV/ENOSYS; NOT_A_DIRECTORY for ENOTDIR; NOT_A_FILE for EISDIR; READ_ONLY for EROFS; EOF for ERANGE; TIMEOUT for ETIMEDOUT. Other kernel codes, including EFAULT (0x8002000e), ENFILE and EMFILE, return unchanged. This is PS4 disassembly evidence; PS5 parity is unverified

  • Error codes (libSceFios2) - Types.hpp declares the subset used by the implementation; the source for the full name table is the PS4 module below. The same module's name table gives these SCE_FIOS_ERROR_ names to 0x80820000 plus: 0x00 UNIMPLEMENTED, 0x01 to 0x04 CANT_ALLOCATE_OP, _FH, _DH and _CHUNK, 0x05 BAD_PATH, 0x06 BAD_PTR, 0x07 BAD_OFFSET, 0x08 BAD_SIZE, 0x09 BAD_IOVCNT, 0x0a BAD_OP, 0x0b BAD_FH, 0x0c BAD_DH, 0x0d BAD_ALIGNMENT, 0x0e NOT_A_FILE, 0x0f NOT_A_DIRECTORY, 0x10 EOF, 0x11 TIMEOUT, 0x12 CANCELLED, 0x13 ACCESS, 0x14 DECOMPRESSION, 0x15 READ_ONLY, 0x16 WRITE_ONLY, 0x17 MEDIA_GONE, 0x18 PATH_TOO_LONG, 0x19 TOO_MANY_OVERLAYS, 0x1a BAD_OVERLAY, 0x1b BAD_ORDER, 0x1c BAD_INDEX, 0x1d EVENT_NOT_HANDLED, 0x1e BUSY, 0x1f BAD_ARCHIVE, 0x21 BAD_FLAGS, 0x22 UNKNOWN, 0x23 ALREADY_EXISTS and 0x24 IN_CALLBACK. 0x20 has no name, 0 is SCE_FIOS_OK and 1 is SCE_FIOS_IN_PROGRESS

Unknown function info