58 KiB
58 KiB
Project technical debt
Build
- Building on Windows requires a specific version of mingw - MinGW-w64 GCC 15.2.0 (
winlibs-gcc15,x86_64-ucrt-posix-seh) - Even compiled prx libraries on Windows require nearby (static linking of these dependencies causes conflicts):
- libgcc_s_seh-1.dll
- libstdc++-6.dll
- libwinpthread-1.dll
Silent stubs
Throughout the project, every function at every stage either does exactly what it's supposed to or throws an exception. Everywhere... except:
- libSceSaveDataDialog.native
- libSceMsgDialog.native - dialogs finish at
sceMsgDialogOpenwithout UI and answer with button 1, sosceMsgDialogClosereturnsNOT_RUNNING; its result beforesceMsgDialogInitializefollows libSceMsgDialog - libSceCommonDialog
- libSceErrorDialog - the error dialog runs the state machine but shows nothing; the error code passed to
sceErrorDialogOpenis only logged - libSceHmd implements only the disconnected-headset path: initialization succeeds, device queries report
NotDetected, and opening a device returnsDeviceDisconnected. Headset support, tracking, rendering and additional HMD exports are not implemented; SDK-level ABI compatibility and in-game behaviour remain unverified. - libSceAudioPropagation implements only the no-acoustic-propagation path: the system keeps a 16-byte header in the title's CPU memory (no GPU memory), rooms, portals, sources and materials are tracked handles, attributes are validated and have no effect, no rays are requested and sources report no audio paths. Ray results, path calculation and audio paths are accepted only when empty and throw otherwise;
sceAudioPropagationSourceRenderwrites silence (zeroes) to each source's output buffer for the given size, without a dry signal. Objects still alive when their system is destroyed become unusable, and their later destroy or unregister is a no-op: PPSA21567 releases its reference-counted room, portal and source owners just beforesceAudioPropagationSystemDestroy, so the order for every object is not proven. Occlusion, reflections and reverb from level geometry are absent; in-game behaviour remains unverified. - libSceNpCommerce - the PS Store icon show/hide calls and
sceNpCommerceSetPsStoreIconLayoutdo nothing - libSceSystemService -
sceSystemServicePowerTickandsceSystemServiceReportAbnormalTerminationreturn success and do nothing: the host has no auto power-off timer to reset and no system crash reporter to notify - sceVideoOutOpen validates the priority and CPU affinity that the open param requests for the VideoOut service thread but does not apply them: the port's present and vblank threads are host threads, and guest priorities and affinities do not reach host scheduling
- The shader recompiler skips baryctric coordinates (is not even passed to SpirvTargetOptions at row 212).
- libSceAudio3d - the port produces no sound: the library has no bed or object exports to give it audio, so
sceAudio3dPortPushonly paces the queue atgranularitysamples per frame at 48 kHz.sceAudio3dPortSetAttributeaccepts the late reverb level and the downmix spread attributes and ignores them - libSceAvPlayer:
sceAvPlayerSetLogCallbackaccepts a callback that is never called, as the player produces no log messages, andsceAvPlayerSetAvailableBandwidthhas no effect, as it governs HLS sources, whichsceAvPlayerAddSourcedoes not implement. - libSceNpTrophy2:
sceNpTrophy2RegisterUnlockCallbackaccepts a callback that is never called, as no trophy is ever unlocked, andsceNpTrophy2UnregisterUnlockCallbackonly returns success. - sceAvPlayerSetTrickSpeed (libSceAvPlayer) with a negative speed runs the clock backwards but delivers no frames; when a forward speed is set again, playback resumes from the rewound time.
- ulobjmgr registers no object:
_sceUlobjmgrRegisterObjectalways hands out id 0 and_sceUlobjmgrUnregisterObjectreleases nothing, as shadPS4 does - libSceHttp - no request reaches the network, so
sceHttpSetResponseHeaderMaxSizehas no response header to limit andsceHttpRedirectCacheFlushno redirect to forget;sceHttpsUnloadCertreturns success likesceHttpsLoadCert, which keeps no certificate
Unknown function info
- sceAvPlayerAddSource (libSceAvPlayer) - requests up to 4 additional decode-ahead video framebuffers from the memory replacement beyond
num_output_video_framebufferswhen memory is available; the console's internal buffering behaviour is unknown - sceVideoOutRegisterBuffers2 (libSceVideoOut) - buffer option 8 (STRICT_COLORIMETRY) is presented as option 0, with the stored values unchanged; what the console changes for it is unknown. Only options 0 and 8 are accepted
- sceVideoOutRegisterBuffers2 (libSceVideoOut) - DCC buffers (category 1):
dcc_controlis taken as the CB_DCC_CONTROL block layout, only bits 0x10026c are accepted;dcc_cb_register_clear_coloras the register-clear texel, only 32-bit values are presented - sceVideoOutOpen (libSceVideoOut) - the open param's first word is unknown (PPSA21564 passes 16; it is not the byte size, since the affinity mask is at offset 16); only 16 is accepted. Whether the param continues past offset 24 is also unknown
- sceRtcParseDateTime (libSceRtc) - accepted format assumed to be the ISO 8601 subset
YYYY-MM-DDTHH:MM:SS[.ffffff](T/t/space separator, optional fractional seconds) with the sibling RFC 3339 zone suffix (Zor±HH:MM), plus the RFC 2822 shapeDdd, DD Mon YYYY HH:MM:SS[ GMT| ±HHMM]and the asctime shapeDdd Mon DD HH:MM:SS YYYY(day zero- or space-padded) that shadPS4 parses at fixed positions; the weekday name is not checked against the date, a±HHMMoffset is subtracted to get UTC like the RFC 3339 path (shadPS4 adds it), a string without a zone is taken as UTC, and anything outside these shapes throws instead of returning a parse error, unverified against hardware - sceAudio3dPortOpen (libSceAudio3d) - buffer modes 0 and 1 (also selected by the 0x10 and 0x18 parameter sizes) and 3 beds depend on an SDK version check in the module (prosper) and throw. A repeated
sceAudio3dInitialize(NOT_READYin shadPS4, 0 in prosper) andsceAudio3dPortAdvanceon a full queue (NOT_READYin shadPS4, unhandled in KytyPS5) throw too - AMPR WriteAddressFromCounterPairOnCompletion (libSceAmpr) - the pair of an even counter n is assumed to give counter n in the low 32 bits and n + 1 in the high 32 bits. Wait compare values, wait flush and counter index ranges follow the ampr_emu reimplementation; the flush is accepted and has no effect, as commands run in order
- AMPR command sizes (libSceAmpr) - commands use the emulator's own encoding with an 8-byte header, so
Nop(n)takes 8 + 4n bytes where the console record is n dwords including its header (NopWithData(n): (n + 1) dwords). The measure functions agree with the appended sizes, but a title that pads to an exact offset or the end of the buffer withNop(remaining / 4)getsSCE_AMPR_ERROR_BUFFER_FULLor a shifted offset. The at-start flag of the_04_00writes is ignored; commands run in order, each after the previous one completes - AMPR counter access (libSceAmpr) - signatures and checks of
WaitOnCounter_04_00,WriteCounter_04_00,ConstructNopandConstructMarkertaken from the ampr_emu reimplementation, which hands counter commands to the console and does not show their effect. The counters are taken as 32 bits each: the 8-byte access of counter n spans n (low) and n + 1 (high), the 2- and 1-byte accesses select a half or a byte of the counter by its offset, waits compare at the access width (signed and wrapped compares included), the AND mask applies to both sides and the atomic writes wrap within the access. TheConstructNoptype is not recorded - APR gather and scatter reads (libSceAmpr) - signatures, argument checks and the read cursor taken from the ampr_emu reimplementation, not confirmed on a title: each read leaves the file, the next file offset and the next destination; a gather reads that file at a new offset into the next destination, a scatter continues in the file into a new destination, a gather-scatter takes both. Recording one needs a read file since the last
ResetGatherScatterState; like ampr_emu,sceAmprCommandBufferResetkeeps that state, and a gather or scatter with no read before it in the submitted buffer throws instead of returningSCE_AMPR_ERROR_APR_INVALIDGATHERSCATTERSTATE - AMM map, map direct and unmap (libSceAmpr) - signatures and the protection mask (CPU, GPU, AMPR and ACP read and write) taken from the ampr_emu reimplementation, which hands the remaining checks and the mapping to the console kernel; the mapper model taken from PS5PCEM:
sceAmprAmmGiveDirectMemoryusage 1 gives the allocated direct memory to the pool plain maps take pages from, usage 0 only allocates it. Not confirmed on a title. The AMM virtual address ranges are a 32 GiB range and a 32 GiB multimap range reserved in the guest arena on first use, not the console's; maps outside them throw. Addresses, sizes and direct offsets must be 16 KiB aligned. The memory type and the GPU mask are ignored, AMPR and ACP access maps as CPU access, unmapped pages go back to the pool and stay reserved. Submission runs the buffer before returning, the submit result is always 0 and a failing command throws; the AMM measures return errors sign-extended, as ampr_emu does.sceAmprAmmGetVirtualAddressRangesthrows for a null output - AMM remap, multimap and protection changes (libSceAmpr) - signatures and the protection and mask checks taken from ampr_emu; the effects are inferred from the names, not confirmed on a title. A remap moves every page of a fully mapped range to the new address with the given protection and leaves the old range reserved; a multimap maps the same pages at a second address, anywhere in the AMM ranges, and a pool page goes back to the pool once its last mapping is unmapped; a multimap onto its own source range throws. A protection change sets the masked bits on every page of a fully mapped range; the memory type is recorded and ignored. A command on a range that is not fully mapped throws
- AMM PRT ranges (libSceAmpr) - signatures, checks and their order taken from ampr_emu, where
MapAsPrtis a map with the PRT flag and protection 0 andAllocatePaForPrta memory type and protection change with mask 1019, both checking the buffer memory after its size; the effects are inferred from the names, not confirmed on a title. Unbacked PRT pages are zero-filled pages with GPU read access, so CPU reads see zeros instead of faulting and GPU writes fault instead of being dropped.AllocatePaForPrtbacks each unbacked page with a pool page and sets the type and protection of backed ones;RemapIntoPrtmoves a fully mapped range into a PRT range, its opcode argument (1011 when 0, as in ampr_emu) is recorded and ignored;UnmapToPrtreturns the pages to the pool and zero-fills them again. A plain map, unmap or remap over a PRT range ends it;AllocatePaForPrt,RemapIntoPrtorUnmapToPrtoutside a PRT range throws - APR map begin and end (libSceAmpr) - as in ampr_emu,
MapBegin/MapDirectBeginmap when they run andMapEndonly closes the region; while a region is open a second begin and every completion write returnEPERM, the at-start_04_00writes are accepted - AMPR markers (libSceAmpr) - signatures taken from the ampr_emu reimplementation, not confirmed on a title:
sceAmprCommandBufferSetMarkerWithColortakes the color by pointer, the push and measure variants by value. Colors are not recorded - sceFontGetRenderScaledKerning (libSceFont) - arguments, the cleared output and the bound renderer check taken from
cellFontGetRenderScaledKerningin RPCS3 (PS3 predecessor of the library), not confirmed on a title. The kerning is thesceFontGetKerningone at the render scale - sceFontGetPixelResolution (libSceFont) - signature taken from the IDA type database of Orbital, not confirmed on a title. The value is the one the library's driver reports (64 for FreeType); the argument checks and the cleared output follow
sceFontGetLibrary - sceFontCreateWritingLine, sceFontWritingLineWritesOrder (libSceFont) - signatures and the
SceFontWritingLineStep/SceFontCreateWritingLineDetaillayouts (detail id0x0FD5) taken from SharpProspero, not confirmed on a title; the meaning of the 64-bit writing attribute is unknown - sceSaveDataTransferringMountPs4, sceSaveDataDirNameSearchPs4 (libSceSaveData.native) - arguments assumed to be those of
sceSaveDataTransferringMountandsceSaveDataDirNameSearch: KytyPS5 binds both NIDs to the PS5 functions, and prosper captured the same result layout on a title for the search. There is no PS4 save area, so the mount returnsNOT_FOUNDand the search reports zero hits - sce::Json::Parser::parse (libSceJson2) - a number that overflows a double (e.g.
1e309) throws: whether the console rejects the document or stores an infinite real is unknown - sceAgcSetSubmitMode (libSceAgc) - mode values unknown; only 0 is accepted
- SET_PREDICATION (AGC driver) - boolean predication follows the AMD PM4 encoding Mesa uses: operation 3 reads 64 bits and 4 reads 32 bits, and bit 8 runs predicated packets when the value is non-zero (clear: when it is zero); the bit 12 hint is ignored. The address must have its low 4 bits clear, as
sceAgcDcbSetPredicationwrites it. Query predication (Z-pass, primitive count), a predicated COND_EXEC, predicated command buffer chains and flips in predicated command buffers throw - sceAgcGetGsOversubscription (libSceAgc) - signature and occupancy formula (base and expanded vertex/export capacities, budget shift,
GE_PC_ALLOC/SPI_SHADER_PGM_RSRC4_GSencoding) follow KytyPS5 only, not confirmed on hardware or a title; a negative or NaN factor that gives a negative target, a missing GS context register or a zeroGE_MAX_OUTPUT_PER_SUBGROUPthrows - sceAgcGetIsTrinityMode (libSceAgc) - signature from the only PPSA26344 call (a pointer to a one-byte flag, result ignored); a null pointer throws because its error code is unknown
- zARR5aCmkoY (libSceAgc) - unknown name, signature
- qj7QZpgr9Uw (libSceAgc) - unknown name
- sceAgcDcbContextStateOpGetSize (libSceAgc) - sizes from KytyPS5 only (5, 27, 27 and 32 dwords), equal to what
qj7QZpgr9Uwwrites; KytyPS5 returns 0 for an operation above 3, here it throws - fd5Bp5tGTgo (libSceAgc) - unknown name
- dolOmWH+huQ (libSceAgc) - unknown name
- dbOlWdppb4o (libSceAgc) - unknown name; same arguments as
sceAgcCreateInterpolantMapping; theSPI_PS_INPUT_CNTLbits foris_f162 inputs follow KytyPS5, not confirmed on hardware - V++UgBtQhn0 (libSceAgc) - unknown name
- sceAgcGetDataPacketPayloadRange (libSceAgc) - signature, the
{base, size in bytes}output and the type 0 range (header + 1, one dword longer than the type 1 payload) from KytyPS5 only, matchingV++UgBtQhn0; prosper returns header + 2 for both types from that address function - gQkqkLttcpw (libSceAgc) - unknown name, signature
- sceAgcDcbPrimeUtcl2 (libSceAgc) - assumed to write the packet
sceAgcAcbPrimeUtcl2writes: PRIME_UTCL2 has the same 5 dwords on the graphics and compute rings. Not confirmed on a title. Both write a NOP of that size, as there is no TLB to prime - sceKernelInternalMemoryGetModuleSegmentInfo (libkernel) - unknown signature
- sceKernelGetModuleInfoFromAddr (libkernel) - the 0x1A8-byte info layout follows the shadPS4 reimplementation; a title's
libc.prxreads onlyid(PPSA14632). The meaning offlagsis unknown; only 2 is accepted, as is only the fullst_size. The id is thesceKernelLoadStartModulehandle of an image opened through the loader and otherwise a stable id from the same range. The name is the host file name without.guest.prx. An image with more than 4 load segments (the converted executable has 7) reports its first 4.tls_offsetis 0 andref_countis 1, as the host loader exposes neither. Not implemented on Windows - sceKernelSyncOnAddressWait (libkernel) - the only known caller passes a null timeout and a name string as the fourth argument; the timeout is assumed to point to microseconds like the other kernel waits, and the name is ignored
- sceKernelSyncOnAddressWait8 / sceKernelSyncOnAddressWait16 / sceKernelSyncOnAddressWait32 / sceKernelSyncOnAddressWait64 (libkernel) - libc's
__std_atomic_wait_direct_8/16/32/64pass a microsecond timeout or null and ignore the result; the by-value comparand, return values and the 2- and 8-byte alignment of Wait16 and Wait64 are assumed - sceKernelAioSubmitReadCommandsMultiple / sceKernelAioSubmitWriteCommandsMultiple / sceKernelAioWaitRequests / sceKernelAioCancelRequest / sceKernelAioCancelRequests / sceKernelAioDeleteRequests (libkernel) - behaviour from shadPS4 (one id per request for the Multiple submits, cancel turns any request aborted and id 0 reports processing, wait mode 2 returns once one request completed); the 128 requests or ids per batch limit is from SharpProspero, with an unknown error, so larger batches throw; wait modes other than 1 (and) and 2 (or) throw; null pointers, negative counts and invalid ids return the codes the single-request siblings use, checked before any state is written
- sceKernelGetAvailableCpumask (libkernel) - returns the default thread affinity, 0x1FFF (CPUs 0 to 12), as KytyPS5 does. Titles pin threads within it (PPSA02664 passes 0x1FFB, Hades II PPSA36082 0x3 and 0x3F); whether CPU 13 is available to a title is not confirmed
- sceKernelMapNamedFlexibleMemoryInternal (libkernel) - flag 0x8000 unknown; only the sceKernelMapNamedFlexibleMemory flags are accepted
- Guest arena (libc) - the application map area is assumed to end at 0xFC_0000_0000, as
SCE_KERNEL_APP_MAP_AREA_END_ADDRdoes on the PS4. On Windows, host allocations made in the arena before libc loads stay, and a fixed guest mapping over one throws - sceLibcInternalBacktraceForGame (libSceLibcInternal, implemented in libc) - unknown signature
- sceLibcInternalHeapErrorReportForGame (libSceLibcInternal, implemented in libc) - unknown signature
- std::_Fiopen (libc) -
_ZSt7_FiopenPKcNSt5_IosbIiE9_OpenmodeEi(NIDvYWK2Pz8vGE; the name comes from the public NID list): the values of the_Openmodeargument and the meaning of the protection argument are unknown, so it throws when called. It is exported so that a title that imports it (PPSA21564 and PPSA21567 do) loads against the host libc when its ownlibc.prxis left out of the guest conversion. - _sceLibcInternalThreadAtexit, _sceLibcInternalThreadDtors (libSceLibcInternal) - FreeBSD
__cxa_thread_atexitsemantics assumed; a null or non-image destructor and an allocation failure throw - _sceLibcInternalForceTlsDestructor (libSceLibcInternal) - unknown return type and behaviour; a title's
libc.prxcalls it from__cxa_finalizewith the module handle of a non-null dso - __progname (libkernel) - unknown data export
- pthread_barrierattr_setpshared (libkernel) - PTHREAD_PROCESS_SHARED throws: FreeBSD 9.0 libthr rejects it with EINVAL and 11.0 accepts it, and which one the console follows is unknown
- sceSslClose (libSceSsl) - unknown signature
- sceSslGetSerialNumber (libSceSsl) - unknown signature
- X+4jdIS75P0 (libSceAudioIn) - unknown name, signature
- sceAudioOut2Set3DLatency (libSceAudioOut) - assumed to take
(user_id, latency): KytyPS5 reads(user_id, output, latency_us), but the only known call sets just edi and esi; only(0xFF, 2)is accepted - sceAudioOut2MasteringInit (libSceAudioOut) - flag values unknown; only 0 is accepted
- sceAudioOutSetMixLevelPadSpk (libSceAudioOut) - effect of a negative mix level unknown; only 0 to 32768 (0 dB) is accepted
- sceAudioOutSetMixLevelPadSpk (libSceAudioOut) - no source applies the level (shadPS4 only stores it); it is assumed to be a linear gain on the port's own output, and the -9 dB default (11626) is applied to every pad speaker port, including those of titles that never call the function
- sceAudioOutGetLastOutputTime (libSceAudioOut) - signature and behaviour taken from the shadPS4 and fpPS4 reimplementations of the PS4 library, not confirmed on a PS5 title: the time is the process time at which
sceAudioOutOutputorsceAudioOutOutputsaccepted the port's last block, not the time the block reached the device - sceAudioOut2PortCreate (libSceAudioOut) -
data_formatis read as the channel count (bits 8-11: only 1, 2, 6, 8 or 12) and sample type (bits 0-6: 0 float, 1 int16); bit 7 and the portflagsare not decoded, and bits 12-31 throw - sceAudioOut2PortCreate (libSceAudioOut) - 12 channels are assumed to be L R C LFE Ls Rs Lb Rb Ltf Rtf Ltb Rtb as in KytyPS5's 12-to-8 fold, and 6 and 8 channels to be its first 6 and 8; no title or SDK header confirms the order
- sceAudioOut2PortCreate (libSceAudioOut) - the stereo fold is assumed, not the console's downmix: C at -3 dB into both sides, Ls/Rs, Lb/Rb and Ltf/Rtf at -3 dB and Ltb/Rtb at -6 dB into their own side, LFE dropped
- scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100, scePsmlMfsrGetDispatchMfsrPacket1100 (libScePsml_debug) - argument layouts unknown; only 0x8A810001 (not initialized) is returned
- BnMAMrsfVWo (libc) - unknown name, signature
- scePngEncEncode (libScePngEnc) - whether rows may stay unfiltered when
filter_typenames a subset of the filters is unknown; as in shadPS4, they may only for 0 and for the all-filters mask - sceVoiceQoSInit (libSceVoiceQoS) - the error codes are unknown: a null or empty memory block, an app type other than 0x20000000 (PPSA14632) or 0x10000000 (PPSA26344) and a second initialization throw. The minimum memory size is unknown; the app type and the block are not used, as no endpoint is implemented
- AudioIn, NpSessionSignaling and PlayerInvitationDialog exports added without an implementation have assumed signatures
- vieBRwlh1Lw (libSceAgc) - unknown name, signature
- fCWdlnmB1Ks (libScePad) - unknown name, signature
- sceKernelGetOperationMode (libkernel) - the signature
(int* mode, int* submode)comes from PPSA12544, which logs both values after the call; the values are unknown and 0 is reported for both, as in the prosper reimplementation. Null outputs throw - Font, Http2, Net, Ssl, SystemService and libkernel exports imported by PPSA12544 and added without an implementation have unknown signatures
- libSceVrSetupDialog, and the Share, NpTrophy2, NpEntitlementAccess and WebBrowserDialog exports imported by PPSA12544's Unity plugins and added without an implementation, have unknown signatures
- libSceAudioPropagation (libSceAudioPropagation) - signatures and struct descriptors recovered from PPSA21567's calls (#481), not from documentation. The system options layout is unknown (only checked for non-null); the fourth argument of
sceAudioPropagationSourceCalculateAudioPathsis unknown;sceAudioPropagationSourceGetAudioPathis assumed to output an 8-byte path handle. The meaning of theRenderInfoword at +0x28 is unknown (PPSA21567 and PPSA21564 pass 2); only 2 is accepted. Both titles pass oneRenderInfoper call: a count of 0 throws, and larger counts are handled element by element without proof. No error code is known, so invalid input throws instead of returning one - sceAvPlayerStartEx (libSceAvPlayer) - start info layout unknown; it is ignored and playback starts as with
sceAvPlayerStart - sceAvPlayerInit / sceAvPlayerInitEx (libSceAvPlayer) - behaviour without a memory replacement unknown; frame and sample buffers then come from the guest heap
- SceAvPlayerVideoEx (libSceAvPlayer) - frame rate field and encoding unknown; it is left zero in frame and stream info
- sceRazorCpuPushMarkerStatic, sceRazorCpuPopMarker (libSceRazorCpu) - signatures from PPSA26344's calls; (name, color, flags) assumed for the push; both do nothing without a capture
- sceAjmBatchJobGetInfo (libSceAjm.native) - writes the result and format sideband of a run job without buffers with the
SIDEBAND_FORMATflag (0x400000000000), as KytyPS5 does, not confirmed on a PS5 title; the format reports bitrate 0 for ATRAC9 as in KytyPS5, while shadPS4 derives it from the superframe size; before the instance is initialized it returns the not-initialized result (1) and no format, like the other run jobs here, while KytyPS5 returns result 0 with the format of the uninitialized decoder - sceAjmDecMp3ParseFrame (libSceAjm.native) - signature, result layout and rate tables taken from the shadPS4 reimplementation of the PS4 library, not confirmed on a PS5 title: the layer field is not checked and MPEG-2.5 stops at 64 kbps; the original file length (
parse_ofl) layout (Xing/Info + LAME tag, VBRI, Fraunhofer0xB4block with its CRC, encoder delay = samples per frame + LAME delay + 529) also comes from shadPS4 only, and the Fraunhofer block has no other public description - sceAjmBatchJobGetCodecInfo, sceAjmBatchJobGetGaplessDecode (libSceAjm.native) - the
RUN_GET_CODEC_INFOflag (0x800), the ATRAC9 codec info layout and its next frame size are taken from the shadPS4 and RPCSX reimplementations, not confirmed on a PS5 title; a run job without buffers returns result 0, as in shadPS4. The gapless sideband reports the total and skip counts the title set and does not count them down: RPCSX does the same, shadPS4 counts them down and BryKytyPS5 returns its current counts - AJM Opus decoder (libSceAjm.native, codec 24) - the initialize parameter layout (
u32 channels, u32 sample rate, u32, seen as2, 48000, 0) and the little-endianu16byte count before each packet come from one title (The Smurfs Dreams); only 48000 Hz and a zero third word are accepted - sceAjmBatchJobControl (libSceAjm.native) - RESET (bit 13), INITIALIZE (bit 14) and the sideband input order (gapless decode, then initialize parameters) come from shadPS4 (PS4); other flags throw
- sceAjmBatchJobControl (libSceAjm.native) - RESET is assumed to clear the context as sceAjmBatchJobClearContext does
- sceAjmBatchJobControl (libSceAjm.native) - initialize parameters are 8 bytes for ATRAC9, 12 for Opus and none for MP3, as one title passes them; other codecs and sizes, and an output other than the 8-byte result, throw
- sceAjmBatchJobControl (libSceAjm.native) - SIDEBAND_GAPLESS_DECODE with RESET overwrites both counts as in RPCSX; shadPS4 ignores a zero count when the other is nonzero. Without RESET they differ, so it throws
- NGS2 custom submixer rack (libSceNgs2.native, rack 0x4002) - structure layouts from shadPS4's
ngs2_custom.h; module id 0x1f for UserFx2, the voice parameter id0x40001f00 | module index, the process flags (1 on the first process call after setup, 2 after a parameter change, 0 otherwise) and the call order (setup per voice at rack creation, process after the inputs are mixed, cleanup at destruction) come only from KytyPS5. Only UserFx2 modules on a single buffer are accepted: other module ids, more buffers, a module control handler, different input and output channel counts, setup flags and default rack options throw. Each module's state is a separate buffer, not thestate_offsetslice of the voice state, andsceNgs2VoiceGetStatestill throws for this rack. As in KytyPS5, process runs only on grains where an input produced samples, so an effect tail stops with the input and a pending flag 2 waits for the next audible grain - sceHttpParseResponseHeader (libSceHttp) - signature follows SharpProspero; parsing and error codes follow shadPS4's reverse-engineered PS4 library, not confirmed on a PS5 title or hardware. Folded values retain their line breaks and whitespace; an empty first line starts the value scan after its line feed. A consumed byte count above
INT_MAXthrows instead of wrapping. - sceHttpParseStatusLine (libSceHttp) - behaviour and error codes follow the shadPS4 reimplementation of the PS4 library, not confirmed on a PS5 title; unlike it, no byte past
lineLenis read - sceHttpUriMerge (libSceHttp) - signature follows SharpProspero; validation, size formula, absolute/relative split and path join follow the disassembly-like body in shadPS4, not confirmed on a PS5 title or hardware. The base URL goes through our
sceHttpUriParse, which removes dot segments from the base path, while the relative part is appended unswept; base query and fragment are dropped. The relative reference is only classified by its scheme and a leading//, and only references with//are validated; as in shadPS4,//host/xis returned unchanged instead of taking the base scheme, a reference with a scheme but no//(mailto:x) is joined onto the base directory, and?qand#fare appended to the base directory instead of the base path. - sceHttpUriUnescape (libSceHttp) - signature follows SharpProspero; percent decoding, invalid sequences and error codes follow shadPS4, not confirmed on a PS5 title or hardware. Size includes the final NUL; malformed escapes and
+remain unchanged, and decoding runs once. - sceHttpUriSweepPath (libSceHttp) - behaviour follows the shadPS4 reimplementation of the PS4 library and its tests (including the PS4 SDK example), not confirmed on a PS5 title or hardware. It is not RFC 3986 5.2.4: a path that doesn't start with
/is copied unchanged and a trailing.or..without a slash is kept. Unlike shadPS4, nothing at or pastsrcSize - 1is read, andsrcSize == 1writes only the terminator - sceHttpSetResponseHeaderMaxSize, sceHttpRedirectCacheFlush, sceHttpsUnloadCert (libSceHttp) - signatures follow shadPS4 (PS4); no PS5 reference has them
- sceHttp2GetMemoryPoolStats (libSceHttp2) - unknown signature
- sceNetGetMemoryPoolStats (libSceNet) - unknown signature
- sceHttpSetRequestStatusCallback (libSceHttp) - no reference implements it (shadPS4 only logs and returns 0); when the callback runs and what status it gets is unknown
- sceNpSessionSignalingGetMemoryInfo (libSceNpSessionSignaling) - unknown signature
- sceNpSessionSignalingGetConnectionStatistics (libSceNpSessionSignaling) - unknown signature
- sceUserServiceGetAgeLevel (libSceUserService) - the meaning of the value is unknown; 0 is reported, as for the unset game presets. PPSA12544 (Unity) only stores it for its user profile
- sceGameUpdateGetAddcontLatestVersion (libSceGameUpdate) - a null
entitlement_labelthrows: KytyPS5 accepts it, prosper returns0x80412803. Bytes afterfoundare zeroed as in KytyPS5; prosper leaves them untouched - sceSystemServiceDisableMediaPlay (libSceSystemService) - unknown signature
- sceSystemServiceReenableMediaPlay (libSceSystemService) - unknown signature
- sceSystemServiceParamGetString (libSceSystemService) - the system name (parameter 6) is the fixed
PS5, not the console's name; other parameters and buffers of 1 to 64 bytes throw - sceNgs2SystemSetSampleRate, sceNgs2SystemSetUserData, sceNgs2SystemGetUserData, sceNgs2SystemLock, sceNgs2SystemUnlock (libSceNgs2.native) - shadPS4 only checks the system handle (
INVALID_SYSTEM_HANDLE) and SharpProspero names what each call does; neither gives the other limits. A sample rate of 0 and a null user data pointer throw, any other rate is accepted, and changing the rate while a sampler filter is enabled throws because the filter coefficients were computed for the old rate. Lock and unlock take the same lock assceNgs2RackLock - sceSaveDataInitialize3 (libSceSaveData.native) - a repeated initialize succeeds: PPSA12544's executable and its Unity SaveData plugin both initialize, and the plugin fails on any error. Initializations are counted and
sceSaveDataTerminateends the session at the last one; how the console pairs them is unknown - sceVoiceSetMuteFlag (libSceVoice) - unknown signature
- sceRtcFormatRFC2822, sceRtcFormatRFC2822LocalTime, sceRtcFormatRFC3339LocalTime (libSceRtc) - only shadPS4 (PS4) has bodies. A null tick returns
INVALID_POINTERlike the existingsceRtcFormatRFC3339, where shadPS4 formats the current time instead; offsets outside ±1439 minutes returnINVALID_VALUElikesceRtcFormatRFC3339; the local-time variants use the host's offset at the given instant (shadPS4 usessceKernelGettimezone, the current offset) - snwprintf_s (libc) - follows C11 K.3.9.1.3 with
RSIZE_MAXassumed to beSIZE_MAX >> 1. A runtime-constraint violation only returns a negative value:set_constraint_handler_sis not exported and the console's default handler is unknown. An invalid multibyte%sargument is copied byte by byte instead of being reported as an encoding error, as invswprintf - libSceUlt queues - the added
sceUltQueuePop,sceUltQueueTryPush,sceUltQueueDestroyandsceUltQueueDataResourcePoolDestroysignatures are inferred from the existing push/pop and object APIs. Queue destruction is assumed to reject blocked callers withULT_ERROR_BUSYand otherwise discard queued data; pool exhaustion returnsULT_ERROR_AGAIN. These rules, alignment checks and shared slot limits have not been confirmed on PS5 hardware or a title. Non-null queue and data-pool option parameters throw because their layouts are unknown. - sceKernelReadv / sceKernelWritev / sceKernelPreadv / sceKernelPwritev (libkernel) are implemented on Linux only; on Windows they throw
- _sceUlobjmgrRegisterObject (ulobjmgr) - parameters taken from shadPS4 (PS4): a nonzero 64-bit object, a nonzero 32-bit kind and a 32-bit id output; the meaning of the first two and the PS5 signature are unverified. The id bound of
_sceUlobjmgrUnregisterObject(below 0x4000) and the rawEINVAL(22) return also come from shadPS4 - sceShareGetCurrentStatus (libSceShare) - validation (feature flag non-zero, status non-null) and the all-zero 16-byte status taken from the KytyPS5 reimplementation, not confirmed on a PS5 title; the meaning of the recording status values is unknown
- sceAgcDcbSetZPassPredicationEnableGetSize, sceAgcDcbSetPredicationDisableGetSize, sceAgcDcbSetBoolPredicationEnableGetSize (libSceAgc) - the builders are inline in the SDK and not exported; the size is assumed to be that of the SET_PREDICATION packet
sceAgcDcbSetPredicationwrites (16 bytes) - Resource registration (libSceAgcDriver) - registration always fails with
RESOURCE_REGISTRATION_UNAVAILABLE, so the owner and resource queries,sceAgcDriverSetResourceUserData,sceAgcDriverFindResourcesPublicandsceAgcDriverUnregisterAllResourcesForOwnerreturn the same error without reading their arguments. Their parameter lists follow the libSceGnmDriver counterparts and are unverified - sceNgs2VoiceControl sampler filter (libSceNgs2.native) - param
0x1000000a, its layout and meaning follow KytyPS5 only: location 1 type 1 is an RBJ low-pass biquad at the system sample rate after resampling, scaled bylevel, a setchannel_maskbit bypasses that channel, type 0 turns the filter off. Other locations and types throw. The voice keeps playing a filter tail after its last block until the history is zero, with outputs below 1e-20 flushed to zero (a KytyPS5 choice); the console's tail length is unknown - sce::Json::InitParameter2 (libSceJson2) - layout inferred, not known: assumed to start with the allocator, its user data and the file buffer size, in that order, and the whole struct is assumed to fit in 40 bytes;
Initializer::initialize(InitParameter2)ignores them asinitialize(InitParameter)does
Functional
- sceNetSendmsg and sceNetRecvmsg (libSceNet) copy the scatter/gather list through one host buffer and accept only the flags
sceNetSend/sceNetRecvaccept. Sending control data throws; a receive never returns control data (msg_controllen0), since no socket option that queues it is supported - Additional content (libSceAppContent) is not installed or mounted:
sceAppContentAddcontMountanswersNOT_FOUNDfor every entitlement label andsceAppContentAddcontUnmountfor every mount point, as no add-content mount is ever handed out - sceKernelInstallExceptionHandler records the handler but nothing delivers to it: a host fault still ends the process, and
sceKernelRaiseExceptionis not implemented. PPSA12544's PS5Util module (Unity) installs a SIGUSR1 handler that readsuc_mcontext.mc_rsp(offset 0xf8 of the context) and raises SIGUSR1 on other threads to stop them for garbage collection, so delivery must run the handler on the target thread with a FreeBSDucontext - libSceUlt queues use preallocated host storage instead of the supplied guest work area; its existing size formula and the 512-byte object layouts remain unverified. Waiting-queue pool thread limits and waiter priority ordering are not implemented. Finalization wakes blocked queue callers with
ULT_ERROR_STATE. - MIMG
tfeandlwenever write the status VGPR after the data. On hardware it is written only when a texel fetch hits an unmapped page of a partially resident texture, or, forlweon sample/gather, when the LOD is below the T#MIN_LOD_WARN; texture memory is always resident here, andlweon sample, gather andimage_get_lodthrows. - Image atomics on 32_SINT and 32_FLOAT surfaces act on the raw dword through an R32_UINT storage view; their float results are assumed to match those measured on 32_UINT surfaces. Other formats throw.
ds_wrxchg2_rtn_b32andds_wrxchg2st64_rtn_b32are translated as two separate 32-bit atomic swaps per invocation. RDNA2 hardware (measured on gfx1035) performs every lane's first exchange before any lane's second one, so when lanes of the same wave or of different waves overlap addresses, the result can differ from hardware.offset0 == offset1throws, although on hardware it is two exchanges in order.- The shader recompiler ignores
s_setreg_b32: writes to MODE (float rounding and denormal controls) and the other hardware registers have no effect, ands_getreg_b32reads of the MODE round fields report round to nearest even even afters_setreg_b32wrote another mode. The initial round mode from the shader's program registers is not read either. - On a host subgroup narrower than 32 lanes,
threadBitreads an EXEC written as a value (s_mov_b32/s_mov_b64) at bit (subgroup invocation id) of EXEC_LO, so lanes at or above the subgroup size read a lower lane's bit. - Shader recompilation currently occurs right before it was transferred to Vulkan with caching, but should be moved to the relinker stage. For this purpose, shader/recompiler was written completely independently from libs/prx.
- v_fma_f64 is fused exactly only for normal inputs: with a subnormal input it is a separate multiply and add, which rounds twice.
- COND_EXEC reads its condition after the earlier packets of its queue complete. Without PFP_SYNC_ME the console's graphics PFP reads it ahead of the ME, so a title that races the read sees a later value here.
- A flip inside a COND_EXEC range throws: the flip is reserved with the video output when the buffer is submitted, and how the console withdraws a skipped one is unknown.
- A COND_EXEC range must hold whole packets and end inside its command buffer. A chained INDIRECT_BUFFER or a REWIND inside a range throws, as what the CP does with the skipped dwords then is unknown.
- v_mullit_f32 follows the hardware measured with the MODE register at IEEE=1 and denormals kept (a signaling NaN src0 is quieted, a positive denormal src2 counts as positive): the recompiler does not read MODE, so other IEEE/denormal settings are not modelled.
- v_fma_legacy_f32 (VOP3 0x140) is assumed to be fused, which has not been measured on hardware. LLVM decodes this encoding as
v_mad_legacy_f32for gfx1013, andv_mac_legacy_f32(VOP2 0x06) was measured to round its product before the add, so 0x140 may do the same. - The executable file that relinker generates opens the console when launched, which is inconvenient for playability.
- PA_CL_CLIP_CNTL (libSceAgcDriver) -
DX_LINEAR_ATTR_CLIP_ENA(bit 24) clear is drawn like bit 24 set, with Vulkan's clipping ofNoPerspectiveoutputs; what a clear bit changes on the console is undocumented. - v_rcp, v_rsq, v_sqrt, v_log, v_exp, v_sin and v_cos (f32 and f16) use the driver's approximation for finite results, not the console's: the low bits can differ. Only NaN, invalid, zero and infinite results and the exact sin/cos zeros are chosen on the bits. v_sin_f32/v_cos_f32 with inputs beyond ±256 cycles were not compared with the console.
--to-inteldoes not lower RDPRU/MCOMMIT; the matcher fails the relink instead. SHA-1 and SHA-256 instructions with a RIP-relative operand fail the relink.- The length-changing path of the instruction rewriter is not used by the converter: it does not adjust VEX/0F38/0F3A RIP-relative operands, data-to-code references (relocations, FDEs, jump tables) or segment sizes, so every substitution keeps the instruction length.
- DB_SHADER_CONTROL.CONSERVATIVE_Z_EXPORT (libSceAgcDriver) becomes
DepthLess/DepthGreater. For a pixel shader that breaks the promise, the host driver decides whether its interpolated Z is depth-tested before shading; what the console does then was not measured. - The Linux placement of the
--to-intelstubs in the ELF patcher is covered only by a synthetic test. - The libc SSE4a trap emulation on Windows is superseded by
--to-inteland remains only until the relinked title has been verified without it. - DCC display buffers are presented only from uniform uncompressed or fast-clear keys; other keys, and register-clear keys over a pending image, throw. Keys are read as one byte per 256 bytes (the driver's model), not in the console's layout.
--to-intelguest module trampolines are covered only by a synthetic relinker test; no game title has been verified with them on Linux or Windows.--to-intelreplaces the approximate VEX.128 register forms of VRSQRTPS and VRCPPS with correctly rounded 1/sqrt(x) and 1/x, not with the AMD approximation: its tables are not public. Intel's approximation of 1/sqrt(1.0) is 0x3F7FF000, and two Newton-Raphson steps on it settle on 0.99999994 instead of 1.0; a renormalised identity quaternion then turns into a NaN axis in PPSA21564, which the console does not show. Refined results now reach the exact value; unrefined ones can still differ from the console in the low bits. Each site costs an out-of-line stub (two jumps, a spill below the red zone, SQRTPS/DIVPS). The 256-bit, scalar, legacy and memory forms keep the native instruction, as does a 4-byte site with no movable instruction after it for the jump (5 sites in PPSA21564).- sceKeyboardGetKey2Char (libSceKeyboard) translates only the 101-key (US) arrangement and throws for the 106-key (Japanese) one; Ctrl and Alt do not change the character.
- sceAudioOut2Set3DLatency and sceAudioOut2MasteringInit (libSceAudioOut) have no effect: there is no 3D rendering or mastering stage.
- sceImeKeyboardGetInfo (libSceIme) returns
0x80bc0023(no resource id) for every id while a keyboard is open, since the IME keyboard never reports a connected device. sceImeKeyboardSetMode validates the mode bits but the mode has no effect, as no IME keyboard events are delivered. - libSceAudiodec throws for the 24-bit PCM word size (
iBwPcm0): its sample layout is unknown. ATRAC9 decoding is covered only by configuration and error tests, as no ATRAC9 encoder is available for a fixture. - sceAjmDecMp3ParseFrame (libSceAjm.native) throws when the original file length is requested (
parse_oflnon-zero) for a layer other than III, for a CRC-protected frame, or for a VBRI header outside MPEG-1 stereo: shadPS4 looks for the tag after the CRC and after the side information, while LAME and FFmpeg place it without the CRC and VBRI always at byte 36. - The output modifier (
mul:2,mul:4,div:2) follows the hardware with the IEEE mode off and f32 denormals flushed, the LLVM graphics default; the shader's MODE register is not read, and the hardware ignores the modifier in the other modes. On f16 results it is ignored, as on the hardware while f16 denormals are enabled; with them flushed the hardware applies it. - Comparison sampling of a color texture (
image_sample_c/image_sample_c_lzon a texture that is not R32 float or R16 unorm) is emulated in the shader, since Vulkan compares only depth formats: the red channel is fetched, compared and, for bilinear filtering, blended (compare, then filter). Only 2D and 2D array views, float/unorm/snorm formats, wrap, clamp-to-edge and clamp-to-border addressing (border red 0 for the black borders, 1 for opaque white) and point or bilinear filtering at one level are implemented; half-border addressing, the border color table, gradients, LOD bias, offsets, LOD clamps, gathers, other dimensions, anisotropy and mip filtering throw. Under bilinear filtering, taps past a clamp-to-border edge compare the border value and blend with the texel taps, so results near the edge depend on the filter weights. AMD documentation does not say how a color format's reference is handled: it is clamped to [0, 1] for unorm and [-1, 1] for snorm, as Vulkan does for unorm depth, and not clamped for float. Bilinear weights are full float, not the hardware's fixed-point subtexel weights - libScePlayerInvitationDialog simulates dialog completion without displaying UI or sending invitations; its parameter ABI remains unverified.
- 64-bit LDS atomics (
ds_*_u64,ds_*_b64,ds_*_f64) read and write the two dwords under a workgroup lock stored after the guest LDS, as LDS is a 32-bit array without 64-bit atomics. They are atomic with respect to each other only: 32-bit accesses to the same dwords issued concurrently are not ordered by the lock. 64-bit GDS atomics throw.ds_min/max(_rtn)_f64andds_cmpst(_rtn)_f64follow the NaN and signed-zero rules measured for the f32 forms; the f64 forms were not measured on hardware. - wcsrtombs_s (libc) follows the console's
libc.prx, but a runtime-constraint violation only returns its error: the default handler there writes the message and a newline tostderrbefore returning, which is not done here. Conversion uses the C locale ofwcrtomb(MB_CUR_MAX1), so the path where a multibyte character does not fit the remaining space is not reached - Thread exit destructors (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only
_sceLibcInternalThreadDtorsruns them, asexitdoes, else they are dropped - sceFontOpenFontSet (libSceFont) opens only the primary file of a system font set. Characters the console takes from the set's other files (Hangul, Thai and Arabic in Japanese and Chinese sets, Arabic in European sets) are reported as unsupported glyphs. The console file names are those of the PS4 firmware; the names of the PS5-only JG2 sets (
0x1A......) are unknown, so they use the SSTJpPro files. When a console file is missing, an openly licensed substitute (Noto Sans, Noto Sans Mono, Noto Sans Thai, Noto Sans CJK) is loaded instead. It is not the system font: its metrics differ, so text width, line height and wrapping differ from the console. System font faces are loaded by FreeType in host memory, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for. - Font writing lines (libSceFont) -
sceFontCreateWritingLine,sceFontWritingLineWritesOrder,sceFontWritingLineRefersRenderStep,sceFontWritingLineGetRenderMetricsandsceFontWritingLineClearfollow KytyPS5: runs are placed left to right, each at the line's advance so far, with no spacing or adjustment. Only horizontal and left-to-right lines, writing attribute 0 and non-null run metrics are modelled; other values, the metrics of an empty line and unknown or null handles throw, since no reference gives their result or error code.sceFontWritingLineGetOrderingSpacestill throws (KytyPS5's values are placeholders). Lines are allocated on the host, not in the font memory - sceImeKeyboardGetResourceId (libSceIme) reports that no USB keyboard is connected (
0x80bc0004, as shadPS4 does) because IME keyboard events are not delivered to the handler, although libSceKeyboard exposes the host keyboard