feat(exports): export the calls PPSA01317 imports

Gran Turismo 7 (PPSA01317) fails to load on unresolved imports and on
two needed libraries that AnyPS5 does not build (#4782).

- sceAppContentDownloadDataFormat empties /download0, as
  sceAppContentTemporaryDataFormat does for /temp0.
- sceNpAuthSetTimeout returns REQUEST_NOT_FOUND for an unknown request
  like the other request calls, and OK otherwise; no request reaches the
  network the timeouts would bound.
- sceNpWebApi2PushEventSetHandleTimeout throws for an unknown library
  context, like sceNpWebApi2GetMemoryPoolStats, and returns OK
  otherwise; push event handles are not tracked and nothing waits on
  one offline.
- sceSslDisableVerifyOption, sceSslGetAlpnSelected, sceSslSetAlpn,
  sceSslSetMinSslVersion, sceAudioOutDeviceIdOpen and the unnamed
  libScePsml NIDs xNZM9Y5lf-M and lcZD9tJraAw are declared without
  parameters and throw; their signatures are unknown.
- libSceUsbStorage and libSceUsbStorageDialog exist with no exports,
  like libSceXml: the title lists both as needed but imports nothing
  from them.

Each assumption is recorded in the library's technical debt file.

Co-authored-by: dawid-swiecicki <8942606+dawid-swiecicki@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
GoodTimeclubs 2026-10-13 01:08:10 +02:00
parent 90c683946f
commit 8a7e1195d4
17 changed files with 113 additions and 0 deletions

View File

@ -93,6 +93,15 @@ int APS5_VABI sceAppContentAppParamGetInt(uint32_t param_id, int32_t* value) {
}
}
int APS5_VABI sceAppContentDownloadDataFormat(const AppContentMountPoint* mount_point) {
if (!mount_point) return SCE_APP_CONTENT_ERROR_PARAMETER;
if (std::strncmp(mount_point->data, DOWNLOAD_MOUNT_POINT, sizeof(mount_point->data)) != 0) APS5_INVALID_ARG_EX;
const auto directory = ResolvePath_nid_no_patch(DOWNLOAD_MOUNT_POINT);
if (std::filesystem::create_directories(directory)) RecordWrittenPath_nid_no_patch(directory);
ClearDirectory(directory);
return 0;
}
int APS5_VABI sceAppContentDownloadDataGetAvailableSpaceKb(const AppContentMountPoint* mount_point, size_t* available_space_kb) {
if (!available_space_kb) return SCE_APP_CONTENT_ERROR_PARAMETER;
if (!mount_point || std::strncmp(mount_point->data, DOWNLOAD_MOUNT_POINT, sizeof(mount_point->data)) != 0) APS5_INVALID_ARG_EX;

View File

@ -499,6 +499,11 @@ int APS5_VABI sceAudioOutGetPortState(int handle, AudioOutPortState* state) {
return 0;
}
int APS5_VABI sceAudioOutDeviceIdOpen() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAudioOutSysClose() {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -110,6 +110,16 @@ int APS5_VABI sceNpAuthPollAsync(int req_id, int* result) {
return NP_POLL_ASYNC_FINISHED;
}
int APS5_VABI sceNpAuthSetTimeout(int req_id, int resolve_retry, uint32_t resolve_timeout, uint32_t connect_timeout, uint32_t send_timeout, uint32_t receive_timeout) {
(void)resolve_retry;
(void)resolve_timeout;
(void)connect_timeout;
(void)send_timeout;
(void)receive_timeout;
std::lock_guard lock(g_requestMutex);
return g_requests.contains(req_id) ? 0 : ORBIS_NP_AUTH_ERROR_REQUEST_NOT_FOUND;
}
int APS5_VABI sceNpAuthWaitAsync(int req_id, int* result) {
if (!result) return ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT;
std::lock_guard lock(g_requestMutex);

View File

@ -174,6 +174,14 @@ int APS5_VABI sceNpWebApi2PushEventDeleteFilter() {
return 0;
}
int APS5_VABI sceNpWebApi2PushEventSetHandleTimeout(int lib_ctx_id, int handle_id, uint32_t timeout) {
(void)handle_id;
(void)timeout;
std::lock_guard lock(g_poolsMutex);
if (!g_pools.contains(lib_ctx_id)) throw std::invalid_argument("sceNpWebApi2PushEventSetHandleTimeout: unknown context");
return 0;
}
int APS5_VABI sceNpWebApi2PushEventRegisterPushContextCallback() {
return g_nextHandle.fetch_add(1, std::memory_order_relaxed);
}

View File

@ -155,4 +155,16 @@ int APS5_VABI scePsmlMfsr2Init() {
return 0;
}
APS5_EXPORT("xNZM9Y5lf-M", scePsmlUnknown01);
int APS5_VABI scePsmlUnknown01(void) {
NotImplemented_nid_no_patch("xNZM9Y5lf-M");
return 0;
}
APS5_EXPORT("lcZD9tJraAw", scePsmlUnknown02);
int APS5_VABI scePsmlUnknown02(void) {
NotImplemented_nid_no_patch("lcZD9tJraAw");
return 0;
}
}

View File

@ -134,6 +134,26 @@ int APS5_VABI sceSslFreeSslCertName(void) {
return 0;
}
int APS5_VABI sceSslDisableVerifyOption(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceSslGetAlpnSelected(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceSslSetAlpn(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceSslSetMinSslVersion(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceSslGetIssuerName(void) {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -0,0 +1,10 @@
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
APS5_DUMMY_FUN
}

View File

@ -0,0 +1,10 @@
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
APS5_DUMMY_FUN
}

View File

@ -19,6 +19,7 @@ int* APS5_VABI __error_nid_postfix();
int APS5_VABI sceAppContentGetAddcontInfo(uint32_t, const NpUnifiedEntitlementLabel*, void*);
int APS5_VABI sceAppContentGetAddcontInfoList(uint32_t, void*, uint32_t, uint32_t*);
int APS5_VABI sceAppContentDownloadDataGetAvailableSpaceKb(const AppContentMountPoint*, size_t*);
int APS5_VABI sceAppContentDownloadDataFormat(const AppContentMountPoint*);
int APS5_VABI sceAppContentAppParamGetInt(uint32_t, int32_t*);
}
@ -47,6 +48,16 @@ int main() {
Require(sceAppContentDownloadDataGetAvailableSpaceKb(&download, &availableKb) == 0);
Require(availableKb == 0);
Require(sceAppContentDownloadDataGetAvailableSpaceKb(&download, nullptr) == ErrorParameter);
const auto downloadData = ResolvePath_nid_no_patch("/download0");
Require(sceAppContentDownloadDataFormat(&download) == 0);
Require(std::filesystem::is_directory(downloadData) && std::filesystem::is_empty(downloadData));
std::filesystem::create_directory(downloadData / "cache");
{ std::ofstream file(downloadData / "cache" / "old.bin"); file << "downloaded"; }
{ std::ofstream file(downloadData / "index.dat"); file << "downloaded"; }
Require(sceAppContentDownloadDataFormat(nullptr) == ErrorParameter);
Require(std::filesystem::exists(downloadData / "index.dat"));
Require(sceAppContentDownloadDataFormat(&download) == 0);
Require(std::filesystem::is_directory(downloadData) && std::filesystem::is_empty(downloadData));
const int32_t expectedParams[] = {3, 23566, -7, 0, 2147483647};
for (uint32_t id = 0; id < 5; ++id) {

View File

@ -11,6 +11,7 @@ int APS5_VABI sceNpAuthDeleteRequest(int req_id);
int APS5_VABI sceNpAuthGetAuthorizationCodeV3(int req_id, const void* param, void* auth_code, int* issuer_id);
int APS5_VABI sceNpAuthGetIdTokenV3(int req_id, const void* param, void* id_token);
int APS5_VABI sceNpAuthPollAsync(int req_id, int* result);
int APS5_VABI sceNpAuthSetTimeout(int req_id, int resolve_retry, uint32_t resolve_timeout, uint32_t connect_timeout, uint32_t send_timeout, uint32_t receive_timeout);
int APS5_VABI sceNpAuthWaitAsync(int req_id, int* result);
}
@ -42,6 +43,9 @@ int main() {
alignas(8) char authCode[16] = {};
int issuerId = 0;
Require(sceNpAuthSetTimeout(syncReq, 2, 5000000, 10000000, 10000000, 10000000) == 0);
Require(sceNpAuthSetTimeout(asyncReq, 0, 0, 0, 0, 0) == 0);
int pollUnprocessed = 0;
Require(sceNpAuthPollAsync(asyncReq, &pollUnprocessed) == invalidId);
int waitUnprocessed = 0;
@ -79,6 +83,7 @@ int main() {
Require(sceNpAuthPollAsync(unknownReq, &pollResult) == requestNotFound);
int waitResult = 0;
Require(sceNpAuthWaitAsync(unknownReq, &waitResult) == requestNotFound);
Require(sceNpAuthSetTimeout(unknownReq, 2, 5000000, 10000000, 10000000, 10000000) == requestNotFound);
Require(sceNpAuthWaitAsync(syncReq, nullptr) == invalidArgument);
Require(sceNpAuthWaitAsync(syncReq, &waitResult) == invalidId);
@ -99,6 +104,7 @@ int main() {
Require(sceNpAuthDeleteRequest(syncReq) == 0);
Require(sceNpAuthGetIdTokenV3(syncReq, param, token) == requestNotFound);
Require(sceNpAuthWaitAsync(syncReq, &waitResult) == requestNotFound);
Require(sceNpAuthSetTimeout(syncReq, 2, 5000000, 10000000, 10000000, 10000000) == requestNotFound);
return 0;
}

View File

@ -15,6 +15,8 @@ extern "C" {
int APS5_VABI sceNpWebApi2Initialize(int, std::size_t);
int APS5_VABI sceNpWebApi2Terminate(int);
int APS5_VABI sceNpWebApi2GetMemoryPoolStats(int, NpWebApi2MemoryPoolStats*);
int APS5_VABI sceNpWebApi2PushEventCreateHandle(int);
int APS5_VABI sceNpWebApi2PushEventSetHandleTimeout(int, int, std::uint32_t);
}
static void Require(bool value) { if (!value) std::abort(); }
@ -38,8 +40,12 @@ int main() {
Require(stats.pool_size == 0x20000 && stats.max_inuse_size == 0 && stats.current_inuse_size == 0 && stats.reserved == 0);
Require(sceNpWebApi2GetMemoryPoolStats(other, &stats) == 0 && stats.pool_size == 0x8000);
Require(Throws([&] { sceNpWebApi2GetMemoryPoolStats(context, nullptr); }));
const int handle = sceNpWebApi2PushEventCreateHandle(context);
Require(handle > 0);
Require(sceNpWebApi2PushEventSetHandleTimeout(context, handle, 30000) == 0);
Require(sceNpWebApi2Terminate(context) == 0);
Require(Throws([&] { sceNpWebApi2GetMemoryPoolStats(context, &stats); }));
Require(Throws([&] { sceNpWebApi2PushEventSetHandleTimeout(context, handle, 30000); }));
Require(sceNpWebApi2Terminate(other) == 0);
return 0;
}

View File

@ -4,6 +4,7 @@
- [sceAppContentDownloadDataGetAvailableSpaceKb](../../../core/libs/prx/libSceAppContent/Export.cpp) (libSceAppContent) - a title whose `param.json` declares `downloadDataSize` 0 gets 0 KB and OK; the console's behaviour for a title without a download data area is unverified (it may return an error instead). KytyPS5 does not special-case it, and shadPS4 stubs 1048576 KB
- [sceAppContentGetAddcontDownloadProgress](../../../core/libs/prx/libSceAppContent/Export.cpp) (libSceAppContent) - imported by PPSA08755, which fails to load without it; added without an implementation because its behavior is unverified. [SharpProspero](https://github.com/SvenGDK/SharpProspero) lists `(uint32_t serviceLabel, entitlementLabel, SceAppContentAddcontDownloadProgress*)`, but no PS5 reference gives the progress layout or the error codes
- [sceAppContentDownloadDataFormat](../../../core/libs/prx/libSceAppContent/Export.cpp) (libSceAppContent) - empties the `/download0` directory, creating it if needed. Imported by PPSA01317. A null mount point returns `PARAMETER` as `sceAppContentTemporaryDataFormat` does, and another mount point throws as in `sceAppContentDownloadDataGetAvailableSpaceKb`; the console's error codes for both and its behaviour with files still open are unverified
### Functional

View File

@ -15,6 +15,7 @@
- [sceAudioOut2PortCreate](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (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](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (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
- [sceAudioOut2PortSetAttributes](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (libSceAudioOut) - each PCM buffer set (attribute 0) is taken as one grain: buffers set between two pushes are queued and played one per grain, at most 16 queued. A grain with no new buffer repeats the last one only when the port has always been given that same buffer (rewritten in place); a port whose buffers move on plays silence instead. Inferred from PPSA12544, whose object port (type 6) is given one grain of a 64-grain ring per set, often two or three between pushes and then none for a few; the console behaviour for several sets per push and for a push without a new buffer is not documented
- [sceAudioOutDeviceIdOpen](../../../core/libs/prx/libSceAudioOut/src/AudioOut.cpp) (libSceAudioOut) - imported by PPSA01317, which fails to load without it; declared without parameters, signature unknown. It opens a port on a given audio device; which device ids exist and how they map to host outputs is unknown, so it throws
### Functional

View File

@ -4,3 +4,4 @@
- [sceNpAuthGetAuthorizedAppCode](../../../core/libs/prx/libSceNpAuth/Export.cpp) (libSceNpAuth) - declared without parameters and returns `SCE_NP_ERROR_SIGNED_OUT` without reading them, as there is no PSN sign-in; the request parameter and code output are not known. Minecraft (PPSA17221) imports it, fails to load without it, and after its sign-in dialog treats the signed-out code as offline play.
- [sceNpAuthAbortRequest, sceNpAuthGetAuthorizationCodeV3, sceNpAuthGetIdTokenV3, sceNpAuthPollAsync, sceNpAuthWaitAsync](../../../core/libs/prx/libSceNpAuth/Export.cpp) (libSceNpAuth) - request tracking, `ORBIS_NP_AUTH_ERROR_REQUEST_NOT_FOUND` (0x80550306) on unknown request IDs, `ORBIS_NP_AUTH_ERROR_INVALID_ID` (0x80550307) on non-async or unprocessed requests in Poll/Wait, `ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT` (0x80550301) on null arguments and repeated calls on completed requests, and `ORBIS_NP_AUTH_ERROR_ABORTED` (0x80550304) after an abort follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/np/np_auth.cpp) (PS4); async requests return OK and defer `SCE_NP_ERROR_SIGNED_OUT` to `sceNpAuthPollAsync`/`sceNpAuthWaitAsync` while sync requests fail immediately; PlayStation Network is not contacted. The parameter `size` fields are not checked (`ORBIS_NP_AUTH_ERROR_INVALID_SIZE`, structure layouts unknown), the request table has no limit (`ORBIS_NP_AUTH_ERROR_REQUEST_MAX`), and console behavior on PS5 is unverified
- [sceNpAuthSetTimeout](../../../core/libs/prx/libSceNpAuth/Export.cpp) (libSceNpAuth) - imported by PPSA01317, which fails to load without it. The signature `(reqId, resolveRetry, resolveTimeout, connTimeout, sendTimeout, recvTimeout)` follows [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/np/np_auth.cpp) (PS4), which only stubs it. An unknown request ID returns `ORBIS_NP_AUTH_ERROR_REQUEST_NOT_FOUND` like the other request calls; otherwise it returns OK and keeps nothing, as no request reaches the network the timeouts would bound. Argument checks of the console are unverified

View File

@ -4,3 +4,4 @@
- [sceNpWebApi2PushEventAbortHandle](../../../core/libs/prx/libSceNpWebApi2/Export.cpp) (libSceNpWebApi2, NID `1OLgvahaSco`) is a throwing stub. The two signed 32-bit handle arguments and return type follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/443f022450f6857256e780daa3d5a14029a748f7/src/core/libraries/np/np_web_api2/np_web_api2.cpp) (PS4); the PS5 signature and abort behavior are unverified. PPSA01736 imports it.
- [sceNpWebApi2GetMemoryPoolStats](../../../core/libs/prx/libSceNpWebApi2/Export.cpp) (libSceNpWebApi2) - imported by PPSA21703's Unity PSN plugin. The signature `(int libCtxId, stats*)` and the layout of the Http2 statistics above (measured on a PS5 for Http2, Ssl and Net) are assumed for this library, not measured. The pool size is the one given to `sceNpWebApi2Initialize`, and the peak and current use are 0. The error codes are unknown, so a null output or an unknown context throws
- [sceNpWebApi2PushEventSetHandleTimeout](../../../core/libs/prx/libSceNpWebApi2/Export.cpp) (libSceNpWebApi2) - imported by PPSA01317, which fails to load without it. The signature `(int libCtxId, int handleId, uint32_t timeout)` follows `sceNpWebApiSetHandleTimeout` of the PS4 libSceNpWebApi in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/np/np_web_api.cpp) and is unverified on the PS5. An unknown library context throws, as in `sceNpWebApi2GetMemoryPoolStats`, since its error code is unknown. The handle is not checked, as push event handles are not tracked (`sceNpWebApi2PushEventDeleteHandle` accepts any handle), and the timeout is not kept, as nothing waits on a handle offline

View File

@ -6,3 +6,4 @@
- [scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100, scePsmlMfsrGetDispatchMfsrPacket1100](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_debug) - argument layouts unknown; only 0x8A810001 (not initialized) is returned
- [scePsmlMfsrGetDispatchMfsrPacket1000](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - unknown signature, imported by PPSA25344; declared without parameters. libScePsml and libScePsml_debug are built from the same source
- [scePsmlMfsrCreateContext1300, scePsmlMfsrGetDispatchMfsrPacket1300](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - unknown signatures, imported by PPSA28416 next to `scePsmlMfsrGetContextBufferRequirement1100`; declared without parameters. The names are not in the aerolib NID list; they hash to the imported NIDs `kLF7WtQ1-Dg` and `DDVUyPyYHTA` (`tools/nid_names.py`)
- [NIDs `xNZM9Y5lf-M` and `lcZD9tJraAw`](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_specularAA and libScePsml_quality8K, exported as `scePsmlUnknown01` and `scePsmlUnknown02`) - imported by PPSA01317, which fails to load without them; names and signatures unknown (not in the aerolib NID list), so they throw

View File

@ -5,6 +5,7 @@
- [sceSslClose](../../../core/libs/prx/libSceSsl/Export.cpp) (libSceSsl) - unknown signature
- [sceSslGetSerialNumber](../../../core/libs/prx/libSceSsl/Export.cpp) (libSceSsl) - unknown signature
- [sceSslGetCaList, sceSslFreeCaList, sceSslUnloadCert](../../../core/libs/prx/libSceSsl/Export.cpp) (libSceSsl) - signatures and the 16-byte `SceSslCaList` layout (an array of certificate handles and a 32-bit count) follow [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/5dfdb4b0b166e83dc9ae275001afb695f12c7174/src/SharpProspero/Interop/Net/Http.cs) and shadPS4's `OrbisSslCaList`, not confirmed for the PS5. On the console the list holds the certificate authorities the SSL service has; [shadPS4](https://github.com/shadps4-emu/shadPS4/pull/4104) returns a placeholder certificate from `sceSslGetCaCerts` because Rise of the Tomb Raider fails its initialization checks without one. No root certificate bundle is shipped and no loaded certificate is kept, so here a context holds none: `sceSslGetCaList` clears the list and returns `NOT_FOUND`, as `sceSslGetCaCerts` does, `sceSslFreeCaList` accepts only that cleared list, and `sceSslUnloadCert` (imported by PPSA15508) has nothing to drop and is assumed to return 0. A null list returns `0x8095177A`, which `sceSslGetCaCerts` and [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/59183dbfa81ed7efdff6069177fed50de0552725/src/libs/network.cpp) return for a null argument (shadPS4, PS4, returns `0x8095F007`). An unknown context throws (KytyPS5 returns `SSL_ERROR_INVALID_ID`, `0x8095F006`, from `sceSslGetCaCerts`), and so does a list `sceSslGetCaList` did not return
- PPSA01317 imports declared without parameters, signatures unknown: [sceSslDisableVerifyOption, sceSslGetAlpnSelected, sceSslSetAlpn, sceSslSetMinSslVersion](../../../core/libs/prx/libSceSsl/Export.cpp) (libSceSsl). They act on a connection, which `sceSslCreateConnection` does not create yet, so they throw until connections exist
### Functional