mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-29 12:15:39 +00:00
fix(libSceSaveData.native): answer sceSaveDataCancel before initialization as measured in a PS5 payload
30 lines
19 KiB
Markdown
30 lines
19 KiB
Markdown
# libSceSaveData.native technical debt
|
|
|
|
### Silent stubs
|
|
|
|
- [sceSaveDataPrepare, sceSaveDataCommit](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) return success without looking at their arguments; what preparing and committing a mounted save do on a console is unknown. The same six titles call both; this counts tests of the result in the three instructions after each call. `sceSaveDataPrepare` has 11 call sites: PPSA01494, PPSA30839 and PPSA31162 test none of them there, PPSA03984 takes an error path when it is negative, PPSA34502 checks it at one of two sites and PPSA36591 at two of four. `sceSaveDataCommit` has 14: PPSA01494 and PPSA30839 test none, PPSA03984 and PPSA31162 check its sign, PPSA34502 checks it at all five sites and PPSA36591 at two of four. A failure code from either would change the save flow of the titles that check it, while the stubs keep all six on the success path.
|
|
|
|
### Unknown function info
|
|
|
|
- [sceSaveDataCreateTransactionResource, sceSaveDataDeleteTransactionResource](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - transaction resources return synthetic positive identifiers and validate initialization state; resource parameter validation and transactional rollback semantics on host filesystem storage are unknown. Nine of the ten local titles call `sceSaveDataCreateTransactionResource`, at 15 sites: ten pass a size of 0xC0000 (768 KiB), four pass 0 (PPSA03984, PPSA25286 and both PPSA34502 sites), and one PPSA18194 site passes a value loaded from a global
|
|
- [sceSaveDataPrepareForTransferring](../../../core/libs/prx/libSceSaveData.native/Export.cpp): the native wrapper confirms the same 16-byte mount point and 40-byte preparation parameter transport as `sceSaveDataPrepare`. Transfer preparation still requires the save-data service backend; its protected stub is unchanged.
|
|
- [sceSaveDataTransferringMountPs4, sceSaveDataDirNameSearchPs4](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - arguments assumed to be those of `sceSaveDataTransferringMount` and `sceSaveDataDirNameSearch`: KytyPS5 binds both NIDs to the PS5 functions, and [prosper](https://github.com/mattias800/prosper) captured the same result layout on a title for the search. There is no PS4 save area, so the mount returns `NOT_FOUND` and the search reports zero hits
|
|
- [sceSaveDataConvert](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - the parameter block (user id at `+0x00`, `SceSaveDataDirName` pointer at `+0x08`, 48 opaque bytes after it) is read from PPSA28416's single call, not confirmed by KytyPS5, shadPS4, fpPS4 or SharpProspero, which have no body for it. Host saves have no size limit, so an existing save returns `SCE_OK` without touching its files and queues a successful type-5 completion event with the user and directory; PPSA03671 polls for this event after conversion. What the console returns for a save that is mounted, already converted or needs no conversion is unknown. The directory name is validated as `sceSaveDataDelete` does
|
|
- [sceSaveDataGetConvertProgress](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - imported by PPSA16064; signature and error codes follow the [SDK 12.000 reference](https://github.com/peterpuppy/bm/blob/3f9d1ba6b896a53080460c903f5c15af8affb80d/features/ps5/document/output/psn_12/System/Save_Data/SaveData-Reference/sce-save-data-get-convert-progress.md) (`float* progress`). Save data conversion on host filesystems completes synchronously, so the progress query returns `SAVE_DATA_OK` with the last conversion's progress (`0.0f` before any conversion or when conversion fails, `1.0f` after successful conversion), `SAVE_DATA_ERROR_PARAMETER` if `progress` is null, or `SAVE_DATA_ERROR_NOT_INITIALIZED` when the library is uninitialized; intermediate asynchronous conversion progress on console is unmeasured
|
|
- [sceSaveDataCancel](../../../core/libs/prx/libSceSaveData.native/Export.cpp): throws once the library is initialized. The native wrapper forwards one 32-bit argument to the save-data service; that argument's meaning and the cancellation results are unknown. Before initialization the console's `sceSaveDataCancel` returned `0x809f0001` (not initialized) for each argument measured, 0, 1, 2 and 0xffffffff, in a payload process on a PS5 (firmware 12.70). `sceSaveDataInitialize3(NULL)` produced no result in that payload process (it hung or ended the process), so the initialized case was not measured
|
|
- [sceSaveDataDirNameSearch](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - the sort keys (0 directory name, 1 user parameter, 2 blocks, 3 modification time, 5 free blocks) and orders (0 ascending, 1 descending) follow shadPS4, not a hardware run; saves with equal keys keep directory-name order before a descending reverse. The search infos (blocks, free blocks and 32 reserved bytes per returned name) follow shadPS4's `OrbisSaveDataSearchInfo`. Keys other than 0, 1, 2, 3 and 5 (including 4) and orders above 1 return `SCE_SAVE_DATA_ERROR_PARAMETER`; shadPS4 and KytyPS5 only reject keys above 5, so key 4 is rejected here because no source names it. In the directory name pattern `%` matches any run of characters, none included, and `_` exactly one, as the comments of shadPS4's matcher describe; also not confirmed on hardware
|
|
- [sceSaveDataDirNameSearch, sceSaveDataGetMountInfo, sceSaveDataMount3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - the 64 KiB block of [SharpEmu](https://github.com/sharpemu/sharpemu/blob/c6d304cc3328bad62cb671327ace181110cf2ddb/src/SharpEmu.Libs/SaveData/SaveDataExports.cs#L82-L84) and the 48 to 16384-block range of SharpEmu and [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/569ec04d1a77127c601eed522ad5bba187173f9d/src/libs/libSaveData.cpp#L30-L31) are not measured on a console, and file system overhead is not counted. What the console does with a `blocks` outside that range is unknown: KytyPS5 rejects the creating mount and SharpEmu clamps it; here a larger one is kept as 16384 and a smaller non-zero one as given. A save's size is the `blocks` of the mount that created it, kept in `<dir>.blocks`, else that of its next mount that names one, else 16384; its free blocks are that size less its files, each rounded up to 64 KiB blocks
|
|
- [sceSaveDataInitialize3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (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 `sceSaveDataTerminate` ends the session at the last one; how the console pairs them is unknown. In PPSA12544 the executable calls it once (0x1721d8f) with 0 as its argument, only while a flag byte of its object is 0, and does not import `sceSaveDataTerminate`; the plugin calls it once (0x1fd2) with 0, skips the call while a flag byte of its own is set, and calls `sceSaveDataTerminate` from two functions (0x2059, 0x20d9) that clear that byte. Of 53 local titles, all import and call it and 28 import `sceSaveDataTerminate` (25 do not); counting tail jumps as calls and ignoring indirect calls, 17 of those 28 call both once, 10 call both twice and 1 calls it once and `sceSaveDataTerminate` twice.
|
|
- [sceSaveDataCheckIpmiIfSize, sceSaveDataDebug, sceSaveDataDebugCheckBackupData, sceSaveDataDebugCleanMount, sceSaveDataDebugCompiledSdkVersion, sceSaveDataDebugCreateSaveDataRoot, sceSaveDataDebugProspero, sceSaveDataDebugRemoveSaveDataRoot and sceSaveDataDebugTarget](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - names and NIDs are present in the [PS5 3.20 export inventory](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceSaveData.native.c). The seven no-argument prototypes follow the PS4 stubs in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/f68923fe807f657348e6719ce658bcbd0a2b1c72/src/core/libraries/save_data/savedata.cpp#L653-L725), not measured on a console; no credible prototypes were found for the other two. All declarations have no parameters solely to resolve known imports and make no ABI claim.
|
|
- The following pending declarations have unverified signatures and behavior; they are parameterless import-resolution declarations and throw through `NotImplemented_nid_no_patch`: [`sceSaveDataAbort`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataBindPsnAccount`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataBindPsnAccountForSystemBackup`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataChangeDatabase`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataChangeInternal`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckBackupData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckBackupDataForCdlg`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckBackupDataInternal`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckBackupDataLight`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckCloudData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckSaveDataBroken`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckSaveDataVersion`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCheckSaveDataVersionLatest`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataClearProgress`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataCreateUploadData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDebugGetThreadId`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteAllUser`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteBackupData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteCloudData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteProspero`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteTitle`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDeleteUser`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDirNameSearchInternal`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataDownload`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetAllSize`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetAppLaunchedUser`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetAutoUploadConditions`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetAutoUploadRequestInfo`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetAutoUploadSetting`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetBoundPsnAccountCount`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetClientThreadPriority`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetCloudQuotaInfo`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetEventInfo`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetMountedSaveDataCount`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetProgress`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetSaveDataCount`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetSaveDataRootDir`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetSaveDataRootPath`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetSaveDataRootUsbPath`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetSavePoint`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataGetUpdatedDataCount`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataInitialize2`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataInitializeForCdlg`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataIsDeletingUsbDb`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataIsMounted`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataManualDelete`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataManualDownload`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataManualUpload`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataMount5`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataMountInternal`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataMountSys`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataRebuildDatabase`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataRegisterEventCallback`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataRestoreBackupData`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataRestoreBackupDataForCdlg`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataRestoreLoadSaveDataMemory`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataSetAutoUploadSetting`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataSetEventInfo`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataSetSaveDataLibraryUser`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataShutdownStart`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataSupportedFakeBrokenStatus`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataSyncCloudList`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataUmountSys`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataUmountWithBackup`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataUnregisterEventCallback`](../../../core/libs/prx/libSceSaveData.native/Export.cpp), [`sceSaveDataUpload`](../../../core/libs/prx/libSceSaveData.native/Export.cpp).
|
|
|
|
### Functional
|
|
|
|
- [sceSaveDataDirNameSearch, sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - only the running title's saves are kept, so a search with another title's `title_id` reports zero hits, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/ec334904604ba41f5d4753f4a2498ec82540e5d6/src/core/libraries/save_data/savedata.cpp#L791-L802) and [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/569ec04d1a77127c601eed522ad5bba187173f9d/src/libs/libSaveData.cpp#L592-L596) do when that title has no save directory; what a console returns for another title's saves is not verified. The running title's ID is the `titleId` in its `param.json`
|
|
- [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) runs the same search as `sceSaveDataDirNameSearch` with the same condition and result structures, as [SharpEmu](https://github.com/sharpemu/sharpemu/blob/main/src/SharpEmu.Libs/SaveData/SaveDataExports.cs) does, its only source; what distinguishes it on the console is unknown. One title (PPSA35669, in a plugin) disassembled for this entry has one call site (0x2eda71); it clears 56 bytes for the result structure first (the size of the structure used here), puts a value returned by a call with the argument 0x8000 at offset 8 and 0x400 at offset 0x10, and afterwards branches on a negative result and reads the 32-bit field at offset 0, skipping its loop when it is 0. That agrees with the result structure of `sceSaveDataDirNameSearch`. The condition structure was not read.
|
|
- [sceSaveDataMount3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - a failed mount (BUSY, EXISTS, NOT_FOUND, MOUNT_FULL) leaves the result as it was, as shadPS4 does; not checked on hardware. Animal Well (PPSA22520) depends on it: it checks for its save with a mount it never unmounts, then saves with a second mount of the same directory, ignores its BUSY and keeps using the first mount point for `sceSaveDataPrepare`, its file and `sceSaveDataUmount2`. In PPSA05347 the function that calls it at 0x235fbb5 zeroes its 0x40-byte result before the call and, for a negative result other than 0x809f0008 and 0x809f000f (BUSY included), logs the code and returns it without recording the mount; no abort follows.
|
|
- [sceSaveDataMount3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - an unterminated or empty directory name, `.`, `..`, or a name containing `/`, `\` or `:` returns `SAVE_DATA_ERROR_PARAMETER`, which the [SDK 12.000 reference](https://github.com/peterpuppy/bm/blob/3f9d1ba6b896a53080460c903f5c15af8affb80d/features/ps5/document/output/psn_12/System/Save_Data/SaveData-Reference/sce-save-data-mount3.md#L196-L204) lists for an invalid parameter, and leaves the result as it was, as [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/569ec04d1a77127c601eed522ad5bba187173f9d/src/libs/libSaveData.cpp#L652-L658) does. The [SDK](https://github.com/peterpuppy/bm/blob/3f9d1ba6b896a53080460c903f5c15af8affb80d/features/ps5/document/output/psn_12/System/Save_Data/SaveData-Reference/sce-save-data-dir-name.md#L32-L36) lets an application use only letters, digits, `-`, `.` and `@` in a name, and KytyPS5 also accepts `_` ([`valid_path_component`](https://github.com/KytyPS5/KytyPS5/blob/569ec04d1a77127c601eed522ad5bba187173f9d/src/libs/libSaveData.cpp#L276-L287)); which other names the console's mount rejects is not checked on hardware
|
|
- [sceSaveDataBackup, sceSaveDataConvert, sceSaveDataDelete, sceSaveDataDirNameSearch, sceSaveDataDirNameSearchPs4, sceSaveDataGetEventResult, sceSaveDataGetMountInfo, sceSaveDataGetParam, sceSaveDataLoadIcon, sceSaveDataMount, sceSaveDataMount3, sceSaveDataSaveIcon, sceSaveDataSetParam, sceSaveDataUmount2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - null pointer arguments return `SAVE_DATA_ERROR_PARAMETER` instead of throwing C++ exceptions, an implementation assumption matching guest error expectations not checked on hardware; unmounted targets return `SAVE_DATA_ERROR_NOT_MOUNTED`, and parameter type or buffer size violations return `SAVE_DATA_ERROR_PARAMETER` after slot lookup
|
|
|
|
- [sceSaveDataSyncSaveDataMemory](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - validates library initialization and parameters; since in-memory saves flush synchronously on write, sync confirms existence and readiness of the memory blob
|