From 9c2a75601deec10a2dba1eadd74a89f342d5e793 Mon Sep 17 00:00:00 2001 From: devilismyfriend <87043616+devilismyfriend@users.noreply.github.com> Date: Fri, 25 Sep 2026 16:27:49 -0700 Subject: [PATCH] feat(libs): agc packet builders, savedata memory, offline service stubs - libSceAgc: SetIndexCount, SetBaseIndirectArgs, DispatchIndirect, wait and write-data patch functions, relaxed checks for what titles send, NOP fillers for LOD stats and wait-until-safe, NotImplemented stubs. - libSceSaveData.native: short mount points, backup events, save-data memory slots. - user/system service, store dialog, video-out flip modes and queue-full error, pad read, fibers, offline behaviour for network/NP modules, and new export-only modules Ampr, JpegEnc, Json2, MsgDialog.native, NpCppWebApi, NpUtility. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo --- core/libs/prx/libSceAcm/Export.cpp | 58 +- core/libs/prx/libSceAgc/Acb/src/Control.cpp | 15 +- core/libs/prx/libSceAgc/Acb/src/Dispatch.cpp | 10 +- core/libs/prx/libSceAgc/CMakeLists.txt | 1 + core/libs/prx/libSceAgc/Cb/src/Dispatch.cpp | 2 +- core/libs/prx/libSceAgc/Cb/src/Sync.cpp | 12 +- .../libs/prx/libSceAgc/Command/src/Memory.cpp | 8 +- .../libs/prx/libSceAgc/Command/src/Packet.cpp | 5 +- .../prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp | 8 +- .../prx/libSceAgc/DcbDraw/src/Instancing.cpp | 16 +- core/libs/prx/libSceAgc/DcbDraw/src/Stats.cpp | 5 +- .../prx/libSceAgc/DcbFlow/src/Control.cpp | 8 +- .../prx/libSceAgc/DcbFlow/src/Dispatch.cpp | 8 +- .../libs/prx/libSceAgc/DcbFlow/src/Memory.cpp | 11 +- .../prx/libSceAgc/DcbState/src/Marker.cpp | 52 +- .../prx/libSceAgc/Patch/src/WaitRegMem.cpp | 14 +- core/libs/prx/libSceAgc/Unimplemented.cpp | 172 ++++ core/libs/prx/libSceAjm/Export.cpp | 2 +- core/libs/prx/libSceAjmi/Export.cpp | 2 +- core/libs/prx/libSceAmpr/Export.cpp | 335 ++++++++ core/libs/prx/libSceAppContent/Export.cpp | 28 +- core/libs/prx/libSceCesCs/Export.cpp | 2 +- core/libs/prx/libSceFiber/Export.cpp | 425 ++++++++-- core/libs/prx/libSceFont.native/Export.cpp | 2 +- core/libs/prx/libSceFont/Export.cpp | 2 +- core/libs/prx/libSceGameUpdate/Export.cpp | 31 +- core/libs/prx/libSceHttp/Export.cpp | 269 +++---- core/libs/prx/libSceHttp2/Export.cpp | 249 +++--- core/libs/prx/libSceJpegEnc/Export.cpp | 28 + core/libs/prx/libSceJson2/Export.cpp | 37 + .../prx/libSceMsgDialog.native/Export.cpp | 10 + core/libs/prx/libSceNet/Export.cpp | 356 ++++++--- core/libs/prx/libSceNetCtl/Export.cpp | 73 +- core/libs/prx/libSceNpCommerce/Export.cpp | 57 +- core/libs/prx/libSceNpCppWebApi/Export.cpp | 745 ++++++++++++++++++ .../prx/libSceNpEntitlementAccess/Export.cpp | 39 +- core/libs/prx/libSceNpManager/Export.cpp | 105 ++- .../prx/libSceNpSessionSignaling/Export.cpp | 40 +- core/libs/prx/libSceNpUtility/Export.cpp | 10 + core/libs/prx/libSceNpWebApi2/Export.cpp | 175 ++-- core/libs/prx/libScePad/Export.cpp | 12 +- core/libs/prx/libScePlayGo/Export.cpp | 189 +++-- core/libs/prx/libScePngEnc/Export.cpp | 28 + core/libs/prx/libScePsml_debug/Export.cpp | 86 ++ .../libs/prx/libSceSaveData.native/Export.cpp | 148 +++- core/libs/prx/libSceShare.native/Export.cpp | 59 +- core/libs/prx/libSceShare/Export.cpp | 88 +++ core/libs/prx/libSceSsl/Export.cpp | 22 +- core/libs/prx/libSceSystemGesture/Export.cpp | 67 +- core/libs/prx/libSceSystemService/Export.cpp | 24 +- core/libs/prx/libSceUserService/Export.cpp | 43 +- core/libs/prx/libSceVideoOut/CMakeLists.txt | 1 + .../libs/prx/libSceVideoOut/Unimplemented.cpp | 20 + .../libSceVideoOut/include/VideoOutDriver.hpp | 3 +- core/libs/prx/libSceVideoOut/src/Buffer.cpp | 9 +- core/libs/prx/libSceVideoOut/src/Output.cpp | 9 +- .../prx/libSceVideoOut/src/VideoOutDriver.cpp | 32 +- 57 files changed, 3328 insertions(+), 939 deletions(-) create mode 100644 core/libs/prx/libSceAgc/Unimplemented.cpp create mode 100644 core/libs/prx/libSceAmpr/Export.cpp create mode 100644 core/libs/prx/libSceJpegEnc/Export.cpp create mode 100644 core/libs/prx/libSceJson2/Export.cpp create mode 100644 core/libs/prx/libSceMsgDialog.native/Export.cpp create mode 100644 core/libs/prx/libSceNpCppWebApi/Export.cpp create mode 100644 core/libs/prx/libSceNpUtility/Export.cpp create mode 100644 core/libs/prx/libScePngEnc/Export.cpp create mode 100644 core/libs/prx/libScePsml_debug/Export.cpp create mode 100644 core/libs/prx/libSceShare/Export.cpp create mode 100644 core/libs/prx/libSceVideoOut/Unimplemented.cpp diff --git a/core/libs/prx/libSceAcm/Export.cpp b/core/libs/prx/libSceAcm/Export.cpp index 1a3910163..db47c5fea 100644 --- a/core/libs/prx/libSceAcm/Export.cpp +++ b/core/libs/prx/libSceAcm/Export.cpp @@ -2,47 +2,55 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// Audio co-processor batches complete immediately without producing output; audio is silent. +static constexpr int SCE_ACM_ERROR_INVALID_PARAMETER = static_cast(0x80E30002); +static std::atomic g_nextId{1}; extern "C" { int APS5_VABI sceAcmBatchStartBuffer(AcmContextId context, const void* batch_commands, size_t batch_size, AcmBatchError* batch_error, AcmBatchId* batch) { - (void)context; - (void)batch_commands; - (void)batch_size; - (void)batch_error; - (void)batch; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)context; + (void)batch_commands; + (void)batch_size; + (void)batch_error; + if (!batch) return SCE_ACM_ERROR_INVALID_PARAMETER; + *batch = g_nextId.fetch_add(1, std::memory_order_relaxed); + return 0; } int APS5_VABI sceAcmBatchStartBuffers(AcmContextId context, uint32_t batch_info_count, const AcmBatchInfo* const batch_info[], AcmBatchError* batch_error, AcmBatchId* batch) { - (void)context; - (void)batch_info_count; - (void)batch_info; - (void)batch_error; - (void)batch; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)context; + (void)batch_info_count; + (void)batch_info; + (void)batch_error; + if (!batch) return SCE_ACM_ERROR_INVALID_PARAMETER; + *batch = g_nextId.fetch_add(1, std::memory_order_relaxed); + return 0; } int APS5_VABI sceAcmBatchWait(AcmContextId context, AcmBatchId batch, uint32_t timeout) { - (void)context; - (void)batch; - (void)timeout; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)context; + (void)batch; + (void)timeout; + return 0; } int APS5_VABI sceAcmContextCreate(AcmContextId* context) { - (void)context; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!context) return SCE_ACM_ERROR_INVALID_PARAMETER; + *context = g_nextId.fetch_add(1, std::memory_order_relaxed); + return 0; } int APS5_VABI sceAcmContextDestroy(AcmContextId context) { - (void)context; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)context; + return 0; +} + +// Builds a convolution-reverb command into a batch; batches execute as no-ops, so nothing is encoded. +int APS5_VABI sceAcm_ConvReverb_SharedInput(void) { + return 0; } } diff --git a/core/libs/prx/libSceAgc/Acb/src/Control.cpp b/core/libs/prx/libSceAgc/Acb/src/Control.cpp index 4532f538b..9bcea7041 100644 --- a/core/libs/prx/libSceAgc/Acb/src/Control.cpp +++ b/core/libs/prx/libSceAgc/Acb/src/Control.cpp @@ -30,11 +30,16 @@ uint32_t APS5_VABI sceAgcAcbJumpGetSize(void) { return 0; } -uint32_t* APS5_VABI sceAgcAcbResetQueue(CommandBuffer* buf, uint32_t op) { - (void)buf; - (void)op; - NotImplemented_nid_no_patch(__func__); - return nullptr; +// Encoded as the custom DISPATCH_RESET NOP packet the driver consumes on compute queues. +uint32_t* APS5_VABI sceAgcAcbResetQueue(CommandBuffer* buf, uint32_t op, uint32_t value) { + (void)value; + Agc::Command::Require(buf != nullptr, __func__, "null command buffer"); + constexpr std::uint32_t OpcodeNop = 0x10; + constexpr std::uint32_t CustomDispatchReset = 0x09; + auto* packet = Agc::Command::Allocate(buf, 2, __func__); + packet[0] = Agc::Command::Header(OpcodeNop, 2, CustomDispatchReset << 2); + packet[1] = op; + return packet; } std::uint32_t* APS5_VABI sceAgcAcbRewind(CommandBuffer* buf, std::uint32_t initialState) { diff --git a/core/libs/prx/libSceAgc/Acb/src/Dispatch.cpp b/core/libs/prx/libSceAgc/Acb/src/Dispatch.cpp index 7ceb0ec94..ae28cda63 100644 --- a/core/libs/prx/libSceAgc/Acb/src/Dispatch.cpp +++ b/core/libs/prx/libSceAgc/Acb/src/Dispatch.cpp @@ -10,11 +10,11 @@ extern "C" { uint32_t* APS5_VABI sceAgcAcbDispatchIndirect(CommandBuffer* buf, const volatile void* indirect_args, uint32_t modifier) { - (void)buf; - (void)indirect_args; - (void)modifier; - NotImplemented_nid_no_patch(__func__); - return nullptr; + // Compute queues take the argument address directly (DISPATCH_INDIRECT with a 64-bit address). + const auto address = reinterpret_cast(indirect_args); + Agc::Command::CheckAddress(address, 4, __func__); + Agc::Command::CheckBits(modifier, 0xa038u | 0x41u, __func__); + return Agc::Command::Emit(buf, 0x16u, {static_cast(address), static_cast(address >> 32u), modifier | 0x41u}, __func__); } std::uint32_t APS5_VABI sceAgcAcbDispatchIndirectGetSize() { diff --git a/core/libs/prx/libSceAgc/CMakeLists.txt b/core/libs/prx/libSceAgc/CMakeLists.txt index 6961369ba..d1d99b23c 100644 --- a/core/libs/prx/libSceAgc/CMakeLists.txt +++ b/core/libs/prx/libSceAgc/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Unimplemented.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Acb/src/Control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Acb/src/Dispatch.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Acb/src/Memory.cpp diff --git a/core/libs/prx/libSceAgc/Cb/src/Dispatch.cpp b/core/libs/prx/libSceAgc/Cb/src/Dispatch.cpp index 088b23012..7e3f94a53 100644 --- a/core/libs/prx/libSceAgc/Cb/src/Dispatch.cpp +++ b/core/libs/prx/libSceAgc/Cb/src/Dispatch.cpp @@ -9,7 +9,7 @@ extern "C" { std::uint32_t* APS5_VABI sceAgcCbDispatch(CommandBuffer* buf, std::uint32_t threadGroupX, std::uint32_t threadGroupY, std::uint32_t threadGroupZ, std::uint32_t modifier) { - Agc::Command::CheckBits(modifier, 0xa038u, __func__); + Agc::Command::CheckBits(modifier, 0xa038u | 0x41u, __func__); return Agc::Command::Emit(buf, 0x15u, {threadGroupX, threadGroupY, threadGroupZ, modifier | 0x41u}, __func__); } diff --git a/core/libs/prx/libSceAgc/Cb/src/Sync.cpp b/core/libs/prx/libSceAgc/Cb/src/Sync.cpp index 74115f047..f418119c5 100644 --- a/core/libs/prx/libSceAgc/Cb/src/Sync.cpp +++ b/core/libs/prx/libSceAgc/Cb/src/Sync.cpp @@ -1,6 +1,8 @@ #include "prx/libSceAgc/Cb/include/Sync.hpp" #include "prx/libSceAgc/Command/include/Packet.hpp" +#include +#include #include #include #include "SceTypes.hpp" @@ -37,10 +39,9 @@ std::uint32_t* APS5_VABI sceAgcCbReleaseMem(CommandBuffer* buf, std::uint8_t act } else if (dataSelect == 5) { Agc::Command::Require(data == 0, __func__, "GDS release cannot use immediate data"); value = gdsOffset | (static_cast(gdsSize) << 16u); - } else { - Agc::Command::Require(gdsOffset == 0 && gdsSize == 0, __func__, "GDS parameters supplied for a non-GDS release"); } - if (dataSelect != 0 && interrupt != 4) { + // A null label is accepted: games emit releases whose destination is never read. + if (dataSelect != 0 && interrupt != 4 && guestAddress != 0) { Agc::Command::CheckAddress(guestAddress, dataSelect == 2 || dataSelect == 3 ? 8 : 4, __func__); } if (dataSelect == 1) { @@ -51,7 +52,10 @@ std::uint32_t* APS5_VABI sceAgcCbReleaseMem(CommandBuffer* buf, std::uint8_t act control |= 0x200u; } const auto eventIndex = action >= 0x2fu ? 6u : 5u; - return Agc::Command::Emit(buf, 0x49u, {action | (eventIndex << 8u) | (control << 12u) | (static_cast(cachePolicy) << 25u), (static_cast(dst) << 16u) | (static_cast(interrupt) << 24u) | (static_cast(dataSelect) << 29u), static_cast(guestAddress), static_cast(guestAddress >> 32u), static_cast(value), static_cast(value >> 32u), interruptContextId}, __func__); + auto* packet = Agc::Command::Emit(buf, 0x49u, {action | (eventIndex << 8u) | (control << 12u) | (static_cast(cachePolicy) << 25u), (static_cast(dst) << 16u) | (static_cast(interrupt) << 24u) | (static_cast(dataSelect) << 29u), static_cast(guestAddress), static_cast(guestAddress >> 32u), static_cast(value), static_cast(value >> 32u), interruptContextId}, __func__); + static const std::uint64_t traced = [] { const char* value = std::getenv("APS5_TRACE_LABEL"); return value ? std::strtoull(value, nullptr, 16) : 0ull; }(); + if (traced != 0 && guestAddress == traced) std::fprintf(stderr, "[agc] RELEASE_MEM for 0x%llx recorded at %p" "\n", static_cast(guestAddress), static_cast(packet)); + return packet; } } diff --git a/core/libs/prx/libSceAgc/Command/src/Memory.cpp b/core/libs/prx/libSceAgc/Command/src/Memory.cpp index 04f08584e..c1952da41 100644 --- a/core/libs/prx/libSceAgc/Command/src/Memory.cpp +++ b/core/libs/prx/libSceAgc/Command/src/Memory.cpp @@ -53,11 +53,13 @@ std::uint32_t* WriteWait(CommandBuffer* buffer, std::uint8_t size, std::uint8_t CheckBits(cachePolicy, 3, function); Require((pollCycles >> 4u) <= 0xffffu, function, "wait poll interval overflow"); if (size == 0) { - CheckBits(reference, 0xffffffffu, function); - CheckBits(mask, 0xffffffffu, function); + // 32-bit waits only use the low halves; guests commonly pass a full 64-bit mask. + reference &= 0xffffffffu; + mask &= 0xffffffffu; } const auto guestAddress = reinterpret_cast(address); - CheckAddress(guestAddress, size == 0 ? 4 : 8, function); + // The address may be left null and filled in later with sceAgcWaitRegMemPatchAddress. + if (guestAddress != 0) CheckAddress(guestAddress, size == 0 ? 4 : 8, function); CheckBits(guestAddress, 0xffffffffffffull, function); const auto waitSize = size == 0 ? 7u : 9u; auto* packet = Allocate(buffer, waitSize + 7u, function); diff --git a/core/libs/prx/libSceAgc/Command/src/Packet.cpp b/core/libs/prx/libSceAgc/Command/src/Packet.cpp index ac4a85471..aebb7c0f4 100644 --- a/core/libs/prx/libSceAgc/Command/src/Packet.cpp +++ b/core/libs/prx/libSceAgc/Command/src/Packet.cpp @@ -15,7 +15,10 @@ void Require(bool condition, const char* function, const char* reason) { } void CheckBits(std::uint64_t value, std::uint64_t mask, const char* function) { - Require((value & ~mask) == 0, function, "reserved bits are set"); + if ((value & ~mask) == 0) return; + char reason[96]; + std::snprintf(reason, sizeof(reason), "reserved bits are set (value 0x%llx, allowed 0x%llx)", static_cast(value), static_cast(mask)); + Require(false, function, reason); } void CheckAddress(std::uint64_t address, std::uint32_t alignment, const char* function) { diff --git a/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp b/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp index e7d38de16..9ff4fb9fd 100644 --- a/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp +++ b/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp @@ -19,15 +19,11 @@ std::uint32_t APS5_VABI sceAgcDcbSetIndexBufferGetSize() { } uint32_t* APS5_VABI sceAgcDcbSetIndexCount(CommandBuffer* buf, uint32_t index_count) { - (void)buf; - (void)index_count; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return Agc::Command::Emit(buf, 0x13u, {index_count}, __func__); } std::uint32_t APS5_VABI sceAgcDcbSetIndexCountGetSize() { - NotImplemented_nid_no_patch(__func__); - return 0; + return 2; } std::uint32_t* APS5_VABI sceAgcDcbSetIndexSize(CommandBuffer* buf, std::uint8_t indexSize, std::uint8_t cachePolicy) { diff --git a/core/libs/prx/libSceAgc/DcbDraw/src/Instancing.cpp b/core/libs/prx/libSceAgc/DcbDraw/src/Instancing.cpp index c1e7ad986..35a5fcba8 100644 --- a/core/libs/prx/libSceAgc/DcbDraw/src/Instancing.cpp +++ b/core/libs/prx/libSceAgc/DcbDraw/src/Instancing.cpp @@ -17,11 +17,17 @@ std::uint32_t APS5_VABI sceAgcDcbSetNumInstancesGetSize() { } uint32_t* APS5_VABI sceAgcDcbSetBaseIndirectArgs(CommandBuffer* buf, uint32_t shader_type, const volatile void* indirect_base_addr) { - (void)buf; - (void)shader_type; - (void)indirect_base_addr; - NotImplemented_nid_no_patch(__func__); - return nullptr; + // SET_BASE with base index 1; header bit 1 selects the dispatch (compute) base over the draw base. + Agc::Command::CheckBits(shader_type, 1, __func__); + const auto address = reinterpret_cast(indirect_base_addr); + Agc::Command::CheckAddress(address, 8, __func__); + Agc::Command::CheckBits(address, 0xffffffffffffull, __func__); + auto* packet = Agc::Command::Allocate(buf, 4, __func__); + packet[0] = Agc::Command::Header(0x11u, 4, shader_type != 0 ? 2u : 0u); + packet[1] = 1; + packet[2] = static_cast(address); + packet[3] = static_cast(address >> 32u); + return packet; } } diff --git a/core/libs/prx/libSceAgc/DcbDraw/src/Stats.cpp b/core/libs/prx/libSceAgc/DcbDraw/src/Stats.cpp index 84da7348d..b3ae56e19 100644 --- a/core/libs/prx/libSceAgc/DcbDraw/src/Stats.cpp +++ b/core/libs/prx/libSceAgc/DcbDraw/src/Stats.cpp @@ -15,9 +15,10 @@ std::uint32_t* APS5_VABI sceAgcDcbGetLodStats(CommandBuffer* buf, std::uint8_t c Agc::Command::CheckBits(reportAndReset, 1, __func__); Agc::Command::CheckBits(reportingIntervalIn100kClocks, 0xffu, __func__); const auto address = reinterpret_cast(buffer); - Agc::Command::CheckAddress(address, 64, __func__); + if (address != 0) Agc::Command::CheckAddress(address, 64, __func__); const auto control = (static_cast(cachePolicy) << 28u) | (static_cast(reportAndReset) << 19u) | (static_cast(forceReset) << 18u) | (resetCount << 10u) | (reportingIntervalIn100kClocks << 2u); - return Agc::Command::Emit(buf, 0x8eu, {bufferSizeInBytes, static_cast(address), static_cast(address >> 32u), control}, __func__); + // LOD statistics are not collected; a same-sized NOP keeps the packet layout without producing data. + return Agc::Command::Emit(buf, 0x10u, {bufferSizeInBytes, static_cast(address), static_cast(address >> 32u), control}, __func__); } std::uint32_t APS5_VABI sceAgcDcbBeginOcclusionQueryGetSize() { diff --git a/core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp b/core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp index 92ef8afc1..d348b2c5b 100644 --- a/core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp +++ b/core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp @@ -51,11 +51,9 @@ uint32_t APS5_VABI sceAgcDcbRewindGetSize(void) { } uint32_t* APS5_VABI sceAgcDcbWaitUntilSafeForRendering(CommandBuffer* buf, uint32_t video_out_handle, uint32_t display_buffer_index) { - (void)buf; - (void)video_out_handle; - (void)display_buffer_index; - NotImplemented_nid_no_patch(__func__); - return nullptr; + // Presentation copies the display buffer when the flip executes, so the buffer is always safe to + // render into; keep the arguments in a NOP for command-buffer dumps. + return Agc::Command::Emit(buf, 0x10u, {video_out_handle, display_buffer_index}, __func__); } } diff --git a/core/libs/prx/libSceAgc/DcbFlow/src/Dispatch.cpp b/core/libs/prx/libSceAgc/DcbFlow/src/Dispatch.cpp index 2b29438a1..5624c73f0 100644 --- a/core/libs/prx/libSceAgc/DcbFlow/src/Dispatch.cpp +++ b/core/libs/prx/libSceAgc/DcbFlow/src/Dispatch.cpp @@ -10,11 +10,9 @@ extern "C" { uint32_t* APS5_VABI sceAgcDcbDispatchIndirect(CommandBuffer* buf, uint32_t data_offset_in_bytes, uint32_t flags) { - (void)buf; - (void)data_offset_in_bytes; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return nullptr; + // Graphics queues read the arguments at an offset from the base set by SetBaseDispatchIndirectArgs. + Agc::Command::CheckBits(flags, 0xa038u | 0x41u, __func__); + return Agc::Command::Emit(buf, 0x16u, {data_offset_in_bytes, flags | 0x41u}, __func__); } std::uint32_t APS5_VABI sceAgcDcbDispatchIndirectGetSize() { diff --git a/core/libs/prx/libSceAgc/DcbFlow/src/Memory.cpp b/core/libs/prx/libSceAgc/DcbFlow/src/Memory.cpp index 67c4dcd8a..4f6b3c805 100644 --- a/core/libs/prx/libSceAgc/DcbFlow/src/Memory.cpp +++ b/core/libs/prx/libSceAgc/DcbFlow/src/Memory.cpp @@ -13,10 +13,13 @@ std::uint32_t* APS5_VABI sceAgcDcbAcquireMem(CommandBuffer* buf, std::uint8_t en Agc::Command::CheckBits(engine, 1, __func__); Agc::Command::CheckBits(cbDbOp, 0x7fffffffu, __func__); Agc::Command::CheckBits(gcrControl, 0x7ffffu, __func__); - const auto address = reinterpret_cast(base); - Agc::Command::Require((address & 0xffu) == 0 && (address >> 40u) == 0, __func__, "invalid acquire memory base address"); - const auto wholeAddressSpace = sizeBytes == 0xffffffffffffffffull; - Agc::Command::Require(wholeAddressSpace || ((sizeBytes & 0xffu) == 0 && (sizeBytes >> 40u) == 0), __func__, "invalid acquire memory range size"); + // The range only scopes cache maintenance, so round it outward to the 256-byte granularity the + // packet encodes instead of rejecting unaligned ranges. + const auto requested = reinterpret_cast(base); + auto address = requested & ~static_cast(0xffu); + const auto wholeAddressSpace = sizeBytes == 0xffffffffffffffffull || (address >> 40u) != 0 || sizeBytes > (1ull << 40u); + if (wholeAddressSpace) address = 0; + else sizeBytes = (sizeBytes + (requested - address) + 0xffu) & ~0xffull; Agc::Command::Require(pollCycles / 40u <= 0xffffu, __func__, "acquire poll interval overflow"); return Agc::Command::Emit(buf, 0x58u, {(static_cast(engine) << 31u) | cbDbOp, wholeAddressSpace ? 0u : static_cast(sizeBytes >> 8u), 0, static_cast(address >> 8u), 0, pollCycles / 40u, gcrControl}, __func__); } diff --git a/core/libs/prx/libSceAgc/DcbState/src/Marker.cpp b/core/libs/prx/libSceAgc/DcbState/src/Marker.cpp index d2d66306c..f457dcc3f 100644 --- a/core/libs/prx/libSceAgc/DcbState/src/Marker.cpp +++ b/core/libs/prx/libSceAgc/DcbState/src/Marker.cpp @@ -3,31 +3,57 @@ #include "prx/libSceAgc/Command/include/Packet.hpp" #include #include +#include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +// Debug markers are custom NOP packets: PUSH carries the NUL-terminated text, POP has no payload. +// Marker colors are only meaningful to capture tools and are not encoded. +namespace { + +constexpr std::uint32_t OpcodeNop = 0x10; +constexpr std::uint32_t CustomPushMarker = 0x0b; +constexpr std::uint32_t CustomPopMarker = 0x0c; + +std::uint32_t* PushMarker(CommandBuffer* buf, const char* str, const char* function) { + Agc::Command::Require(buf != nullptr, function, "null command buffer"); + const char* text = str ? str : ""; + const std::size_t bytes = std::strlen(text) + 1; + const auto payload = static_cast((bytes + 3) / 4); + Agc::Command::Require(payload <= 0x4000u, function, "marker text too long"); + auto* packet = Agc::Command::Allocate(buf, payload + 1, function); + packet[0] = Agc::Command::Header(OpcodeNop, payload + 1, CustomPushMarker << 2); + std::memset(packet + 1, 0, payload * sizeof(std::uint32_t)); + std::memcpy(packet + 1, text, bytes); + return packet; +} + +std::uint32_t* PopMarker(CommandBuffer* buf, const char* function) { + Agc::Command::Require(buf != nullptr, function, "null command buffer"); + auto* packet = Agc::Command::Allocate(buf, 2, function); + packet[0] = Agc::Command::Header(OpcodeNop, 2, CustomPopMarker << 2); + packet[1] = 0; + return packet; +} + +} + extern "C" { uint32_t* APS5_VABI sceAgcDcbSetMarker(CommandBuffer* buf, const char* str, uint32_t color) { - (void)buf; - (void)str; - (void)color; - NotImplemented_nid_no_patch(__func__); - return nullptr; + (void)color; + auto* packet = PushMarker(buf, str, __func__); + PopMarker(buf, __func__); + return packet; } uint32_t* APS5_VABI sceAgcDcbPopMarker(CommandBuffer* buf) { - (void)buf; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return PopMarker(buf, __func__); } uint32_t* APS5_VABI sceAgcDcbPushMarker(CommandBuffer* buf, const char* str, uint32_t color) { - (void)buf; - (void)str; - (void)color; - NotImplemented_nid_no_patch(__func__); - return nullptr; + (void)color; + return PushMarker(buf, str, __func__); } } diff --git a/core/libs/prx/libSceAgc/Patch/src/WaitRegMem.cpp b/core/libs/prx/libSceAgc/Patch/src/WaitRegMem.cpp index 0baf91ef6..daa5b4216 100644 --- a/core/libs/prx/libSceAgc/Patch/src/WaitRegMem.cpp +++ b/core/libs/prx/libSceAgc/Patch/src/WaitRegMem.cpp @@ -30,9 +30,17 @@ int APS5_VABI sceAgcWaitRegMemPatchReference(std::uint32_t* cmd, std::uint64_t r } int APS5_VABI sceAgcWaitRegMemPatchCompareFunction(std::uint32_t* cmd, std::uint8_t compareFunction) { - (void)cmd; - (void)compareFunction; - NotImplemented_nid_no_patch(__func__); + auto* wait = Agc::Command::ValidateWait(cmd, __func__); + Agc::Command::Require(compareFunction <= 6, __func__, "invalid wait comparison"); + wait[1] = (wait[1] & ~7u) | compareFunction; + return 0; +} + +int APS5_VABI sceAgcWriteDataPatchSetAddressOrOffset(std::uint32_t* cmd, std::uint64_t address) { + Agc::Command::CheckAddress(reinterpret_cast(cmd), 4, __func__); + Agc::Command::Require(((cmd[0] >> 8u) & 0xffu) == 0x37u, __func__, "not a WRITE_DATA packet"); + cmd[2] = static_cast(address); + cmd[3] = static_cast(address >> 32u); return 0; } diff --git a/core/libs/prx/libSceAgc/Unimplemented.cpp b/core/libs/prx/libSceAgc/Unimplemented.cpp new file mode 100644 index 000000000..b4b94f6a4 --- /dev/null +++ b/core/libs/prx/libSceAgc/Unimplemented.cpp @@ -0,0 +1,172 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +int APS5_VABI sceAgcAcbPushMarkerSpan() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcAcbSetMarkerSpan() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcAcbSetWorkloadComplete() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcAcbSetWorkloadStreamInactive() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcAcbSetWorkloadsActive() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcAcquireMemSetEngine() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcDcbPushMarkerSpan() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcDcbSetMarkerSpan() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcDcbSetWorkloadStreamInactive() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcDebugRaiseException() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcGetDataPacketPayloadRange() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcGetDefaultCxStateFlat() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcGetGsOversubscription() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcGetIsTrinityMode() { + return 0; +} + +int APS5_VABI sceAgcGetSemaphoreLabel() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAgcSetAmmSemaphoreMemory() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("-KRzWekV120", sceAgcUnknown__MKRzWekV120); +// Unnamed DCB state toggle: games call it as (cb, enable, 0, 0) and ignore the result. It sits +// between SetBaseIndirectArgs and SetIndexBuffer in the import table; treated as a no-op. +std::uint32_t* APS5_VABI sceAgcUnknown__MKRzWekV120(void* buf, std::uint32_t enable, std::uint64_t a2, std::uint64_t a3) { + static bool logged = false; + if (!logged) { + logged = true; + std::fprintf(stderr, "[agc] -KRzWekV120 treated as no-op (enable=%u args=0x%llx,0x%llx)" "\n", enable, static_cast(a2), static_cast(a3)); + } + (void)buf; + return nullptr; +} + +APS5_EXPORT("6nths4DHNrs", sceAgcUnknown_6nths4DHNrs); +int APS5_VABI sceAgcUnknown_6nths4DHNrs() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("7Wa3aeJgeVU", sceAgcUnknown_7Wa3aeJgeVU); +int APS5_VABI sceAgcUnknown_7Wa3aeJgeVU() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("EJBA4dbmvfg", sceAgcUnknown_EJBA4dbmvfg); +int APS5_VABI sceAgcUnknown_EJBA4dbmvfg() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("ICkECTBxrMw", sceAgcUnknown_ICkECTBxrMw); +int APS5_VABI sceAgcUnknown_ICkECTBxrMw() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("Ikfdt-rIqCE", sceAgcUnknown_Ikfdt_MrIqCE); +int APS5_VABI sceAgcUnknown_Ikfdt_MrIqCE() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("RTpj-tIlvZc", sceAgcUnknown_RTpj_MtIlvZc); +int APS5_VABI sceAgcUnknown_RTpj_MtIlvZc() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("SwI6QxqwAC0", sceAgcUnknown_SwI6QxqwAC0); +int APS5_VABI sceAgcUnknown_SwI6QxqwAC0() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("d4NZIlguzv0", sceAgcUnknown_d4NZIlguzv0); +int APS5_VABI sceAgcUnknown_d4NZIlguzv0() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("eAy8eGNsCuU", sceAgcUnknown_eAy8eGNsCuU); +int APS5_VABI sceAgcUnknown_eAy8eGNsCuU() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("rP5xLdOf26k", sceAgcUnknown_rP5xLdOf26k); +int APS5_VABI sceAgcUnknown_rP5xLdOf26k() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("tmy-+rBpspY", sceAgcUnknown_tmy_M_PrBpspY); +int APS5_VABI sceAgcUnknown_tmy_M_PrBpspY() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("y5K5tPktiL8", sceAgcUnknown_y5K5tPktiL8); +int APS5_VABI sceAgcUnknown_y5K5tPktiL8() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libSceAjm/Export.cpp b/core/libs/prx/libSceAjm/Export.cpp index a7c85810e..fa38a9b32 100644 --- a/core/libs/prx/libSceAjm/Export.cpp +++ b/core/libs/prx/libSceAjm/Export.cpp @@ -94,7 +94,7 @@ int APS5_VABI sceAjmModuleUnregister(uint32_t context, uint32_t codec) { return 0; } -const char* sceAjmStrError(int error) { +const char* APS5_VABI sceAjmStrError(int error) { (void)error; NotImplemented_nid_no_patch(__func__); return nullptr; diff --git a/core/libs/prx/libSceAjmi/Export.cpp b/core/libs/prx/libSceAjmi/Export.cpp index a7c85810e..fa38a9b32 100644 --- a/core/libs/prx/libSceAjmi/Export.cpp +++ b/core/libs/prx/libSceAjmi/Export.cpp @@ -94,7 +94,7 @@ int APS5_VABI sceAjmModuleUnregister(uint32_t context, uint32_t codec) { return 0; } -const char* sceAjmStrError(int error) { +const char* APS5_VABI sceAjmStrError(int error) { (void)error; NotImplemented_nid_no_patch(__func__); return nullptr; diff --git a/core/libs/prx/libSceAmpr/Export.cpp b/core/libs/prx/libSceAmpr/Export.cpp new file mode 100644 index 000000000..0deb6a264 --- /dev/null +++ b/core/libs/prx/libSceAmpr/Export.cpp @@ -0,0 +1,335 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" +#include "prx/libkernel/Apr/include/AprCommandBuffer.hpp" +#include + +static constexpr int SCE_AMPR_ERROR_BUFFER_FULL = 0x8002001C; + +static int Append(Apr::CommandBufferObject* buffer, const void* command, uint32_t bytes) { + if (!buffer->base || bytes > buffer->size - buffer->offset) return SCE_AMPR_ERROR_BUFFER_FULL; + std::memcpy(buffer->base + buffer->offset, command, bytes); + buffer->offset += bytes; + ++buffer->numCommands; + return 0; +} + +extern "C" { + +int APS5_VABI sceAmprAprCommandBufferConstructor(Apr::CommandBufferObject* buffer, uint64_t* gatherState, uint64_t* scatterState) { + buffer->type = Apr::BufferType::Apr; + *gatherState = 0; + *scatterState = 0; + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferDestructor(Apr::CommandBufferObject* buffer, uint64_t* gatherState, uint64_t* scatterState) { + (void)buffer; + (void)gatherState; + (void)scatterState; + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferMapBegin() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferMapDirectBegin() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferMapEnd() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferReadFile(Apr::CommandBufferObject* buffer, uint64_t* gatherState, uint64_t* scatterState, uint32_t fileId, void* destination, uint64_t size, uint64_t offset) { + (void)gatherState; + (void)scatterState; + Apr::ReadFileCommand command{}; + command.header = {Apr::Opcode::ReadFile, sizeof(command)}; + command.fileId = fileId; + command.destination = reinterpret_cast(destination); + command.size = size; + command.offset = offset; + return Append(buffer, &command, sizeof(command)); +} + +int APS5_VABI sceAmprAprCommandBufferReadFileGather() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferReadFileGatherScatter() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferReadFileScatter() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprAprCommandBufferResetGatherScatterState() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferClearBuffer(Apr::CommandBufferObject* buffer) { + buffer->base = nullptr; + buffer->size = 0; + buffer->offset = 0; + buffer->numCommands = 0; + return 0; +} + +int APS5_VABI sceAmprCommandBufferConstructMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferConstructNop() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferConstructor(Apr::CommandBufferObject* buffer) { + *buffer = {nullptr, 0, 0, 0, Apr::BufferType::Generic}; + return 0; +} + +int APS5_VABI sceAmprCommandBufferDestructor(Apr::CommandBufferObject* buffer) { + (void)buffer; + return 0; +} + +void* APS5_VABI sceAmprCommandBufferGetBufferBaseAddress(const Apr::CommandBufferObject* buffer) { + return buffer->base; +} + +uint32_t APS5_VABI sceAmprCommandBufferGetCurrentOffset(const Apr::CommandBufferObject* buffer) { + return buffer->offset; +} + +uint32_t APS5_VABI sceAmprCommandBufferGetNumCommands(const Apr::CommandBufferObject* buffer) { + return buffer->numCommands; +} + +uint32_t APS5_VABI sceAmprCommandBufferGetSize(const Apr::CommandBufferObject* buffer) { + return buffer->size; +} + +uint32_t APS5_VABI sceAmprCommandBufferGetType(const Apr::CommandBufferObject* buffer) { + return static_cast(buffer->type); +} + +int APS5_VABI sceAmprCommandBufferNop() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferNopWithData() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferPopMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferPushMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferPushMarkerWithColor() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferReset(Apr::CommandBufferObject* buffer) { + buffer->offset = 0; + buffer->numCommands = 0; + return 0; +} + +int APS5_VABI sceAmprCommandBufferSetBuffer(Apr::CommandBufferObject* buffer, void* memory, uint32_t size) { + buffer->base = static_cast(memory); + buffer->size = size; + buffer->offset = 0; + buffer->numCommands = 0; + return 0; +} + +int APS5_VABI sceAmprCommandBufferSetMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferSetMarkerWithColor() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWaitOnAddress_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWaitOnCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWriteAddressFromCounterPair_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWriteAddressFromCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWriteAddressFromTimeCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWriteAddress_04_00(Apr::CommandBufferObject* buffer, uint64_t* address, uint64_t value, uint32_t flags) { + Apr::WriteAddressCommand command{}; + command.header = {Apr::Opcode::WriteAddress, sizeof(command)}; + command.address = reinterpret_cast(address); + command.value = value; + command.flags = flags; + return Append(buffer, &command, sizeof(command)); +} + +int APS5_VABI sceAmprCommandBufferWriteCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprCommandBufferWriteKernelEventQueue_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeMapBegin() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeMapDirectBegin() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeMapEnd() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeNop() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeNopWithData() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizePopMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizePushMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizePushMarkerWithColor() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +uint32_t APS5_VABI sceAmprMeasureCommandSizeReadFile(void) { + return sizeof(Apr::ReadFileCommand); +} + +int APS5_VABI sceAmprMeasureCommandSizeReadFileGather() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeReadFileGatherScatter() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeReadFileScatter() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeResetGatherScatterState() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeSetMarker() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeSetMarkerWithColor() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWaitOnAddress_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWaitOnCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWriteAddressFromCounterPair_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWriteAddressFromCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWriteAddressFromTimeCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +uint32_t APS5_VABI sceAmprMeasureCommandSizeWriteAddress_04_00(void) { + return sizeof(Apr::WriteAddressCommand); +} + +int APS5_VABI sceAmprMeasureCommandSizeWriteCounter_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceAmprMeasureCommandSizeWriteKernelEventQueue_04_00() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libSceAppContent/Export.cpp b/core/libs/prx/libSceAppContent/Export.cpp index a82776a71..9469c86d6 100644 --- a/core/libs/prx/libSceAppContent/Export.cpp +++ b/core/libs/prx/libSceAppContent/Export.cpp @@ -2,6 +2,11 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +static constexpr int SCE_APP_CONTENT_ERROR_PARAMETER = static_cast(0x80D90002); +static constexpr uint32_t APPPARAM_ID_SKU_FLAG = 1; +static constexpr int32_t SKU_FLAG_FULL = 3; extern "C" { @@ -20,10 +25,17 @@ int APS5_VABI sceAppContentAddcontUnmount(const AppContentMountPoint* mount_poin } int APS5_VABI sceAppContentAppParamGetInt(uint32_t param_id, int32_t* value) { - (void)param_id; - (void)value; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!value) return SCE_APP_CONTENT_ERROR_PARAMETER; + switch (param_id) { + case APPPARAM_ID_SKU_FLAG: + *value = SKU_FLAG_FULL; + return 0; + case 2: case 3: case 4: case 5: + *value = 0; + return 0; + default: + return SCE_APP_CONTENT_ERROR_PARAMETER; + } } int APS5_VABI sceAppContentDownloadDataGetAvailableSpaceKb(const AppContentMountPoint* mount_point, size_t* available_space_kb) { @@ -34,10 +46,10 @@ int APS5_VABI sceAppContentDownloadDataGetAvailableSpaceKb(const AppContentMount } int APS5_VABI sceAppContentInitialize(const AppContentInitParam* init_param, AppContentBootParam* boot_param) { - (void)init_param; - (void)boot_param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)init_param; + if (!boot_param) return SCE_APP_CONTENT_ERROR_PARAMETER; + std::memset(boot_param, 0, sizeof(*boot_param)); + return 0; } int APS5_VABI sceAppContentTemporaryDataFormat(const AppContentMountPoint* mount_point) { diff --git a/core/libs/prx/libSceCesCs/Export.cpp b/core/libs/prx/libSceCesCs/Export.cpp index 74c0388f7..aaa150eef 100644 --- a/core/libs/prx/libSceCesCs/Export.cpp +++ b/core/libs/prx/libSceCesCs/Export.cpp @@ -5,7 +5,7 @@ extern "C" { -const uint8_t* sceCesRefersUcsProfileCp1252(void) { +const uint8_t* APS5_VABI sceCesRefersUcsProfileCp1252(void) { NotImplemented_nid_no_patch(__func__); return nullptr; } diff --git a/core/libs/prx/libSceFiber/Export.cpp b/core/libs/prx/libSceFiber/Export.cpp index 4e805a493..b24a8ea92 100644 --- a/core/libs/prx/libSceFiber/Export.cpp +++ b/core/libs/prx/libSceFiber/Export.cpp @@ -2,79 +2,398 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +static constexpr int32_t SCE_OK = 0; +static constexpr int32_t SCE_FIBER_ERROR_NULL = static_cast(0x80590001); +static constexpr int32_t SCE_FIBER_ERROR_ALIGNMENT = static_cast(0x80590002); +static constexpr int32_t SCE_FIBER_ERROR_RANGE = static_cast(0x80590003); +static constexpr int32_t SCE_FIBER_ERROR_INVALID = static_cast(0x80590004); +static constexpr int32_t SCE_FIBER_ERROR_PERMISSION = static_cast(0x80590005); +static constexpr int32_t SCE_FIBER_ERROR_STATE = static_cast(0x80590006); + +static constexpr std::size_t FIBER_OBJECT_SIZE = 0x100; +static constexpr std::size_t FIBER_OPT_PARAM_SIZE = 0x80; +static constexpr std::size_t FIBER_MIN_CONTEXT_SIZE = 512; + +#ifdef _WIN32 + +using GuestFiberEntry = void (APS5_VABI*)(std::uint64_t argOnInitialize, std::uint64_t argOnRun); + +// A fiber that is switching away stays Suspending until its context is saved; whoever runs next +// on that host thread publishes Suspended. Fibers migrate between threads, so a resumer must never +// see Suspended before the saved stack pointer is valid. +enum class FiberState : std::uint32_t { + Idle = 1, + Running = 2, + Suspending = 3, + Suspended = 4, +}; + +struct Fiber { + std::uint64_t magic; + std::atomic state; + std::uint32_t reserved; + GuestFiberEntry entry; + std::uint64_t argOnInitialize; + std::uint8_t* context; + std::uint64_t contextSize; + void* savedStack; + char name[FIBER_MAX_NAME_LENGTH + 1]; +}; +static_assert(sizeof(Fiber) <= FIBER_OBJECT_SIZE, "guest reserves 0x100 bytes for SceFiber"); + +static constexpr std::uint64_t FIBER_MAGIC = 0x5245424946355041ull; + +struct StackBounds { + void* base; + void* limit; + void* deallocation; +}; + +struct ThreadFiberState { + Fiber* current = nullptr; + void* threadStack = nullptr; + StackBounds threadBounds{}; + std::uint64_t transfer = 0; + Fiber* pendingSuspend = nullptr; +}; + +static thread_local ThreadFiberState g_thread; + +// A fiber may resume on a different host thread than the one that suspended it, so the +// thread-local state must be looked up again after every stack switch rather than cached. +__attribute__((noinline)) static ThreadFiberState& ThreadState() { + asm volatile("" ::: "memory"); + return g_thread; +} + +static bool TraceFibers() { + static const bool enabled = std::getenv("APS5_TRACE_FIBER") != nullptr; + return enabled; +} + +static void CompletePendingSuspend() { + auto& thread = ThreadState(); + if (thread.pendingSuspend) { + thread.pendingSuspend->state.store(FiberState::Suspended, std::memory_order_release); + thread.pendingSuspend = nullptr; + } +} + +extern "C" void Aps5FiberSwitchStack(void** save, void* load); +extern "C" void Aps5FiberTrampoline(); + +asm(R"( + .text + .globl Aps5FiberSwitchStack + .def Aps5FiberSwitchStack; .scl 2; .type 32; .endef +Aps5FiberSwitchStack: + push %rbp + push %rbx + push %rdi + push %rsi + push %r12 + push %r13 + push %r14 + push %r15 + sub $0xa8, %rsp + movaps %xmm6, 0x00(%rsp) + movaps %xmm7, 0x10(%rsp) + movaps %xmm8, 0x20(%rsp) + movaps %xmm9, 0x30(%rsp) + movaps %xmm10, 0x40(%rsp) + movaps %xmm11, 0x50(%rsp) + movaps %xmm12, 0x60(%rsp) + movaps %xmm13, 0x70(%rsp) + movaps %xmm14, 0x80(%rsp) + movaps %xmm15, 0x90(%rsp) + stmxcsr 0xa0(%rsp) + fnstcw 0xa4(%rsp) + mov %rsp, (%rcx) + mov %rdx, %rsp + movaps 0x00(%rsp), %xmm6 + movaps 0x10(%rsp), %xmm7 + movaps 0x20(%rsp), %xmm8 + movaps 0x30(%rsp), %xmm9 + movaps 0x40(%rsp), %xmm10 + movaps 0x50(%rsp), %xmm11 + movaps 0x60(%rsp), %xmm12 + movaps 0x70(%rsp), %xmm13 + movaps 0x80(%rsp), %xmm14 + movaps 0x90(%rsp), %xmm15 + ldmxcsr 0xa0(%rsp) + fldcw 0xa4(%rsp) + add $0xa8, %rsp + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rsi + pop %rdi + pop %rbx + pop %rbp + ret + + .globl Aps5FiberTrampoline + .def Aps5FiberTrampoline; .scl 2; .type 32; .endef +Aps5FiberTrampoline: + mov %r12, %rcx + and $-16, %rsp + sub $32, %rsp + call Aps5FiberMain + ud2 +)"); + +struct InitialFrame { + std::uint8_t xmm[0xa0]; + std::uint32_t mxcsr; + std::uint16_t fpuControl; + std::uint16_t padding; + std::uint64_t r15, r14, r13, r12, rsi, rdi, rbx, rbp; + std::uint64_t returnAddress; +}; +static_assert(sizeof(InitialFrame) == 0xa8 + 8 * 8 + 8, "initial fiber frame must match Aps5FiberSwitchStack"); + +static StackBounds CurrentBounds() { + auto* tib = reinterpret_cast(NtCurrentTeb()); + auto* teb = reinterpret_cast(tib); + return {tib->StackBase, tib->StackLimit, *reinterpret_cast(teb + 0x1478)}; +} + +static void SetBounds(const StackBounds& bounds) { + auto* tib = reinterpret_cast(NtCurrentTeb()); + auto* teb = reinterpret_cast(tib); + tib->StackBase = bounds.base; + tib->StackLimit = bounds.limit; + *reinterpret_cast(teb + 0x1478) = bounds.deallocation; +} + +static StackBounds FiberBounds(const Fiber* fiber) { + return {fiber->context + fiber->contextSize, fiber->context, fiber->context}; +} + +static Fiber* AsFiber(FiberObject* object) { + auto* fiber = reinterpret_cast(object); + return fiber && fiber->magic == FIBER_MAGIC ? fiber : nullptr; +} + +extern "C" [[noreturn]] void Aps5FiberMain(Fiber* fiber) { + CompletePendingSuspend(); + fiber->entry(fiber->argOnInitialize, ThreadState().transfer); + throw std::runtime_error(std::string("sceFiber: entry function of fiber '") + fiber->name + "' returned"); +} + +static void PrepareInitialStack(Fiber* fiber) { + const auto top = reinterpret_cast(fiber->context + fiber->contextSize) & ~static_cast(15); + auto* frame = reinterpret_cast(top - 256); + std::memset(frame, 0, sizeof(*frame)); + frame->mxcsr = _mm_getcsr(); + std::uint16_t control = 0; + asm volatile("fnstcw %0" : "=m"(control)); + frame->fpuControl = control; + frame->r12 = reinterpret_cast(fiber); + frame->returnAddress = reinterpret_cast(&Aps5FiberTrampoline); + fiber->savedStack = frame; +} + +static bool AcquireForResume(Fiber* target) { + for (;;) { + auto state = target->state.load(std::memory_order_acquire); + if (state == FiberState::Suspending) { + std::this_thread::yield(); + continue; + } + if (state != FiberState::Idle && state != FiberState::Suspended) return false; + if (target->state.compare_exchange_weak(state, FiberState::Running, std::memory_order_acq_rel)) { + if (state == FiberState::Idle) PrepareInitialStack(target); + return true; + } + } +} + +static void Resume(Fiber* target, void** save, std::uint64_t argOnRun) { + const auto* frame = static_cast(target->savedStack); + if (frame->returnAddress == 0) { + std::fprintf(stderr, "[fiber] resuming '%s' with a wiped context: saved=%p context=%p size=0x%llx\n", target->name, target->savedStack, + static_cast(target->context), static_cast(target->contextSize)); + const auto* words = static_cast(target->savedStack); + for (int i = 0; i < 40; i += 4) std::fprintf(stderr, "[fiber] +0x%03x %016llx %016llx %016llx %016llx\n", i * 8, static_cast(words[i]), static_cast(words[i + 1]), static_cast(words[i + 2]), static_cast(words[i + 3])); + std::fflush(stderr); + std::abort(); + } + ThreadState().current = target; + ThreadState().transfer = argOnRun; + SetBounds(FiberBounds(target)); + Aps5FiberSwitchStack(save, target->savedStack); +} extern "C" { -int32_t APS5_VABI sceFiberFinalize(FiberObject* fiber) { - (void)fiber; - NotImplemented_nid_no_patch(__func__); - return 0; +int32_t APS5_VABI _sceFiberInitializeImpl_nid_postfix(FiberObject* object, const char* name, GuestFiberEntry entry, uint64_t arg_on_initialize, void* addr_context, uint64_t size_context, const void* opt_param, uint32_t build_version) { + (void)opt_param; + (void)build_version; + if (!object || !name || !entry) return SCE_FIBER_ERROR_NULL; + if ((reinterpret_cast(object) & 7) != 0) return SCE_FIBER_ERROR_ALIGNMENT; + if (addr_context == nullptr && size_context != 0) return SCE_FIBER_ERROR_INVALID; + if ((reinterpret_cast(addr_context) & 15) != 0 || (size_context & 15) != 0) return SCE_FIBER_ERROR_ALIGNMENT; + if (addr_context == nullptr) return SCE_FIBER_ERROR_INVALID; + if (size_context < FIBER_MIN_CONTEXT_SIZE) return SCE_FIBER_ERROR_RANGE; + auto* fiber = reinterpret_cast(object); + std::memset(object, 0, FIBER_OBJECT_SIZE); + fiber->magic = FIBER_MAGIC; + fiber->state.store(FiberState::Idle, std::memory_order_relaxed); + fiber->entry = entry; + fiber->argOnInitialize = arg_on_initialize; + fiber->context = static_cast(addr_context); + fiber->contextSize = size_context; + std::strncpy(fiber->name, name, FIBER_MAX_NAME_LENGTH); + if (TraceFibers()) std::fprintf(stderr, "[fiber] init %s object=%p context=%p+0x%llx entry=%p\n", fiber->name, static_cast(object), addr_context, static_cast(size_context), reinterpret_cast(entry)); + return SCE_OK; } -int32_t APS5_VABI sceFiberGetInfo(FiberObject* fiber, FiberInfo* fiber_info) { - (void)fiber; - (void)fiber_info; - NotImplemented_nid_no_patch(__func__); - return 0; +int32_t APS5_VABI sceFiberFinalize(FiberObject* object) { + auto* fiber = AsFiber(object); + if (!fiber) return object ? SCE_FIBER_ERROR_INVALID : SCE_FIBER_ERROR_NULL; + const auto state = fiber->state.load(std::memory_order_acquire); + if (state == FiberState::Running || state == FiberState::Suspending) return SCE_FIBER_ERROR_STATE; + fiber->magic = 0; + return SCE_OK; } -int32_t APS5_VABI sceFiberGetSelf(FiberObject** fiber) { - (void)fiber; - NotImplemented_nid_no_patch(__func__); - return 0; +int32_t APS5_VABI sceFiberRun_nid_postfix(FiberObject* object, uint64_t arg_on_run, uint64_t* arg_on_return) { + auto* fiber = AsFiber(object); + if (!fiber) return object ? SCE_FIBER_ERROR_INVALID : SCE_FIBER_ERROR_NULL; + if (ThreadState().current) return SCE_FIBER_ERROR_PERMISSION; + if (!AcquireForResume(fiber)) return SCE_FIBER_ERROR_STATE; + ThreadState().threadBounds = CurrentBounds(); + Resume(fiber, &ThreadState().threadStack, arg_on_run); + CompletePendingSuspend(); + SetBounds(ThreadState().threadBounds); + if (arg_on_return) *arg_on_return = ThreadState().transfer; + return SCE_OK; } -int32_t APS5_VABI sceFiberGetThreadFramePointerAddress(uint64_t* addr_frame_pointer) { - (void)addr_frame_pointer; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int32_t APS5_VABI sceFiberOptParamInitialize(FiberOptParam* opt_param) { - (void)opt_param; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int32_t APS5_VABI sceFiberRename(FiberObject* fiber, const char* name) { - (void)fiber; - (void)name; - NotImplemented_nid_no_patch(__func__); - return 0; +int32_t APS5_VABI sceFiberSwitch(FiberObject* object, uint64_t arg_on_run, uint64_t* arg_on_run_out) { + auto* target = AsFiber(object); + if (!target) return object ? SCE_FIBER_ERROR_INVALID : SCE_FIBER_ERROR_NULL; + auto* self = ThreadState().current; + if (!self) return SCE_FIBER_ERROR_PERMISSION; + if (target == self || !AcquireForResume(target)) return SCE_FIBER_ERROR_STATE; + if (TraceFibers()) { + auto** frame = static_cast(__builtin_frame_address(0)); + void* chain[6] = {}; + auto** guest = static_cast(frame[0]); + for (int depth = 0; depth < 6 && guest; ++depth) { + chain[depth] = guest[1]; + guest = static_cast(guest[0]); + } + std::fprintf(stderr, "[fiber] switch %s -> %s from %p %p %p %p %p %p\n", self->name, target->name, chain[0], chain[1], chain[2], chain[3], chain[4], chain[5]); + } + self->state.store(FiberState::Suspending, std::memory_order_relaxed); + ThreadState().pendingSuspend = self; + Resume(target, &self->savedStack, arg_on_run); + CompletePendingSuspend(); + if (arg_on_run_out) *arg_on_run_out = ThreadState().transfer; + return SCE_OK; } int32_t APS5_VABI sceFiberReturnToThread(uint64_t arg_on_return, uint64_t* arg_on_run) { - (void)arg_on_return; - (void)arg_on_run; - NotImplemented_nid_no_patch(__func__); - return 0; + auto* self = ThreadState().current; + if (!self) return SCE_FIBER_ERROR_PERMISSION; + if (TraceFibers()) std::fprintf(stderr, "[fiber] return %s from %p\n", self->name, __builtin_return_address(0)); + self->state.store(FiberState::Suspending, std::memory_order_relaxed); + ThreadState().pendingSuspend = self; + ThreadState().current = nullptr; + ThreadState().transfer = arg_on_return; + SetBounds(ThreadState().threadBounds); + Aps5FiberSwitchStack(&self->savedStack, ThreadState().threadStack); + CompletePendingSuspend(); + if (arg_on_run) *arg_on_run = ThreadState().transfer; + return SCE_OK; } -int32_t APS5_VABI sceFiberRun_nid_postfix(FiberObject* fiber, uint64_t arg_on_run, uint64_t* arg_on_return) { - (void)fiber; - (void)arg_on_run; - (void)arg_on_return; - NotImplemented_nid_no_patch(__func__); - return 0; +int32_t APS5_VABI sceFiberGetSelf(FiberObject** fiber) { + if (!fiber) return SCE_FIBER_ERROR_NULL; + if (!ThreadState().current) return SCE_FIBER_ERROR_PERMISSION; + *fiber = reinterpret_cast(ThreadState().current); + return SCE_OK; +} + +int32_t APS5_VABI sceFiberGetInfo(FiberObject* object, FiberInfo* fiber_info) { + auto* fiber = AsFiber(object); + if (!fiber || !fiber_info) return object && fiber_info ? SCE_FIBER_ERROR_INVALID : SCE_FIBER_ERROR_NULL; + if (fiber_info->size != sizeof(FiberInfo)) return SCE_FIBER_ERROR_INVALID; + fiber_info->entry = reinterpret_cast(fiber->entry); + fiber_info->arg_on_initialize = fiber->argOnInitialize; + fiber_info->addr_context = fiber->context; + fiber_info->size_context = fiber->contextSize; + std::memcpy(fiber_info->name, fiber->name, sizeof(fiber_info->name)); + fiber_info->size_context_margin = static_cast(-1); + return SCE_OK; +} + +int32_t APS5_VABI sceFiberRename(FiberObject* object, const char* name) { + auto* fiber = AsFiber(object); + if (!fiber || !name) return object && name ? SCE_FIBER_ERROR_INVALID : SCE_FIBER_ERROR_NULL; + std::memset(fiber->name, 0, sizeof(fiber->name)); + std::strncpy(fiber->name, name, FIBER_MAX_NAME_LENGTH); + return SCE_OK; +} + +int32_t APS5_VABI sceFiberOptParamInitialize(FiberOptParam* opt_param) { + if (!opt_param) return SCE_FIBER_ERROR_NULL; + std::memset(opt_param, 0, FIBER_OPT_PARAM_SIZE); + return SCE_OK; +} + +int32_t APS5_VABI sceFiberGetThreadFramePointerAddress(uint64_t* addr_frame_pointer) { + (void)addr_frame_pointer; + NotImplemented_nid_no_patch(__func__); + return 0; } int32_t APS5_VABI sceFiberStartContextSizeCheck(uint32_t flags) { - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)flags; + NotImplemented_nid_no_patch(__func__); + return 0; } int32_t APS5_VABI sceFiberStopContextSizeCheck(void) { - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int32_t APS5_VABI sceFiberSwitch(FiberObject* fiber, uint64_t arg_on_run, uint64_t* arg_on_return) { - (void)fiber; - (void)arg_on_run; - (void)arg_on_return; - NotImplemented_nid_no_patch(__func__); - return 0; + NotImplemented_nid_no_patch(__func__); + return 0; } } + +#else + +extern "C" { + +int32_t APS5_VABI _sceFiberInitializeImpl_nid_postfix() { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberFinalize(FiberObject*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberRun_nid_postfix(FiberObject*, uint64_t, uint64_t*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberSwitch(FiberObject*, uint64_t, uint64_t*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberReturnToThread(uint64_t, uint64_t*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberGetSelf(FiberObject**) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberGetInfo(FiberObject*, FiberInfo*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberRename(FiberObject*, const char*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberOptParamInitialize(FiberOptParam*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberGetThreadFramePointerAddress(uint64_t*) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberStartContextSizeCheck(uint32_t) { NotImplemented_nid_no_patch(__func__); return 0; } +int32_t APS5_VABI sceFiberStopContextSizeCheck(void) { NotImplemented_nid_no_patch(__func__); return 0; } + +} + +#endif diff --git a/core/libs/prx/libSceFont.native/Export.cpp b/core/libs/prx/libSceFont.native/Export.cpp index 87b9d2475..33f3d0fa4 100644 --- a/core/libs/prx/libSceFont.native/Export.cpp +++ b/core/libs/prx/libSceFont.native/Export.cpp @@ -497,7 +497,7 @@ int APS5_VABI sceFontWritingLineWritesOrder(FontWritingLine writing_line, uint64 return 0; } -const FontWritingStep* sceFontWritingRefersRenderStep(FontWriting* font_writing) { +const FontWritingStep* APS5_VABI sceFontWritingRefersRenderStep(FontWriting* font_writing) { (void)font_writing; NotImplemented_nid_no_patch(__func__); return nullptr; diff --git a/core/libs/prx/libSceFont/Export.cpp b/core/libs/prx/libSceFont/Export.cpp index 87b9d2475..33f3d0fa4 100644 --- a/core/libs/prx/libSceFont/Export.cpp +++ b/core/libs/prx/libSceFont/Export.cpp @@ -497,7 +497,7 @@ int APS5_VABI sceFontWritingLineWritesOrder(FontWritingLine writing_line, uint64 return 0; } -const FontWritingStep* sceFontWritingRefersRenderStep(FontWriting* font_writing) { +const FontWritingStep* APS5_VABI sceFontWritingRefersRenderStep(FontWriting* font_writing) { (void)font_writing; NotImplemented_nid_no_patch(__func__); return nullptr; diff --git a/core/libs/prx/libSceGameUpdate/Export.cpp b/core/libs/prx/libSceGameUpdate/Export.cpp index 937cda4b6..bc9cbef05 100644 --- a/core/libs/prx/libSceGameUpdate/Export.cpp +++ b/core/libs/prx/libSceGameUpdate/Export.cpp @@ -3,31 +3,30 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +// Update checks need the network, which is not available; requests fail so the game skips the check. +static constexpr int SCE_GAME_UPDATE_ERROR_OFFLINE = static_cast(0x80D50001); + extern "C" { int APS5_VABI sceGameUpdateAbortRequest(int request_id) { - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + return 0; } int APS5_VABI sceGameUpdateCheck(int request_id, const GameUpdateCheckParam* param, GameUpdateCheckResult* result) { - (void)request_id; - (void)param; - (void)result; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)param; + (void)result; + return SCE_GAME_UPDATE_ERROR_OFFLINE; } int APS5_VABI sceGameUpdateCreateRequest(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_GAME_UPDATE_ERROR_OFFLINE; } int APS5_VABI sceGameUpdateDeleteRequest(int request_id) { - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + return 0; } int APS5_VABI sceGameUpdateGetAddcontLatestVersion(uint32_t service_label, const void* entitlement_label, GameUpdateAddcontVersionInfo* info) { @@ -39,13 +38,11 @@ int APS5_VABI sceGameUpdateGetAddcontLatestVersion(uint32_t service_label, const } int APS5_VABI sceGameUpdateInitialize(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceGameUpdateTerminate(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } } diff --git a/core/libs/prx/libSceHttp/Export.cpp b/core/libs/prx/libSceHttp/Export.cpp index 882ca8b4e..d3292924e 100644 --- a/core/libs/prx/libSceHttp/Export.cpp +++ b/core/libs/prx/libSceHttp/Export.cpp @@ -2,40 +2,42 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// No network is emulated: contexts, templates and requests can be created, but any request +// that would touch the network fails with the library's network error. +static constexpr int ERROR_NETWORK = static_cast(0x80431063); +static std::atomic g_nextHandle{1}; extern "C" { int APS5_VABI sceHttpAbortRequest(int request_id) { - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + return 0; } int APS5_VABI sceHttpAddRequestHeader(int id, const char* name, const char* value, uint32_t mode) { - (void)id; - (void)name; - (void)value; - (void)mode; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)name; + (void)value; + (void)mode; + return 0; } int APS5_VABI sceHttpCreateConnection(int tmpl_id, const char* server_name, const char* scheme, uint16_t port, int enable_keep_alive) { - (void)tmpl_id; - (void)server_name; - (void)scheme; - (void)port; - (void)enable_keep_alive; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)tmpl_id; + (void)server_name; + (void)scheme; + (void)port; + (void)enable_keep_alive; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpCreateConnectionWithURL(int tmpl_id, const char* url, int enable_keep_alive) { - (void)tmpl_id; - (void)url; - (void)enable_keep_alive; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)tmpl_id; + (void)url; + (void)enable_keep_alive; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpCreateEpoll(int http_ctx_id, HttpEpollHandle* eh) { @@ -46,199 +48,172 @@ int APS5_VABI sceHttpCreateEpoll(int http_ctx_id, HttpEpollHandle* eh) { } int APS5_VABI sceHttpCreateRequest(int conn_id, int method, const char* path, uint64_t content_length) { - (void)conn_id; - (void)method; - (void)path; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)conn_id; + (void)method; + (void)path; + (void)content_length; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpCreateRequestWithURL2(int conn_id, const char* method, const char* url, uint64_t content_length) { - (void)conn_id; - (void)method; - (void)url; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)conn_id; + (void)method; + (void)url; + (void)content_length; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpCreateTemplate(int http_ctx_id, const char* user_agent, int http_ver, int is_auto_proxy_conf) { - (void)http_ctx_id; - (void)user_agent; - (void)http_ver; - (void)is_auto_proxy_conf; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)http_ctx_id; + (void)user_agent; + (void)http_ver; + (void)is_auto_proxy_conf; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpDeleteConnection(int conn_id) { - (void)conn_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)conn_id; + return 0; } int APS5_VABI sceHttpDeleteRequest(int req_id) { - (void)req_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + return 0; } int APS5_VABI sceHttpDeleteTemplate(int tmpl_id) { - (void)tmpl_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)tmpl_id; + return 0; } int APS5_VABI sceHttpDestroyEpoll(int http_ctx_id, HttpEpollHandle eh) { - (void)http_ctx_id; - (void)eh; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)http_ctx_id; + (void)eh; + return 0; } int APS5_VABI sceHttpGetAllResponseHeaders(int request_id, char** header, size_t* header_size) { - (void)request_id; - (void)header; - (void)header_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)header; + (void)header_size; + return ERROR_NETWORK; } int APS5_VABI sceHttpGetResponseContentLength(int request_id, int* result, uint64_t* content_length) { - (void)request_id; - (void)result; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)result; + (void)content_length; + return ERROR_NETWORK; } int APS5_VABI sceHttpGetStatusCode(int request_id, int* status_code) { - (void)request_id; - (void)status_code; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)status_code; + return ERROR_NETWORK; } int APS5_VABI sceHttpInit_nid_postfix(int memid, int ssl_ctx_id, uint64_t pool_size) { - (void)memid; - (void)ssl_ctx_id; - (void)pool_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)memid; + (void)ssl_ctx_id; + (void)pool_size; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttpsDisableOption(int id, uint32_t ssl_flags) { - (void)id; - (void)ssl_flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)ssl_flags; + return 0; } int APS5_VABI sceHttpSendRequest(int request_id, const void* post_data, size_t size) { - (void)request_id; - (void)post_data; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)post_data; + (void)size; + return ERROR_NETWORK; } int APS5_VABI sceHttpSetAuthEnabled(int id, int enable) { - (void)id; - (void)enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)enable; + return 0; } int APS5_VABI sceHttpSetAutoRedirect(int id, int enable) { - (void)id; - (void)enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)enable; + return 0; } int APS5_VABI sceHttpSetConnectTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttpSetEpoll(int id, HttpEpollHandle eh, void* user_arg) { - (void)id; - (void)eh; - (void)user_arg; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)eh; + (void)user_arg; + return 0; } int APS5_VABI sceHttpSetNonblock(int id, int enable) { - (void)id; - (void)enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)enable; + return 0; } int APS5_VABI sceHttpSetRecvTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttpSetRequestContentLength(int request_id, uint64_t content_length) { - (void)request_id; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)content_length; + return 0; } int APS5_VABI sceHttpSetResolveRetry(int id, int32_t retry) { - (void)id; - (void)retry; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)retry; + return 0; } int APS5_VABI sceHttpSetResolveTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttpSetSendTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttpsSetMinSslVersion(int id, uint32_t ssl_version) { - (void)id; - (void)ssl_version; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)ssl_version; + return 0; } int APS5_VABI sceHttpsSetSslCallback(int id, HttpsCallback cbfunc, void* user_arg) { - (void)id; - (void)cbfunc; - (void)user_arg; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)cbfunc; + (void)user_arg; + return 0; } int APS5_VABI sceHttpTerm_nid_postfix(int http_ctx_id) { - (void)http_ctx_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)http_ctx_id; + return 0; } int APS5_VABI sceHttpUnsetEpoll(int id) { - (void)id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + return 0; } int APS5_VABI sceHttpUriBuild(char* out, size_t* require, size_t prepare, const SceHttpUriElement* src_element, uint32_t option) { @@ -271,10 +246,24 @@ int APS5_VABI sceHttpUriParse(SceHttpUriElement* out, const char* src_url, void* } int APS5_VABI sceHttpWaitRequest(HttpEpollHandle eh, HttpNBEvent* nbev, int maxevents, int timeout) { - (void)eh; - (void)nbev; - (void)maxevents; - (void)timeout; + (void)eh; + (void)nbev; + (void)maxevents; + (void)timeout; + return ERROR_NETWORK; +} + +int APS5_VABI sceHttpCreateRequestWithURL() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceHttpReadData() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceHttpSetChunkedTransferEnabled() { NotImplemented_nid_no_patch(__func__); return 0; } diff --git a/core/libs/prx/libSceHttp2/Export.cpp b/core/libs/prx/libSceHttp2/Export.cpp index c1e890b02..95f07e60a 100644 --- a/core/libs/prx/libSceHttp2/Export.cpp +++ b/core/libs/prx/libSceHttp2/Export.cpp @@ -2,228 +2,209 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// No network is emulated: contexts, templates and requests can be created, but any request +// that would touch the network fails with the library's network error. +static constexpr int ERROR_NETWORK = static_cast(0x80436063); +static std::atomic g_nextHandle{1}; extern "C" { int APS5_VABI sceHttp2AddRequestHeader(int id, const char* name, const char* value, uint32_t mode) { - (void)id; - (void)name; - (void)value; - (void)mode; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)name; + (void)value; + (void)mode; + return 0; } int APS5_VABI sceHttp2CreateRequestWithURL(int tmpl_id, const char* method, const char* url, uint64_t content_length) { - (void)tmpl_id; - (void)method; - (void)url; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)tmpl_id; + (void)method; + (void)url; + (void)content_length; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttp2CreateTemplate(int lib_http2_ctx_id, const char* user_agent, int http_ver, int is_auto_proxy_conf) { - (void)lib_http2_ctx_id; - (void)user_agent; - (void)http_ver; - - (void)is_auto_proxy_conf; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_http2_ctx_id; + (void)user_agent; + (void)http_ver; + (void)is_auto_proxy_conf; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttp2DeleteRequest(int req_id) { - (void)req_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + return 0; } int APS5_VABI sceHttp2DeleteTemplate(int tmpl_id) { - (void)tmpl_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)tmpl_id; + return 0; } int APS5_VABI sceHttp2GetAllResponseHeaders(int req_id, char** header, size_t* header_size) { - (void)req_id; - (void)header; - (void)header_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)header; + (void)header_size; + return ERROR_NETWORK; } int APS5_VABI sceHttp2GetResponseContentLength(int req_id, int* result, uint64_t* content_length) { - (void)req_id; - (void)result; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)result; + (void)content_length; + return ERROR_NETWORK; } int APS5_VABI sceHttp2GetStatusCode(int req_id, int* status_code) { - (void)req_id; - (void)status_code; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)status_code; + return ERROR_NETWORK; } int APS5_VABI sceHttp2Init(int libnet_mem_id, int libssl_ctx_id, size_t pool_size, int max_concurrent_request) { - (void)libnet_mem_id; - (void)libssl_ctx_id; - (void)pool_size; - (void)max_concurrent_request; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)libnet_mem_id; + (void)libssl_ctx_id; + (void)pool_size; + (void)max_concurrent_request; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceHttp2ReadData(int req_id, void* data, size_t size) { - (void)req_id; - (void)data; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)data; + (void)size; + return ERROR_NETWORK; } int APS5_VABI sceHttp2ReadDataAsync(int req_id, void* data, size_t size, void* kqueue_option, void* option) { - (void)req_id; - (void)data; - (void)size; - (void)kqueue_option; - (void)option; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)data; + (void)size; + (void)kqueue_option; + (void)option; + return ERROR_NETWORK; } int APS5_VABI sceHttp2SendRequest(int req_id, const void* post_data, size_t size) { - (void)req_id; - (void)post_data; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)post_data; + (void)size; + return ERROR_NETWORK; } int APS5_VABI sceHttp2SendRequestAsync(int req_id, const void* post_data, size_t size, void* kqueue_option, void* option) { - (void)req_id; - (void)post_data; - (void)size; - (void)kqueue_option; - (void)option; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)post_data; + (void)size; + (void)kqueue_option; + (void)option; + return ERROR_NETWORK; } int APS5_VABI sceHttp2SetAuthEnabled(int id, int is_enable) { - (void)id; - (void)is_enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)is_enable; + return 0; } int APS5_VABI sceHttp2SetAutoRedirect(int id, int enable) { - (void)id; - (void)enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)enable; + return 0; } int APS5_VABI sceHttp2SetConnectionWaitTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SetConnectTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SetInflateGZIPEnabled(int id, int enable) { - (void)id; - (void)enable; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)enable; + return 0; } int APS5_VABI sceHttp2SetRecvTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SetRedirectCallback(int id, void* cb_func, void* user_arg) { - (void)id; - (void)cb_func; - (void)user_arg; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)cb_func; + (void)user_arg; + return 0; } int APS5_VABI sceHttp2SetRequestContentLength(int id, uint64_t content_length) { - (void)id; - (void)content_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)content_length; + return 0; } int APS5_VABI sceHttp2SetResolveTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SetSendTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SetSslCallback(int id, void* cb_func, void* user_arg) { - (void)id; - (void)cb_func; - (void)user_arg; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)cb_func; + (void)user_arg; + return 0; } int APS5_VABI sceHttp2SetTimeOut(int id, uint32_t usec) { - (void)id; - (void)usec; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)usec; + return 0; } int APS5_VABI sceHttp2SslDisableOption(int id, uint32_t ssl_flags) { - (void)id; - (void)ssl_flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)ssl_flags; + return 0; } int APS5_VABI sceHttp2SslEnableOption(int id, uint32_t ssl_flags) { - (void)id; - (void)ssl_flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)id; + (void)ssl_flags; + return 0; } int APS5_VABI sceHttp2Term(int lib_http2_ctx_id) { - (void)lib_http2_ctx_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_http2_ctx_id; + return 0; } int APS5_VABI sceHttp2WaitAsync(int req_id, Http2AsyncResult* result, uint32_t* timeout, void* option) { - (void)req_id; - (void)result; - (void)timeout; - (void)option; + (void)req_id; + (void)result; + (void)timeout; + (void)option; + return ERROR_NETWORK; +} + +int APS5_VABI sceHttp2AbortRequest() { NotImplemented_nid_no_patch(__func__); return 0; } diff --git a/core/libs/prx/libSceJpegEnc/Export.cpp b/core/libs/prx/libSceJpegEnc/Export.cpp new file mode 100644 index 000000000..8f4b5a78f --- /dev/null +++ b/core/libs/prx/libSceJpegEnc/Export.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +int APS5_VABI sceJpegEncCreate() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceJpegEncDelete() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceJpegEncEncode() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceJpegEncQueryMemorySize() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libSceJson2/Export.cpp b/core/libs/prx/libSceJson2/Export.cpp new file mode 100644 index 000000000..848de74a4 --- /dev/null +++ b/core/libs/prx/libSceJson2/Export.cpp @@ -0,0 +1,37 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + + +extern "C" { + +// Initialization succeeds as on an offline console: the title tears its whole web API layer down on +// an init failure and later dereferences it anyway. Requests made through it fail as offline. +int APS5_VABI _ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE(void* self, const void* parameter) { + (void)self; + (void)parameter; + return 0; +} + +int APS5_VABI _ZN3sce4Json11InitializerC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce4Json11InitializerD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce4Json12MemAllocatorC2Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce4Json12MemAllocatorD2Ev(void* self) { + (void)self; + return 0; +} + +} diff --git a/core/libs/prx/libSceMsgDialog.native/Export.cpp b/core/libs/prx/libSceMsgDialog.native/Export.cpp new file mode 100644 index 000000000..dbe06e1d1 --- /dev/null +++ b/core/libs/prx/libSceMsgDialog.native/Export.cpp @@ -0,0 +1,10 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +int SceMsgDialogNativeModuleLoaded_nid_no_patch = 1; + +} diff --git a/core/libs/prx/libSceNet/Export.cpp b/core/libs/prx/libSceNet/Export.cpp index ef59f2ce7..bb4b9bab3 100644 --- a/core/libs/prx/libSceNet/Export.cpp +++ b/core/libs/prx/libSceNet/Export.cpp @@ -2,54 +2,112 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include +#include +#include +#include +#include +#include +#include + +// No network is emulated: pools, resolvers and epoll instances exist, but sockets cannot be +// created, so every socket operation fails with the guest's EBADF. +static constexpr int GUEST_EINTR = 4; +static constexpr int GUEST_EBADF = 9; +static constexpr int GUEST_EINVAL = 22; +static constexpr int GUEST_ENOSPC = 28; +static constexpr int GUEST_EAFNOSUPPORT = 47; +static constexpr int GUEST_ENETDOWN = 50; +static constexpr int GUEST_EHOSTUNREACH = 65; +static constexpr int GUEST_AF_INET = 2; + +static thread_local int g_netErrno = 0; +static std::atomic g_nextId{1}; + +struct Epoll { + std::mutex lock; + std::condition_variable changed; + bool aborted = false; +}; + +static std::mutex g_epollLock; +static std::map> g_epolls; + +static int Fail(int error) { + g_netErrno = error; + return static_cast(0x80410100u | static_cast(error)); +} + +static std::shared_ptr FindEpoll(int eid) { + std::lock_guard lock(g_epollLock); + const auto found = g_epolls.find(eid); + return found == g_epolls.end() ? nullptr : found->second; +} + +static void AbortEpoll(Epoll& epoll) { + { + std::lock_guard lock(epoll.lock); + epoll.aborted = true; + } + epoll.changed.notify_all(); +} extern "C" { int APS5_VABI sceNetAccept(int s, void* addr, uint32_t* addrlen) { - (void)s; - (void)addr; - (void)addrlen; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)addr; + (void)addrlen; + return Fail(GUEST_EBADF); } int APS5_VABI sceNetBind_nid_postfix(int s, const void* addr, uint32_t addrlen) { - (void)s; - (void)addr; - (void)addrlen; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)addr; + (void)addrlen; + return Fail(GUEST_EBADF); } int APS5_VABI sceNetEpollControl(int eid, int op, int id, const NetEpollEvent* event) { - (void)eid; - (void)op; - (void)id; - (void)event; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)op; + (void)id; + (void)event; + if (!FindEpoll(eid)) return Fail(GUEST_EBADF); + return Fail(GUEST_EBADF); } int APS5_VABI sceNetEpollCreate(const char* name, int flags) { - (void)name; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)name; + (void)flags; + const int id = g_nextId.fetch_add(1, std::memory_order_relaxed); + std::lock_guard lock(g_epollLock); + g_epolls[id] = std::make_shared(); + return id; } int APS5_VABI sceNetEpollDestroy(int eid) { - (void)eid; - NotImplemented_nid_no_patch(__func__); - return 0; + std::lock_guard lock(g_epollLock); + const auto found = g_epolls.find(eid); + if (found == g_epolls.end()) return Fail(GUEST_EBADF); + AbortEpoll(*found->second); + g_epolls.erase(found); + return 0; } int APS5_VABI sceNetEpollWait(int eid, NetEpollEvent* events, int maxevents, int timeout) { - (void)eid; - (void)events; - (void)maxevents; - (void)timeout; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)events; + (void)maxevents; + auto epoll = FindEpoll(eid); + if (!epoll) return Fail(GUEST_EBADF); + std::unique_lock lock(epoll->lock); + const auto aborted = [&] { return epoll->aborted; }; + if (timeout < 0) epoll->changed.wait(lock, aborted); + else epoll->changed.wait_for(lock, std::chrono::microseconds(timeout), aborted); + if (epoll->aborted) { + epoll->aborted = false; + return Fail(GUEST_EINTR); + } + return 0; } int APS5_VABI sceNetEtherNtostr(const NetEtherAddr* n, char* str, size_t len) { @@ -68,138 +126,214 @@ int APS5_VABI sceNetGetMacAddress(NetEtherAddr* addr, int flags) { } int APS5_VABI sceNetGetSockInfo(int s, void* info, int n, int flags) { - (void)s; - (void)info; - (void)n; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)info; + (void)n; + (void)flags; + return Fail(GUEST_EBADF); } int APS5_VABI sceNetGetsockname(int s, void* addr, uint32_t* addrlen) { - (void)s; - (void)addr; - (void)addrlen; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)addr; + (void)addrlen; + return Fail(GUEST_EBADF); } uint32_t APS5_VABI sceNetHtonl_nid_postfix(uint32_t host32) { - (void)host32; - NotImplemented_nid_no_patch(__func__); - return 0; + return __builtin_bswap32(host32); } uint16_t APS5_VABI sceNetHtons_nid_postfix(uint16_t host16) { - (void)host16; - NotImplemented_nid_no_patch(__func__); - return 0; + return __builtin_bswap16(host16); } -const char* sceNetInetNtop(int af, const void* src, char* dst, uint32_t size) { - (void)af; - (void)src; - (void)dst; - (void)size; - NotImplemented_nid_no_patch(__func__); - return nullptr; +const char* APS5_VABI sceNetInetNtop(int af, const void* src, char* dst, uint32_t size) { + if (af != GUEST_AF_INET || !src || !dst) { + Fail(GUEST_EAFNOSUPPORT); + return nullptr; + } + const auto* bytes = static_cast(src); + if (std::snprintf(dst, size, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]) >= static_cast(size)) { + Fail(GUEST_ENOSPC); + return nullptr; + } + return dst; } int APS5_VABI sceNetInetPton(int af, const char* src, void* dst) { - (void)af; - (void)src; - (void)dst; - NotImplemented_nid_no_patch(__func__); - return 0; + if (af != GUEST_AF_INET) return Fail(GUEST_EAFNOSUPPORT); + if (!src || !dst) return Fail(GUEST_EINVAL); + unsigned parts[4]; + char trailing; + if (std::sscanf(src, "%u.%u.%u.%u%c", &parts[0], &parts[1], &parts[2], &parts[3], &trailing) != 4) return 0; + auto* bytes = static_cast(dst); + for (int index = 0; index < 4; ++index) { + if (parts[index] > 255) return 0; + bytes[index] = static_cast(parts[index]); + } + return 1; } int APS5_VABI sceNetInit_nid_postfix(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceNetListen(int s, int backlog) { - (void)s; - (void)backlog; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)backlog; + return Fail(GUEST_EBADF); } uint32_t APS5_VABI sceNetNtohl_nid_postfix(uint32_t net32) { - (void)net32; - NotImplemented_nid_no_patch(__func__); - return 0; + return __builtin_bswap32(net32); } uint16_t APS5_VABI sceNetNtohs_nid_postfix(uint16_t net16) { - (void)net16; - NotImplemented_nid_no_patch(__func__); - return 0; + return __builtin_bswap16(net16); } int APS5_VABI sceNetPoolCreate(const char* name, int size, int flags) { - (void)name; - (void)size; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)name; + (void)flags; + if (size <= 0) return Fail(GUEST_EINVAL); + return g_nextId.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNetPoolDestroy(int memid) { - (void)memid; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)memid; + return 0; } int APS5_VABI sceNetResolverCreate(const char* name, int memid, int flags) { - (void)name; - (void)memid; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)name; + (void)memid; + (void)flags; + return g_nextId.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNetResolverStartNtoa(int rid, const char* hostname, void* addr, int timeout, int retry, int flags) { - (void)rid; - (void)hostname; - (void)addr; - (void)timeout; - (void)retry; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)rid; + (void)hostname; + (void)addr; + (void)timeout; + (void)retry; + (void)flags; + return Fail(GUEST_EHOSTUNREACH); } int APS5_VABI sceNetSetsockopt(int s, int level, int optname, const void* optval, uint32_t optlen) { - (void)s; - (void)level; - (void)optname; - (void)optval; - (void)optlen; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)level; + (void)optname; + (void)optval; + (void)optlen; + return Fail(GUEST_EBADF); } int APS5_VABI sceNetShutdown(int s, int how) { - (void)s; - (void)how; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + (void)how; + return Fail(GUEST_EBADF); } int APS5_VABI sceNetSocket(const char* name, int family, int type, int protocol) { - (void)name; - (void)family; - (void)type; - (void)protocol; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)name; + (void)family; + (void)type; + (void)protocol; + return Fail(GUEST_ENETDOWN); } int APS5_VABI sceNetSocketClose(int s) { - (void)s; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)s; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetConnect(int s, const void* addr, uint32_t addrlen) { + (void)s; + (void)addr; + (void)addrlen; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetEpollAbort(int eid, int flags) { + (void)flags; + auto epoll = FindEpoll(eid); + if (!epoll) return Fail(GUEST_EBADF); + AbortEpoll(*epoll); + return 0; +} + +int* APS5_VABI sceNetErrnoLoc(void) { + return &g_netErrno; +} + +int APS5_VABI sceNetGetsockopt(int s, int level, int optname, void* optval, uint32_t* optlen) { + (void)s; + (void)level; + (void)optname; + (void)optval; + (void)optlen; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetRecv(int s, void* buf, size_t len, int flags) { + (void)s; + (void)buf; + (void)len; + (void)flags; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetRecvfrom(int s, void* buf, size_t len, int flags, void* from, uint32_t* fromlen) { + (void)s; + (void)buf; + (void)len; + (void)flags; + (void)from; + (void)fromlen; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetResolverDestroy(int rid) { + (void)rid; + return 0; +} + +int APS5_VABI sceNetResolverStartAton(int rid, const void* addr, char* hostname, int len, int timeout, int retry, int flags) { + (void)rid; + (void)addr; + (void)hostname; + (void)len; + (void)timeout; + (void)retry; + (void)flags; + return Fail(GUEST_EHOSTUNREACH); +} + +int APS5_VABI sceNetSend(int s, const void* msg, size_t len, int flags) { + (void)s; + (void)msg; + (void)len; + (void)flags; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetSendto(int s, const void* msg, size_t len, int flags, const void* to, uint32_t tolen) { + (void)s; + (void)msg; + (void)len; + (void)flags; + (void)to; + (void)tolen; + return Fail(GUEST_EBADF); +} + +int APS5_VABI sceNetSocketAbort(int s, int flags) { + (void)s; + (void)flags; + return Fail(GUEST_EBADF); } } diff --git a/core/libs/prx/libSceNetCtl/Export.cpp b/core/libs/prx/libSceNetCtl/Export.cpp index 3cd6cb69a..1f7af1cd0 100644 --- a/core/libs/prx/libSceNetCtl/Export.cpp +++ b/core/libs/prx/libSceNetCtl/Export.cpp @@ -2,67 +2,80 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// Network control reports an initialized but disconnected interface: no network is emulated. +static constexpr int SCE_NET_CTL_ERROR_CALLBACK_MAX = static_cast(0x80412103); +static constexpr int SCE_NET_CTL_ERROR_INVALID_ID = static_cast(0x80412105); +static constexpr int SCE_NET_CTL_ERROR_INVALID_ADDR = static_cast(0x80412107); +static constexpr int SCE_NET_CTL_ERROR_NOT_CONNECTED = static_cast(0x80412108); +static constexpr int NET_CTL_STATE_DISCONNECTED = 0; +static constexpr int MAX_CALLBACKS = 8; + +static std::mutex g_callbackLock; +static NetCtlCallback g_callbacks[MAX_CALLBACKS] = {}; extern "C" { int APS5_VABI sceNetCtlCheckCallback(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceNetCtlGetInfo(int code, NetCtlInfo* info) { - (void)code; - (void)info; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)code; + (void)info; + return SCE_NET_CTL_ERROR_NOT_CONNECTED; } int APS5_VABI sceNetCtlGetNatInfo(NetCtlNatInfo* nat_info) { - (void)nat_info; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)nat_info; + return SCE_NET_CTL_ERROR_NOT_CONNECTED; } int APS5_VABI sceNetCtlGetResult(int event_type, int* error_code) { - (void)event_type; - (void)error_code; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)event_type; + if (!error_code) return SCE_NET_CTL_ERROR_INVALID_ADDR; + *error_code = 0; + return 0; } int APS5_VABI sceNetCtlGetState(int* state) { - (void)state; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!state) return SCE_NET_CTL_ERROR_INVALID_ADDR; + *state = NET_CTL_STATE_DISCONNECTED; + return 0; } int APS5_VABI sceNetCtlGetStateV6(int* state) { - (void)state; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!state) return SCE_NET_CTL_ERROR_INVALID_ADDR; + *state = NET_CTL_STATE_DISCONNECTED; + return 0; } int APS5_VABI sceNetCtlInit(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceNetCtlRegisterCallback(NetCtlCallback func, void* arg, int* cid) { - (void)func; - (void)arg; - (void)cid; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!func || !cid) return SCE_NET_CTL_ERROR_INVALID_ADDR; + std::lock_guard lock(g_callbackLock); + for (int index = 0; index < MAX_CALLBACKS; ++index) { + if (!g_callbacks[index]) { + g_callbacks[index] = func; + *cid = index; + return 0; + } + } + return SCE_NET_CTL_ERROR_CALLBACK_MAX; } void APS5_VABI sceNetCtlTerm(void) { - NotImplemented_nid_no_patch(__func__); } int APS5_VABI sceNetCtlUnregisterCallback(int cid) { - (void)cid; - NotImplemented_nid_no_patch(__func__); - return 0; + if (cid < 0 || cid >= MAX_CALLBACKS) return SCE_NET_CTL_ERROR_INVALID_ID; + std::lock_guard lock(g_callbackLock); + g_callbacks[cid] = nullptr; + return 0; } } diff --git a/core/libs/prx/libSceNpCommerce/Export.cpp b/core/libs/prx/libSceNpCommerce/Export.cpp index e7bdccd9b..e56b3e859 100644 --- a/core/libs/prx/libSceNpCommerce/Export.cpp +++ b/core/libs/prx/libSceNpCommerce/Export.cpp @@ -1,12 +1,67 @@ #include #include +#include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +namespace { + +constexpr int COMMON_DIALOG_STATUS_NONE = 0; +constexpr int COMMON_DIALOG_STATUS_INITIALIZED = 1; +constexpr int COMMON_DIALOG_STATUS_FINISHED = 3; +constexpr int COMMON_DIALOG_RESULT_USER_CANCELED = 1; +constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast(0x80B80003u); +constexpr int COMMON_DIALOG_ERROR_ALREADY_INITIALIZED = static_cast(0x80B80004u); +constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast(0x80B80006u); +constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast(0x80B80009u); + +int g_status = COMMON_DIALOG_STATUS_NONE; + +} + extern "C" { +// The store dialog has nothing to show: every open finishes at once as cancelled by the user. +int APS5_VABI sceNpCommerceDialogInitialize() { + if (g_status != COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_ALREADY_INITIALIZED; + g_status = COMMON_DIALOG_STATUS_INITIALIZED; + return 0; +} + +int APS5_VABI sceNpCommerceDialogOpen(const void* param) { + if (g_status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED; + if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL; + g_status = COMMON_DIALOG_STATUS_FINISHED; + return 0; +} + int APS5_VABI sceNpCommerceDialogUpdateStatus(void) { - NotImplemented_nid_no_patch(__func__); + return g_status; +} + +int APS5_VABI sceNpCommerceDialogGetStatus(void) { + return g_status; +} + +int APS5_VABI sceNpCommerceDialogGetResult(void* result) { + if (result == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL; + if (g_status != COMMON_DIALOG_STATUS_FINISHED) return COMMON_DIALOG_ERROR_NOT_FINISHED; + // SceNpCommerceDialogResult: int32 result, bool authorized, then reserved bytes. + std::int32_t value = COMMON_DIALOG_RESULT_USER_CANCELED; + std::memcpy(result, &value, sizeof(value)); + std::uint8_t authorized = 0; + std::memcpy(static_cast(result) + sizeof(value), &authorized, sizeof(authorized)); + return 0; +} + +int APS5_VABI sceNpCommerceDialogClose(void) { + if (g_status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED; + g_status = COMMON_DIALOG_STATUS_FINISHED; + return 0; +} + +int APS5_VABI sceNpCommerceDialogTerminate() { + g_status = COMMON_DIALOG_STATUS_NONE; return 0; } diff --git a/core/libs/prx/libSceNpCppWebApi/Export.cpp b/core/libs/prx/libSceNpCppWebApi/Export.cpp new file mode 100644 index 000000000..eb7416f8a --- /dev/null +++ b/core/libs/prx/libSceNpCppWebApi/Export.cpp @@ -0,0 +1,745 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +static constexpr int SCE_NP_WEBAPI_ERROR_UNAVAILABLE = static_cast(0x80552901); + +// Offline PSN: request entry points (API calls, transaction start/readData, factories) fail with +// SCE_NP_WEBAPI_ERROR_UNAVAILABLE; parameter bookkeeping succeeds; response accessors stay unimplemented +// because a failed request never produces a response. +extern "C" { + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V111UserFactory6createEPNS1_6Common10LibContextEPNS5_12IntrusivePtrINS3_4UserEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V121GetRankingRequestBody18setStartSerialRankERKi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V121GetRankingRequestBody8setGroupERKNS3_5GroupE() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V121GetRankingRequestBody8setLimitERKi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V121GetRankingRequestBody8setUsersERKNS1_6Common6VectorINS5_12IntrusivePtrINS3_4UserEEEEE() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V121GetRankingRequestBody9setOffsetERKi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122GetRankingResponseBody10getEntriesEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122RecordScoreRequestBody10setCommentEPKc() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122RecordScoreRequestBody12setSmallDataEPKvm() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122RecordScoreRequestBody15setNeedsTmpRankERKb() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122RecordScoreRequestBody19setComparedDateTimeERK10SceRtcTick() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V122RecordScoreRequestBody7setPcIdERKi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V128GetRankingRequestBodyFactory6createEPNS1_6Common10LibContextEPNS5_12IntrusivePtrINS3_21GetRankingRequestBodyEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V129RecordScoreRequestBodyFactory6createEPNS1_6Common10LibContextElPNS5_12IntrusivePtrINS3_22RecordScoreRequestBodyEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V14User12setAccountIdERKm() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V14User7setPcIdERKi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi10getRankingEiRKNS4_21ParameterToGetRankingERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_22GetRankingResponseBodyEEENSA_INS8_18ResponseHeaderBaseEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi21ParameterToGetRanking10initializeEPNS1_6Common10LibContextEi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi21ParameterToGetRanking24setgetRankingRequestBodyENS1_6Common12IntrusivePtrINS3_21GetRankingRequestBodyEEE() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi21ParameterToGetRanking9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi21ParameterToGetRankingC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi21ParameterToGetRankingD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi22getLargeDataByObjectIdEiRKNS4_33ParameterToGetLargeDataByObjectIdERNS1_6Common21DownStreamTransactionINS8_12IntrusivePtrINS4_37GetLargeDataByObjectIdResponseHeadersEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi33ParameterToGetLargeDataByObjectId10initializeEPNS1_6Common10LibContextEPKc() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi33ParameterToGetLargeDataByObjectId9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi33ParameterToGetLargeDataByObjectIdC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V17ViewApi33ParameterToGetLargeDataByObjectIdD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19BoardsApi18getBoardDefinitionEiRKNS4_29ParameterToGetBoardDefinitionERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_30GetBoardDefinitionResponseBodyEEENSA_INS8_18ResponseHeaderBaseEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19BoardsApi29ParameterToGetBoardDefinition10initializeEPNS1_6Common10LibContextEi() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19BoardsApi29ParameterToGetBoardDefinition9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19BoardsApi29ParameterToGetBoardDefinitionC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19BoardsApi29ParameterToGetBoardDefinitionD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi11recordScoreEiRKNS4_22ParameterToRecordScoreERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_23RecordScoreResponseBodyEEENSA_INS4_26RecordScoreResponseHeadersEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi15recordLargeDataEiRKNS4_26ParameterToRecordLargeDataERNS1_6Common19UpStreamTransactionINS8_12IntrusivePtrINS3_27RecordLargeDataResponseBodyEEENSA_INS8_18ResponseHeaderBaseEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi22ParameterToRecordScore10initializeEPNS1_6Common10LibContextEiNS6_12IntrusivePtrINS3_22RecordScoreRequestBodyEEE() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi22ParameterToRecordScore22setxPsnAtomicOperationENS5_19XPsnAtomicOperationE() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi22ParameterToRecordScore9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi22ParameterToRecordScoreC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi22ParameterToRecordScoreD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi26ParameterToRecordLargeData10initializeEPNS1_6Common10LibContextEiNS5_19XPsnAtomicOperationEPKc() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi26ParameterToRecordLargeData9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi26ParameterToRecordLargeDataC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi12Leaderboards2V19RecordApi26ParameterToRecordLargeDataD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi17TitleCloudStorage2V17DataApi12downloadDataEiRKNS4_23ParameterToDownloadDataERNS1_6Common21DownStreamTransactionINS8_12IntrusivePtrINS4_27DownloadDataResponseHeadersEEEEE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi17TitleCloudStorage2V17DataApi23ParameterToDownloadData10initializeEPNS1_6Common10LibContextEPKci() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi17TitleCloudStorage2V17DataApi23ParameterToDownloadData9terminateEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi17TitleCloudStorage2V17DataApi23ParameterToDownloadDataC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi17TitleCloudStorage2V17DataApi23ParameterToDownloadDataD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common10InitParamsC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common10InitParamsD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common10LibContextC1Ev(uint64_t* self) { + *self = 0; + return 0; +} + +// Initialization succeeds as on an offline console (see libSceJson2); individual requests fail. +int APS5_VABI _ZN3sce2Np9CppWebApi6Common10initializeERKNS2_10InitParamsERNS2_10LibContextE(const void* params, uint64_t* context) { + (void)params; + if (context) *context = 1; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V121GetRankingRequestBodyEEC1ERS7_(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V121GetRankingRequestBodyEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V121GetRankingRequestBodyEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122RecordScoreRequestBodyEEC1ERS7_(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122RecordScoreRequestBodyEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122RecordScoreRequestBodyEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V14UserEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V14UserEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V19RecordApi26RecordScoreResponseHeadersEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V19RecordApi26RecordScoreResponseHeadersEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorINS3_INS1_12Leaderboards2V15EntryEEEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common13ConstIteratorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEED2Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEE5startEPNS2_10LibContextE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V127RecordLargeDataResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common19UpStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V127RecordLargeDataResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextEm() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common19UpStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V127RecordLargeDataResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE8sendDataEPKvm() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common19UpStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V127RecordLargeDataResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common19UpStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V127RecordLargeDataResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V17ViewApi37GetLargeDataByObjectIdResponseHeadersEEEE5startEPNS2_10LibContextE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V17ViewApi37GetLargeDataByObjectIdResponseHeadersEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V17ViewApi37GetLargeDataByObjectIdResponseHeadersEEEE8readDataEPcm() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V17ViewApi37GetLargeDataByObjectIdResponseHeadersEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_12Leaderboards2V17ViewApi37GetLargeDataByObjectIdResponseHeadersEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_17TitleCloudStorage2V17DataApi27DownloadDataResponseHeadersEEEE5startEPNS2_10LibContextE() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_17TitleCloudStorage2V17DataApi27DownloadDataResponseHeadersEEEE6finishEv() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_17TitleCloudStorage2V17DataApi27DownloadDataResponseHeadersEEEE8readDataEPcm() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_17TitleCloudStorage2V17DataApi27DownloadDataResponseHeadersEEEEC1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common21DownStreamTransactionINS2_12IntrusivePtrINS1_17TitleCloudStorage2V17DataApi27DownloadDataResponseHeadersEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6StringD1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_12Leaderboards2V14UserEEEE8pushBackERKS8_() { + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_12Leaderboards2V14UserEEEEC1EPNS2_10LibContextE(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_12Leaderboards2V14UserEEEED1Ev(void* self) { + (void)self; + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEE3endEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEE5beginEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEEppEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZN3sce2Np9CppWebApi6Common9terminateERNS2_10LibContextE(uint64_t* context) { + *context = 0; + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V122GetRankingResponseBody22getLastUpdatedDateTimeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V123RecordScoreResponseBody10getTmpRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V123RecordScoreResponseBody16getTmpSerialRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody11getSortModeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody13getEntryLimitEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody13getUpdateModeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody13sortModeIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody15entryLimitIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody15updateModeIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody16getMaxScoreLimitEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody16getMinScoreLimitEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody18maxScoreLimitIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody18minScoreLimitIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody20getLargeDataNumLimitEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody21getLargeDataSizeLimitEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody22largeDataNumLimitIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V130GetBoardDefinitionResponseBody23largeDataSizeLimitIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry10getCommentEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry11getObjectIdEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry11getOnlineIdEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry12commentIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry12getAccountIdEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry12getSmallDataEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry13getSerialRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry13objectIdIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry14getHighestRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry14smallDataIsSetEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry20getHighestSerialRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry7getPcIdEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry7getRankEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V15Entry8getScoreEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi12Leaderboards2V19RecordApi26RecordScoreResponseHeaders24getXPsnAtomicOperationIdEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE11getResponseERS8_() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEE11getResponseERS8_() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEENS4_INS2_18ResponseHeaderBaseEEEE11getResponseERS8_() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V121GetRankingRequestBodyEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122GetRankingResponseBodyEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V122RecordScoreRequestBodyEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V130GetBoardDefinitionResponseBodyEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V14UserEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V15EntryEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_12Leaderboards2V19RecordApi26RecordScoreResponseHeadersEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6BinaryEEptEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorINS3_INS1_12Leaderboards2V15EntryEEEEEEdeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_12Leaderboards2V123RecordScoreResponseBodyEEENS4_INS6_9RecordApi26RecordScoreResponseHeadersEEEE18getResponseHeadersERSB_() { + return SCE_NP_WEBAPI_ERROR_UNAVAILABLE; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common6Binary4sizeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common6String5c_strEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEEdeEv() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_12Leaderboards2V15EntryEEEEneERKS9_() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libSceNpEntitlementAccess/Export.cpp b/core/libs/prx/libSceNpEntitlementAccess/Export.cpp index bd68b6276..1e31e7b5a 100644 --- a/core/libs/prx/libSceNpEntitlementAccess/Export.cpp +++ b/core/libs/prx/libSceNpEntitlementAccess/Export.cpp @@ -3,36 +3,39 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +// No add-on content is installed; the base game is the full SKU. +static constexpr int SCE_NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER = static_cast(0x80558003); +static constexpr int SCE_NP_ENTITLEMENT_ACCESS_ERROR_NOT_FOUND = static_cast(0x80558007); +static constexpr uint32_t SKU_FLAG_FULL = 3; + extern "C" { int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfo(uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label, NpEntitlementAccessAddcontEntitlementInfo* info) { - (void)service_label; - (void)entitlement_label; - (void)info; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)service_label; + (void)entitlement_label; + (void)info; + return SCE_NP_ENTITLEMENT_ACCESS_ERROR_NOT_FOUND; } int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfoList(uint32_t service_label, NpEntitlementAccessAddcontEntitlementInfo* list, uint32_t list_num, uint32_t* hit_num) { - (void)service_label; - (void)list; - (void)list_num; - (void)hit_num; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)service_label; + (void)list; + (void)list_num; + if (!hit_num) return SCE_NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER; + *hit_num = 0; + return 0; } int APS5_VABI sceNpEntitlementAccessGetSkuFlag(uint32_t* sku_flag) { - (void)sku_flag; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!sku_flag) return SCE_NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER; + *sku_flag = SKU_FLAG_FULL; + return 0; } int APS5_VABI sceNpEntitlementAccessInitialize(const NpEntitlementAccessInitParam* init_param, NpEntitlementAccessBootParam* boot_param) { - (void)init_param; - (void)boot_param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)init_param; + (void)boot_param; + return 0; } } diff --git a/core/libs/prx/libSceNpManager/Export.cpp b/core/libs/prx/libSceNpManager/Export.cpp index 25d100387..dac4c2cfa 100644 --- a/core/libs/prx/libSceNpManager/Export.cpp +++ b/core/libs/prx/libSceNpManager/Export.cpp @@ -2,18 +2,25 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// PSN is not emulated: the user is reported as signed out and online queries fail. +static constexpr int SCE_NP_ERROR_INVALID_ARGUMENT = static_cast(0x80550003); +static constexpr int SCE_NP_ERROR_SIGNED_OUT = static_cast(0x80550006); +static constexpr uint32_t NP_STATE_SIGNED_OUT = 1; +static constexpr int NP_POLL_ASYNC_FINISHED = 0; + +static std::atomic g_nextRequest{1}; extern "C" { int APS5_VABI sceNpAbortRequest(int req_id) { - (void)req_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + return 0; } int APS5_VABI sceNpCheckCallback(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceNpCheckNpAvailability(int req_id, const char* user, void* result) { @@ -32,28 +39,24 @@ int APS5_VABI sceNpCheckNpReachability(int req_id, int user_id) { } int APS5_VABI sceNpCheckPremium(int req_id, const NpCheckPremiumParameter* param, NpCheckPremiumResult* result) { - (void)req_id; - (void)param; - (void)result; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + (void)param; + (void)result; + return SCE_NP_ERROR_SIGNED_OUT; } int APS5_VABI sceNpCreateAsyncRequest(const NpCreateAsyncRequestParameter* param) { - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)param; + return g_nextRequest.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpCreateRequest(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return g_nextRequest.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpDeleteRequest(int req_id) { - (void)req_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + return 0; } int APS5_VABI sceNpGetAccountAge(int req_id, int user_id, uint8_t* age) { @@ -65,17 +68,15 @@ int APS5_VABI sceNpGetAccountAge(int req_id, int user_id, uint8_t* age) { } int APS5_VABI sceNpGetAccountCountryA(int user_id, void* country_code) { - (void)user_id; - (void)country_code; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_id; + (void)country_code; + return SCE_NP_ERROR_SIGNED_OUT; } int APS5_VABI sceNpGetAccountIdA(int user_id, uint64_t* account_id) { - (void)user_id; - (void)account_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_id; + (void)account_id; + return SCE_NP_ERROR_SIGNED_OUT; } int APS5_VABI sceNpGetNpId(int user_id, NpId* np_id) { @@ -93,17 +94,16 @@ int APS5_VABI sceNpGetNpReachabilityState(int user_id, uint32_t* state) { } int APS5_VABI sceNpGetOnlineId(int user_id, NpOnlineId* online_id) { - (void)user_id; - (void)online_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_id; + (void)online_id; + return SCE_NP_ERROR_SIGNED_OUT; } int APS5_VABI sceNpGetState(int user_id, uint32_t* state) { - (void)user_id; - (void)state; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_id; + if (!state) return SCE_NP_ERROR_INVALID_ARGUMENT; + *state = NP_STATE_SIGNED_OUT; + return 0; } int APS5_VABI sceNpHasSignedUp(int user_id, bool* has_signed_up) { @@ -114,10 +114,9 @@ int APS5_VABI sceNpHasSignedUp(int user_id, bool* has_signed_up) { } int APS5_VABI sceNpPollAsync(int req_id, int* result) { - (void)req_id; - (void)result; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)req_id; + if (result) *result = SCE_NP_ERROR_SIGNED_OUT; + return NP_POLL_ASYNC_FINISHED; } void APS5_VABI sceNpRegisterGamePresenceCallback(void* callback, void* userdata) { @@ -161,10 +160,9 @@ int APS5_VABI sceNpSetContentRestriction(const NpContentRestriction* restriction } int APS5_VABI sceNpSetNpTitleId(const NpTitleId* title_id, const NpTitleSecret* title_secret) { - (void)title_id; - (void)title_secret; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)title_id; + (void)title_secret; + return 0; } int APS5_VABI sceNpUnregisterStateCallback(void) { @@ -172,4 +170,27 @@ int APS5_VABI sceNpUnregisterStateCallback(void) { return 0; } +int APS5_VABI sceNpGetAccountLanguage2(int req_id, int user_id, void* language) { + (void)req_id; + (void)user_id; + (void)language; + return SCE_NP_ERROR_SIGNED_OUT; +} + +int APS5_VABI sceNpNotifyPremiumFeature(const void* param) { + (void)param; + return 0; +} + +int APS5_VABI sceNpRegisterStateCallbackA(void* callback, void* userdata) { + (void)userdata; + if (!callback) return SCE_NP_ERROR_INVALID_ARGUMENT; + return 1; +} + +int APS5_VABI sceNpUnregisterStateCallbackA(int callback_id) { + (void)callback_id; + return 0; +} + } diff --git a/core/libs/prx/libSceNpSessionSignaling/Export.cpp b/core/libs/prx/libSceNpSessionSignaling/Export.cpp index 3440f62b4..02d4796b6 100644 --- a/core/libs/prx/libSceNpSessionSignaling/Export.cpp +++ b/core/libs/prx/libSceNpSessionSignaling/Export.cpp @@ -2,13 +2,47 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// Peer-to-peer signaling needs the network: contexts exist, but sessions never activate. +static constexpr int SCE_NP_SESSION_SIGNALING_ERROR_INVALID_ARGUMENT = static_cast(0x80552D02); +static constexpr int SCE_NP_SESSION_SIGNALING_ERROR_UNAVAILABLE = static_cast(0x80552D06); +static std::atomic g_nextContext{1}; extern "C" { int APS5_VABI sceNpSessionSignalingInitialize(void* param) { - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)param; + return 0; +} + +int APS5_VABI sceNpSessionSignalingActivateSession(void) { + return SCE_NP_SESSION_SIGNALING_ERROR_UNAVAILABLE; +} + +int APS5_VABI sceNpSessionSignalingCreateContext2(const void* param, uint32_t* context_id) { + (void)param; + if (!context_id) return SCE_NP_SESSION_SIGNALING_ERROR_INVALID_ARGUMENT; + *context_id = g_nextContext.fetch_add(1, std::memory_order_relaxed); + return 0; +} + +int APS5_VABI sceNpSessionSignalingDeactivate(uint32_t context_id) { + (void)context_id; + return 0; +} + +int APS5_VABI sceNpSessionSignalingDestroyContext(uint32_t context_id) { + (void)context_id; + return 0; +} + +int APS5_VABI sceNpSessionSignalingGetConnectionInfo(void) { + return SCE_NP_SESSION_SIGNALING_ERROR_UNAVAILABLE; +} + +int APS5_VABI sceNpSessionSignalingTerminate(void) { + return 0; } } diff --git a/core/libs/prx/libSceNpUtility/Export.cpp b/core/libs/prx/libSceNpUtility/Export.cpp new file mode 100644 index 000000000..ef15719ce --- /dev/null +++ b/core/libs/prx/libSceNpUtility/Export.cpp @@ -0,0 +1,10 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +int SceNpUtilityModuleLoaded_nid_no_patch = 1; + +} diff --git a/core/libs/prx/libSceNpWebApi2/Export.cpp b/core/libs/prx/libSceNpWebApi2/Export.cpp index a259e1912..7e9445433 100644 --- a/core/libs/prx/libSceNpWebApi2/Export.cpp +++ b/core/libs/prx/libSceNpWebApi2/Export.cpp @@ -2,142 +2,155 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// The PSN web API has no service behind it: handles can be created, but requests fail. +static constexpr int SCE_NP_WEBAPI2_ERROR_INVALID_ARGUMENT = static_cast(0x80553402); +static constexpr int SCE_NP_WEBAPI2_ERROR_UNAVAILABLE = static_cast(0x80553406); +static std::atomic g_nextHandle{1}; extern "C" { int APS5_VABI sceNpWebApi2AbortRequest(int64_t request_id) { - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + return 0; } int APS5_VABI sceNpWebApi2AddHttpRequestHeader(int64_t request_id, const char* field_name, const char* value) { - (void)request_id; - (void)field_name; - (void)value; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)field_name; + (void)value; + return 0; } void APS5_VABI sceNpWebApi2CheckTimeout(void) { - NotImplemented_nid_no_patch(__func__); } int APS5_VABI sceNpWebApi2CreateRequest(int user_context_id, const char* api_group, const char* path, const char* method, const void* content_parameter, int64_t* request_id) { - (void)user_context_id; - (void)api_group; - (void)path; - (void)method; - (void)content_parameter; - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_context_id; + (void)api_group; + (void)path; + (void)method; + (void)content_parameter; + if (!request_id) return SCE_NP_WEBAPI2_ERROR_INVALID_ARGUMENT; + *request_id = g_nextHandle.fetch_add(1, std::memory_order_relaxed); + return 0; } int APS5_VABI sceNpWebApi2CreateUserContext(int lib_ctx_id, int user_id) { - (void)lib_ctx_id; - (void)user_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_ctx_id; + (void)user_id; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpWebApi2DeleteRequest(int64_t request_id) { - (void)request_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + return 0; } int APS5_VABI sceNpWebApi2DeleteUserContext(int user_context_id) { - (void)user_context_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_context_id; + return 0; } int APS5_VABI sceNpWebApi2GetHttpResponseHeaderValue(int64_t request_id, const char* field_name, char* value, size_t value_size) { - (void)request_id; - (void)field_name; - (void)value; - (void)value_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)field_name; + (void)value; + (void)value_size; + return SCE_NP_WEBAPI2_ERROR_UNAVAILABLE; } int APS5_VABI sceNpWebApi2GetHttpResponseHeaderValueLength(int64_t request_id, const char* field_name, size_t* value_length) { - (void)request_id; - (void)field_name; - (void)value_length; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)field_name; + (void)value_length; + return SCE_NP_WEBAPI2_ERROR_UNAVAILABLE; } int APS5_VABI sceNpWebApi2Initialize(int lib_http_ctx_id, size_t pool_size) { - (void)lib_http_ctx_id; - (void)pool_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_http_ctx_id; + (void)pool_size; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpWebApi2PushEventCreateFilter(int lib_ctx_id, int handle_id, const char* np_service_name, uint32_t np_service_label, const void* filter_param, size_t filter_param_num) { - (void)lib_ctx_id; - (void)handle_id; - (void)np_service_name; - (void)np_service_label; - (void)filter_param; - (void)filter_param_num; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_ctx_id; + (void)handle_id; + (void)np_service_name; + (void)np_service_label; + (void)filter_param; + (void)filter_param_num; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpWebApi2PushEventCreateHandle(int lib_ctx_id) { - (void)lib_ctx_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_ctx_id; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpWebApi2PushEventDeleteHandle(int lib_ctx_id, int handle_id) { - (void)lib_ctx_id; - (void)handle_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_ctx_id; + (void)handle_id; + return 0; } int APS5_VABI sceNpWebApi2PushEventDeletePushContext(int user_context_id, const void* push_context_id) { - (void)user_context_id; - (void)push_context_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_context_id; + (void)push_context_id; + return 0; } int APS5_VABI sceNpWebApi2PushEventRegisterCallback(int user_context_id, int filter_id, void* callback, void* user_arg) { - (void)user_context_id; - (void)filter_id; - (void)callback; - (void)user_arg; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)user_context_id; + (void)filter_id; + (void)callback; + (void)user_arg; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceNpWebApi2ReadData(int64_t request_id, void* data, size_t size) { - (void)request_id; - (void)data; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)data; + (void)size; + return SCE_NP_WEBAPI2_ERROR_UNAVAILABLE; } int APS5_VABI sceNpWebApi2SendRequest(int64_t request_id, const void* data, size_t data_size, NpWebApi2ResponseInformationOption* response_info_option) { - (void)request_id; - (void)data; - (void)data_size; - (void)response_info_option; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)request_id; + (void)data; + (void)data_size; + (void)response_info_option; + return SCE_NP_WEBAPI2_ERROR_UNAVAILABLE; } int APS5_VABI sceNpWebApi2Terminate(int lib_ctx_id) { - (void)lib_ctx_id; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)lib_ctx_id; + return 0; +} + +int APS5_VABI sceNpWebApi2PushEventCreatePushContext() { + return SCE_NP_WEBAPI2_ERROR_UNAVAILABLE; +} + +int APS5_VABI sceNpWebApi2PushEventDeleteFilter() { + return 0; +} + +int APS5_VABI sceNpWebApi2PushEventRegisterPushContextCallback() { + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); +} + +int APS5_VABI sceNpWebApi2PushEventStartPushContextCallback() { + return 0; +} + +int APS5_VABI sceNpWebApi2PushEventUnregisterCallback() { + return 0; +} + +int APS5_VABI sceNpWebApi2PushEventUnregisterPushContextCallback() { + return 0; } } diff --git a/core/libs/prx/libScePad/Export.cpp b/core/libs/prx/libScePad/Export.cpp index e669eb474..be2cc63e1 100644 --- a/core/libs/prx/libScePad/Export.cpp +++ b/core/libs/prx/libScePad/Export.cpp @@ -87,12 +87,14 @@ int APS5_VABI scePadOpen_nid_postfix(int userId, int type, int index, const void return PAD_HANDLE; } +int APS5_VABI scePadReadState(int handle, PadData* data); + int APS5_VABI scePadRead_nid_postfix(int handle, PadData* data, int num) { - (void)handle; - (void)data; - (void)num; - NotImplemented_nid_no_patch(__func__); - return 0; + // The title drains the queued states; one current state is reported per call. + if (data == nullptr || num <= 0) APS5_INVALID_ARG_EX; + const int result = scePadReadState(handle, data); + if (result != 0) return result; + return 1; } int APS5_VABI scePadReadState(int handle, PadData* data) { diff --git a/core/libs/prx/libScePlayGo/Export.cpp b/core/libs/prx/libScePlayGo/Export.cpp index 38d08555c..68524329c 100644 --- a/core/libs/prx/libScePlayGo/Export.cpp +++ b/core/libs/prx/libScePlayGo/Export.cpp @@ -2,31 +2,86 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include +#include +#include +#include +#include + +// The game is fully installed on the host, so every chunk is local and nothing is pending. +static constexpr int SCE_PLAYGO_ERROR_BAD_POINTER = static_cast(0x80B20004); +static constexpr int SCE_PLAYGO_ERROR_BAD_HANDLE = static_cast(0x80B20005); +static constexpr int PLAYGO_HANDLE = 1; +static constexpr int8_t PLAYGO_LOCUS_LOCAL_FAST = 3; +static constexpr int32_t PLAYGO_INSTALL_SPEED_FULL = 2; + +static int32_t g_installSpeed = PLAYGO_INSTALL_SPEED_FULL; + +static constexpr int SCE_PLAYGO_ERROR_BAD_CHUNK_ID = static_cast(0x80B2000C); +static constexpr int SCE_PLAYGO_ERROR_BAD_SIZE = static_cast(0x80B2000D); + +// The package's chunk table is not part of the dump, so the chunk set comes from the title's +// playgo-chunkdefs.xml: every listed chunk plus chunks 0 through the default chunk. Games probe +// chunk IDs and size arrays from the result, so unknown IDs must be rejected. +static const std::set& ValidChunks() { + static const std::set chunks = [] { + std::set result{0}; + std::ifstream file(ResolvePath_nid_no_patch("/app0/playgo-chunkdefs.xml")); + if (!file) return result; + const std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + static const std::regex chunk(R"re((std::stoul((*it)[1].str()))); + static const std::regex defaultChunk(R"re(default_chunk="(\d+)")re"); + std::smatch match; + if (std::regex_search(text, match, defaultChunk)) { + const auto last = std::stoul(match[1].str()); + for (unsigned long id = 0; id <= last && id <= 0xFFFF; ++id) result.insert(static_cast(id)); + } + return result; + }(); + return chunks; +} + +static int ValidateChunks(const uint16_t* chunk_ids, uint32_t number_of_entries) { + if (!chunk_ids) return SCE_PLAYGO_ERROR_BAD_POINTER; + if (number_of_entries == 0) return SCE_PLAYGO_ERROR_BAD_SIZE; + const auto& valid = ValidChunks(); + for (uint32_t index = 0; index < number_of_entries; ++index) + if (!valid.contains(chunk_ids[index])) return SCE_PLAYGO_ERROR_BAD_CHUNK_ID; + return 0; +} extern "C" { int APS5_VABI scePlayGoClose(int handle) { - (void)handle; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + return 0; } int APS5_VABI scePlayGoGetChunkId(int handle, uint16_t* out_chunk_id_list, uint32_t number_of_entries, uint32_t* out_entries) { - (void)handle; - (void)out_chunk_id_list; - (void)number_of_entries; - (void)out_entries; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + if (!out_entries) return SCE_PLAYGO_ERROR_BAD_POINTER; + const auto& valid = ValidChunks(); + if (!out_chunk_id_list) { + *out_entries = static_cast(valid.size()); + return 0; + } + uint32_t written = 0; + for (const auto id : valid) { + if (written == number_of_entries) break; + out_chunk_id_list[written++] = id; + } + *out_entries = written; + return 0; } int APS5_VABI scePlayGoGetEta(int handle, const uint16_t* chunk_ids, uint32_t number_of_entries, int64_t* out_eta) { - (void)handle; - (void)chunk_ids; - (void)number_of_entries; - (void)out_eta; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + if (!out_eta) return SCE_PLAYGO_ERROR_BAD_POINTER; + if (const int error = ValidateChunks(chunk_ids, number_of_entries)) return error; + *out_eta = 0; + return 0; } int APS5_VABI scePlayGoGetInstallChunkId(int handle, uint16_t* out_chunk_id_list, uint32_t number_of_entries, uint32_t* out_entries) { @@ -39,10 +94,10 @@ int APS5_VABI scePlayGoGetInstallChunkId(int handle, uint16_t* out_chunk_id_list } int APS5_VABI scePlayGoGetInstallSpeed(int handle, int32_t* out_speed) { - (void)handle; - (void)out_speed; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + if (!out_speed) return SCE_PLAYGO_ERROR_BAD_POINTER; + *out_speed = g_installSpeed; + return 0; } int APS5_VABI scePlayGoGetLanguageMask(int handle, uint64_t* out_language_mask) { @@ -53,83 +108,76 @@ int APS5_VABI scePlayGoGetLanguageMask(int handle, uint64_t* out_language_mask) } int APS5_VABI scePlayGoGetLocus(int handle, const uint16_t* chunk_ids, uint32_t number_of_entries, int8_t* out_loci) { - (void)handle; - (void)chunk_ids; - (void)number_of_entries; - (void)out_loci; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + if (!out_loci) return SCE_PLAYGO_ERROR_BAD_POINTER; + if (const int error = ValidateChunks(chunk_ids, number_of_entries)) return error; + for (uint32_t index = 0; index < number_of_entries; ++index) out_loci[index] = PLAYGO_LOCUS_LOCAL_FAST; + return 0; } int APS5_VABI scePlayGoGetOptionalChunk(int handle, int32_t type, PlayGoOptionalChunk* option) { - (void)handle; - (void)type; - (void)option; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + (void)type; + if (!option) return SCE_PLAYGO_ERROR_BAD_POINTER; + option->bitmask = 0; + return 0; } int APS5_VABI scePlayGoGetProgress(int handle, const uint16_t* chunk_ids, uint32_t number_of_entries, PlayGoProgress* out_progress) { - (void)handle; - (void)chunk_ids; - (void)number_of_entries; - (void)out_progress; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + if (!out_progress) return SCE_PLAYGO_ERROR_BAD_POINTER; + if (const int error = ValidateChunks(chunk_ids, number_of_entries)) return error; + out_progress->progress_size = 1; + out_progress->total_size = 1; + return 0; } int APS5_VABI scePlayGoGetSupportedOptionalChunk(int handle, int32_t type, PlayGoOptionalChunk* option) { - (void)handle; - (void)type; - (void)option; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + (void)type; + if (!option) return SCE_PLAYGO_ERROR_BAD_POINTER; + option->bitmask = 0; + return 0; } int APS5_VABI scePlayGoGetToDoList(int handle, PlayGoToDo* out_todo_list, uint32_t number_of_entries, uint32_t* out_entries) { - (void)handle; - (void)out_todo_list; - (void)number_of_entries; - (void)out_entries; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + (void)out_todo_list; + (void)number_of_entries; + if (!out_entries) return SCE_PLAYGO_ERROR_BAD_POINTER; + *out_entries = 0; + return 0; } int APS5_VABI scePlayGoInitialize(const PlayGoInitParams* init) { - (void)init; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!init) return SCE_PLAYGO_ERROR_BAD_POINTER; + return 0; } int APS5_VABI scePlayGoOpen(int* out_handle, const void* param) { - (void)out_handle; - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)param; + if (!out_handle) return SCE_PLAYGO_ERROR_BAD_POINTER; + *out_handle = PLAYGO_HANDLE; + return 0; } int APS5_VABI scePlayGoPrefetch(int handle, const uint16_t* chunk_ids, uint32_t number_of_entries, int8_t minimum_locus) { - (void)handle; - (void)chunk_ids; - (void)number_of_entries; - (void)minimum_locus; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + (void)minimum_locus; + return ValidateChunks(chunk_ids, number_of_entries); } int APS5_VABI scePlayGoPrefetchOptionalChunk(int handle, int32_t type, const PlayGoOptionalChunk* option) { - (void)handle; - (void)type; - (void)option; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + (void)type; + (void)option; + return 0; } int APS5_VABI scePlayGoSetInstallSpeed(int handle, int32_t speed) { - (void)handle; - (void)speed; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle != PLAYGO_HANDLE) return SCE_PLAYGO_ERROR_BAD_HANDLE; + g_installSpeed = speed; + return 0; } int APS5_VABI scePlayGoSetToDoList(int handle, const PlayGoToDo* todo_list, uint32_t number_of_entries) { @@ -141,8 +189,7 @@ int APS5_VABI scePlayGoSetToDoList(int handle, const PlayGoToDo* todo_list, uint } int APS5_VABI scePlayGoTerminate(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } } diff --git a/core/libs/prx/libScePngEnc/Export.cpp b/core/libs/prx/libScePngEnc/Export.cpp new file mode 100644 index 000000000..5c131543d --- /dev/null +++ b/core/libs/prx/libScePngEnc/Export.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +int APS5_VABI scePngEncCreate() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI scePngEncDelete() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI scePngEncEncode() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI scePngEncQueryMemorySize() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libScePsml_debug/Export.cpp b/core/libs/prx/libScePsml_debug/Export.cpp new file mode 100644 index 000000000..67d7cf76b --- /dev/null +++ b/core/libs/prx/libScePsml_debug/Export.cpp @@ -0,0 +1,86 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +extern "C" { + +APS5_EXPORT("+2KpvixvL6E", scePsmlUnknown__P2KpvixvL6E); +int APS5_VABI scePsmlUnknown__P2KpvixvL6E() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("3WVD91e12ZQ", scePsmlUnknown_3WVD91e12ZQ); +int APS5_VABI scePsmlUnknown_3WVD91e12ZQ() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("AHalTX9wFZY", scePsmlUnknown_AHalTX9wFZY); +int APS5_VABI scePsmlUnknown_AHalTX9wFZY() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("ArakEpzsZo0", scePsmlUnknown_ArakEpzsZo0); +int APS5_VABI scePsmlUnknown_ArakEpzsZo0() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("FSGaTQze0UY", scePsmlUnknown_FSGaTQze0UY); +int APS5_VABI scePsmlUnknown_FSGaTQze0UY() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("GHna9-DvnUk", scePsmlUnknown_GHna9_MDvnUk); +int APS5_VABI scePsmlUnknown_GHna9_MDvnUk() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("GJY0MvuTcs8", scePsmlUnknown_GJY0MvuTcs8); +int APS5_VABI scePsmlUnknown_GJY0MvuTcs8() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("JaLBe0P3jSU", scePsmlUnknown_JaLBe0P3jSU); +int APS5_VABI scePsmlUnknown_JaLBe0P3jSU() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("LXq+6mIxpCw", scePsmlUnknown_LXq_P6mIxpCw); +int APS5_VABI scePsmlUnknown_LXq_P6mIxpCw() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("RUNLFro+qok", scePsmlUnknown_RUNLFro_Pqok); +int APS5_VABI scePsmlUnknown_RUNLFro_Pqok() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("eWoKNeB6V-k", scePsmlUnknown_eWoKNeB6V_Mk); +int APS5_VABI scePsmlUnknown_eWoKNeB6V_Mk() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("gxv3i+MTEzU", scePsmlUnknown_gxv3i_PMTEzU); +int APS5_VABI scePsmlUnknown_gxv3i_PMTEzU() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +APS5_EXPORT("jEevBXmagOQ", scePsmlUnknown_jEevBXmagOQ); +int APS5_VABI scePsmlUnknown_jEevBXmagOQ() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +} diff --git a/core/libs/prx/libSceSaveData.native/Export.cpp b/core/libs/prx/libSceSaveData.native/Export.cpp index 1672db2ef..ce6f82d14 100644 --- a/core/libs/prx/libSceSaveData.native/Export.cpp +++ b/core/libs/prx/libSceSaveData.native/Export.cpp @@ -1,5 +1,11 @@ +#include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -18,6 +24,24 @@ static std::string save_root() { return std::string(SAVE_DIR); } +// Events the title polls with sceSaveDataGetEventResult (a backup completes at once here), and the +// "save data memory" blobs (small per-slot memories the title reads and writes without mounting), +// persisted as files under the save root so they survive restarts. +static std::mutex g_state_mutex; +static std::deque g_events; +static std::map> g_memories; +constexpr std::uint32_t SAVE_DATA_EVENT_TYPE_BACKUP = 2; + +static std::string memory_path(std::uint32_t slot) { + return save_root() + "/_memory_" + std::to_string(slot) + ".bin"; +} + +static void store_memory(std::uint32_t slot, const std::vector& memory) { + std::filesystem::create_directories(save_root()); + std::ofstream file(memory_path(slot), std::ios::binary | std::ios::trunc); + file.write(reinterpret_cast(memory.data()), static_cast(memory.size())); +} + static bool dir_name_match(const char* str, const char* pattern) { if (pattern == nullptr || pattern[0] == '\0') { return true; @@ -51,9 +75,20 @@ static bool dir_name_match(const char* str, const char* pattern) { extern "C" { int APS5_VABI sceSaveDataBackup(const SaveDataBackup* backup) { - (void)backup; - NotImplemented_nid_no_patch(__func__); - return 0; + if (backup == nullptr || backup->dir_name == nullptr) { + throw std::runtime_error("sceSaveDataBackup: null argument"); + } + // The system copies the save directory to its backup area asynchronously; the copy itself is + // not observable by the title, only its completion event. + SaveDataEvent event{}; + event.type = SAVE_DATA_EVENT_TYPE_BACKUP; + event.error_code = SAVE_DATA_OK; + event.user_id = backup->user_id; + if (backup->title_id != nullptr) event.title_id = *backup->title_id; + event.dir_name = *backup->dir_name; + std::lock_guard lock(g_state_mutex); + g_events.push_back(event); + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataCommit(const SaveDataCommitParam* param) { @@ -119,9 +154,16 @@ int APS5_VABI sceSaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond, Sa int APS5_VABI sceSaveDataGetEventResult(const void* event_param, SaveDataEvent* event) { (void)event_param; - (void)event; - NotImplemented_nid_no_patch(__func__); - return 0; + if (event == nullptr) { + throw std::runtime_error("sceSaveDataGetEventResult: null event"); + } + std::lock_guard lock(g_state_mutex); + if (g_events.empty()) { + return SAVE_DATA_ERROR_NOT_FOUND; + } + *event = g_events.front(); + g_events.pop_front(); + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataGetMountInfo(const SaveDataMountPoint* mount_point, SaveDataMountInfo* info) { @@ -153,9 +195,25 @@ int APS5_VABI sceSaveDataGetParam(const SaveDataMountPoint* mount_point, uint32_ } int APS5_VABI sceSaveDataGetSaveDataMemory2(SaveDataMemoryGet2* get_param) { - (void)get_param; - NotImplemented_nid_no_patch(__func__); - return 0; + if (get_param == nullptr) { + throw std::runtime_error("sceSaveDataGetSaveDataMemory2: null argument"); + } + std::lock_guard lock(g_state_mutex); + const auto it = g_memories.find(get_param->slot_id); + if (it == g_memories.end()) { + return SAVE_DATA_ERROR_NOT_FOUND; + } + if (get_param->data != nullptr && get_param->data->buf != nullptr) { + const auto& memory = it->second; + if (get_param->data->offset > memory.size()) { + return SAVE_DATA_ERROR_PARAMETER; + } + const auto bytes = std::min(get_param->data->buf_size, memory.size() - get_param->data->offset); + std::memcpy(get_param->data->buf, memory.data() + get_param->data->offset, bytes); + } + if (get_param->param != nullptr) std::memset(get_param->param, 0, sizeof(SaveDataParam)); + if (get_param->icon != nullptr) get_param->icon->data_size = 0; + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataInitialize3(const void* init) { @@ -204,12 +262,10 @@ int APS5_VABI sceSaveDataMount3(const SaveDataMount3* mount, SaveDataMountResult throw std::runtime_error("sceSaveDataMount3: invalid directory name"); } const std::string real_path = save_root() + "/" + dirName; - const std::string mountPoint = "/" + real_path; - if (mountPoint.size() >= sizeof(mount_result->mount_point.data)) { - throw std::runtime_error("sceSaveDataMount3: directory path exceeds mount point capacity"); - } - if (find_slot_by_mount_point(mountPoint.c_str()) != -1) { - return SAVE_DATA_ERROR_BUSY; + for (const auto& used : g_slots) { + if (used.used && used.real_path == real_path) { + return SAVE_DATA_ERROR_BUSY; + } } const bool exists = std::filesystem::is_directory(real_path); if (create && exists) { @@ -225,6 +281,10 @@ int APS5_VABI sceSaveDataMount3(const SaveDataMount3* mount, SaveDataMountResult if (create || create2) { std::filesystem::create_directories(real_path); } + // The title gets a short mount point (16 bytes on the PS5) and opens files under it; the + // path resolver maps it to the save directory, whose name may be far longer. + const std::string mountPoint = "/_sm/" + std::to_string(slot); + AddPathAlias_nid_no_patch(mountPoint.c_str(), std::filesystem::absolute(real_path).string().c_str()); g_slots[slot].used = true; g_slots[slot].mount_point = mountPoint; g_slots[slot].real_path = real_path; @@ -271,22 +331,61 @@ int APS5_VABI sceSaveDataSetParam(const SaveDataMountPoint* mount_point, uint32_ } int APS5_VABI sceSaveDataSetSaveDataMemory2(const SaveDataMemorySet2* set_param) { - (void)set_param; - NotImplemented_nid_no_patch(__func__); - return 0; + if (set_param == nullptr) { + throw std::runtime_error("sceSaveDataSetSaveDataMemory2: null argument"); + } + std::lock_guard lock(g_state_mutex); + const auto it = g_memories.find(set_param->slot_id); + if (it == g_memories.end()) { + return SAVE_DATA_ERROR_NOT_FOUND; + } + auto& memory = it->second; + if (set_param->data != nullptr) { + const auto count = set_param->data_num == 0 ? 1u : set_param->data_num; + for (std::uint32_t i = 0; i < count; ++i) { + const auto& data = set_param->data[i]; + if (data.buf == nullptr) continue; + if (data.offset > memory.size() || data.buf_size > memory.size() - data.offset) { + return SAVE_DATA_ERROR_PARAMETER; + } + std::memcpy(memory.data() + data.offset, data.buf, data.buf_size); + } + } + store_memory(set_param->slot_id, memory); + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataSetupSaveDataMemory2(const SaveDataMemorySetup2* setup_param, SaveDataMemorySetupResult* result) { - (void)setup_param; - (void)result; - NotImplemented_nid_no_patch(__func__); - return 0; + if (setup_param == nullptr) { + throw std::runtime_error("sceSaveDataSetupSaveDataMemory2: null argument"); + } + std::lock_guard lock(g_state_mutex); + auto& memory = g_memories[setup_param->slot_id]; + std::size_t existed = 0; + if (memory.empty()) { + std::ifstream file(memory_path(setup_param->slot_id), std::ios::binary); + if (file) { + memory.assign(std::istreambuf_iterator(file), std::istreambuf_iterator()); + existed = memory.size(); + } + } else { + existed = memory.size(); + } + if (memory.size() < setup_param->memory_size) { + memory.resize(setup_param->memory_size, 0); + } + if (existed == 0) store_memory(setup_param->slot_id, memory); + if (result != nullptr) { + std::memset(result, 0, sizeof(*result)); + result->existed_memory_size = existed; + } + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataSyncSaveDataMemory(const void* sync_param) { (void)sync_param; - NotImplemented_nid_no_patch(__func__); - return 0; + // Every Set already reached the file; nothing is buffered. + return SAVE_DATA_OK; } int APS5_VABI sceSaveDataTerminate(void) { @@ -316,6 +415,7 @@ int APS5_VABI sceSaveDataUmount2(uint32_t mode, const SaveDataMountPoint* mount_ if (slot == -1) { return SAVE_DATA_ERROR_NOT_MOUNTED; } + RemovePathAlias_nid_no_patch(g_slots[slot].mount_point.c_str()); g_slots[slot] = MountSlot{}; return SAVE_DATA_OK; } diff --git a/core/libs/prx/libSceShare.native/Export.cpp b/core/libs/prx/libSceShare.native/Export.cpp index a2969e98a..2d8f2cf36 100644 --- a/core/libs/prx/libSceShare.native/Export.cpp +++ b/core/libs/prx/libSceShare.native/Export.cpp @@ -3,6 +3,8 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +// Capture and sharing are not emulated; policy and parameter calls are accepted. + extern "C" { int APS5_VABI sceShareCaptureScreenshot(const void* param, int32_t* req_id) { @@ -20,15 +22,13 @@ int APS5_VABI sceShareCaptureVideoClip(const void* param, int32_t* req_id) { } int APS5_VABI sceShareFeaturePermit(uint32_t feature_flags) { - (void)feature_flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)feature_flags; + return 0; } int APS5_VABI sceShareFeatureProhibit(uint32_t feature_flags) { - (void)feature_flags; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)feature_flags; + return 0; } int APS5_VABI sceShareGetCurrentStatus(uint32_t feature_flag, ShareCurrentStatus* status) { @@ -39,11 +39,10 @@ int APS5_VABI sceShareGetCurrentStatus(uint32_t feature_flag, ShareCurrentStatus } int APS5_VABI sceShareInitialize(size_t heap_size, int thread_priority, uint64_t affinity_mask) { - (void)heap_size; - (void)thread_priority; - (void)affinity_mask; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)heap_size; + (void)thread_priority; + (void)affinity_mask; + return 0; } int APS5_VABI sceShareOpenMenuForContent(const void* content_id) { @@ -53,43 +52,37 @@ int APS5_VABI sceShareOpenMenuForContent(const void* content_id) { } int APS5_VABI sceShareRegisterContentEventCallback(void* callback, void* user_data) { - (void)callback; - (void)user_data; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)callback; + (void)user_data; + return 0; } int APS5_VABI sceShareSetCaptureSource(uint32_t feature_flags, const void* tap_point) { - (void)feature_flags; - (void)tap_point; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)feature_flags; + (void)tap_point; + return 0; } int APS5_VABI sceShareSetContentParam(const char* content_param) { - (void)content_param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)content_param; + return 0; } int APS5_VABI sceShareSetScreenshotOverlayImage(const char* file_path, int32_t margin_x, int32_t margin_y, int32_t origin) { - (void)file_path; - (void)margin_x; - (void)margin_y; - (void)origin; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)file_path; + (void)margin_x; + (void)margin_y; + (void)origin; + return 0; } int APS5_VABI sceShareTerminate(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceShareUnregisterContentEventCallback(void* callback) { - (void)callback; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)callback; + return 0; } } diff --git a/core/libs/prx/libSceShare/Export.cpp b/core/libs/prx/libSceShare/Export.cpp new file mode 100644 index 000000000..2d8f2cf36 --- /dev/null +++ b/core/libs/prx/libSceShare/Export.cpp @@ -0,0 +1,88 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" + +// Capture and sharing are not emulated; policy and parameter calls are accepted. + +extern "C" { + +int APS5_VABI sceShareCaptureScreenshot(const void* param, int32_t* req_id) { + (void)param; + (void)req_id; + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceShareCaptureVideoClip(const void* param, int32_t* req_id) { + (void)param; + (void)req_id; + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceShareFeaturePermit(uint32_t feature_flags) { + (void)feature_flags; + return 0; +} + +int APS5_VABI sceShareFeatureProhibit(uint32_t feature_flags) { + (void)feature_flags; + return 0; +} + +int APS5_VABI sceShareGetCurrentStatus(uint32_t feature_flag, ShareCurrentStatus* status) { + (void)feature_flag; + (void)status; + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceShareInitialize(size_t heap_size, int thread_priority, uint64_t affinity_mask) { + (void)heap_size; + (void)thread_priority; + (void)affinity_mask; + return 0; +} + +int APS5_VABI sceShareOpenMenuForContent(const void* content_id) { + (void)content_id; + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceShareRegisterContentEventCallback(void* callback, void* user_data) { + (void)callback; + (void)user_data; + return 0; +} + +int APS5_VABI sceShareSetCaptureSource(uint32_t feature_flags, const void* tap_point) { + (void)feature_flags; + (void)tap_point; + return 0; +} + +int APS5_VABI sceShareSetContentParam(const char* content_param) { + (void)content_param; + return 0; +} + +int APS5_VABI sceShareSetScreenshotOverlayImage(const char* file_path, int32_t margin_x, int32_t margin_y, int32_t origin) { + (void)file_path; + (void)margin_x; + (void)margin_y; + (void)origin; + return 0; +} + +int APS5_VABI sceShareTerminate(void) { + return 0; +} + +int APS5_VABI sceShareUnregisterContentEventCallback(void* callback) { + (void)callback; + return 0; +} + +} diff --git a/core/libs/prx/libSceSsl/Export.cpp b/core/libs/prx/libSceSsl/Export.cpp index d4754b2df..9801185d6 100644 --- a/core/libs/prx/libSceSsl/Export.cpp +++ b/core/libs/prx/libSceSsl/Export.cpp @@ -2,6 +2,12 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include + +// No network is emulated: contexts, templates and requests can be created, but any request +// that would touch the network fails with the library's network error. +static constexpr int ERROR_NETWORK = static_cast(0x80435001); +static std::atomic g_nextHandle{1}; extern "C" { @@ -20,13 +26,21 @@ int APS5_VABI sceSslGetCaCerts(int ssl_ctx_id, void* ca_certs) { } int APS5_VABI sceSslInit_nid_postfix(uint64_t pool_size) { - (void)pool_size; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)pool_size; + return g_nextHandle.fetch_add(1, std::memory_order_relaxed); } int APS5_VABI sceSslTerm_nid_postfix(int ssl_ctx_id) { - (void)ssl_ctx_id; + (void)ssl_ctx_id; + return 0; +} + +int APS5_VABI sceSslClose() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceSslGetSerialNumber() { NotImplemented_nid_no_patch(__func__); return 0; } diff --git a/core/libs/prx/libSceSystemGesture/Export.cpp b/core/libs/prx/libSceSystemGesture/Export.cpp index 64d5134aa..61f241f15 100644 --- a/core/libs/prx/libSceSystemGesture/Export.cpp +++ b/core/libs/prx/libSceSystemGesture/Export.cpp @@ -3,6 +3,12 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +// No touch input is emulated: recognizers exist but never report events. +static constexpr int32_t GESTURE_HANDLE = 1; +static constexpr int SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT = static_cast(0x80D10002); +static constexpr int SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE = static_cast(0x80D10003); +static constexpr int SCE_SYSTEM_GESTURE_ERROR_INDEX_OUT_OF_ARRAY = static_cast(0x80D10005); + extern "C" { int APS5_VABI sceSystemGestureAppendTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer) { @@ -13,24 +19,20 @@ int APS5_VABI sceSystemGestureAppendTouchRecognizer(int32_t gesture_handle, Syst } int APS5_VABI sceSystemGestureClose(int32_t gesture_handle) { - (void)gesture_handle; - NotImplemented_nid_no_patch(__func__); - return 0; + return gesture_handle == GESTURE_HANDLE ? 0 : SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; } int APS5_VABI sceSystemGestureCreateTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer, int32_t type, const SystemGestureRectangle* rectangle, const void* param) { - (void)gesture_handle; - (void)recognizer; - (void)type; - (void)rectangle; - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)type; + (void)rectangle; + (void)param; + if (gesture_handle != GESTURE_HANDLE) return SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; + if (!recognizer) return SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT; + return 0; } int APS5_VABI sceSystemGestureFinalizePrimitiveTouchRecognizer(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 0; } int APS5_VABI sceSystemGestureGetPrimitiveTouchEventByIndex(int32_t gesture_handle, uint32_t index, SystemGesturePrimitiveTouchEvent* event) { @@ -74,12 +76,11 @@ int APS5_VABI sceSystemGestureGetTouchEventByEventID(int32_t gesture_handle, con } int APS5_VABI sceSystemGestureGetTouchEventByIndex(int32_t gesture_handle, const SystemGestureTouchRecognizer* recognizer, uint32_t index, SystemGestureTouchEvent* event) { - (void)gesture_handle; - (void)recognizer; - (void)index; - (void)event; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)gesture_handle; + (void)recognizer; + (void)index; + (void)event; + return SCE_SYSTEM_GESTURE_ERROR_INDEX_OUT_OF_ARRAY; } int APS5_VABI sceSystemGestureGetTouchEvents(int32_t gesture_handle, const SystemGestureTouchRecognizer* recognizer, SystemGestureTouchEvent* event_buffer, uint32_t capacity_of_buffer, uint32_t* number_of_event) { @@ -93,10 +94,8 @@ int APS5_VABI sceSystemGestureGetTouchEvents(int32_t gesture_handle, const Syste } int APS5_VABI sceSystemGestureGetTouchEventsCount(int32_t gesture_handle, const SystemGestureTouchRecognizer* recognizer) { - (void)gesture_handle; - (void)recognizer; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)recognizer; + return gesture_handle == GESTURE_HANDLE ? 0 : SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; } int APS5_VABI sceSystemGestureGetTouchRecognizerInformation(int32_t gesture_handle, const SystemGestureTouchRecognizer* recognizer, SystemGestureTouchRecognizerInformation* information) { @@ -108,16 +107,14 @@ int APS5_VABI sceSystemGestureGetTouchRecognizerInformation(int32_t gesture_hand } int APS5_VABI sceSystemGestureInitializePrimitiveTouchRecognizer(const void* param) { - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)param; + return 0; } int32_t APS5_VABI sceSystemGestureOpen(int32_t input_type, const void* param) { - (void)input_type; - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)input_type; + (void)param; + return GESTURE_HANDLE; } int APS5_VABI sceSystemGestureRemoveTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer) { @@ -147,17 +144,13 @@ int APS5_VABI sceSystemGestureUpdateAllTouchRecognizer(int32_t gesture_handle) { } int APS5_VABI sceSystemGestureUpdatePrimitiveTouchRecognizer(int32_t gesture_handle, const void* param) { - (void)gesture_handle; - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)param; + return gesture_handle == GESTURE_HANDLE ? 0 : SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; } int APS5_VABI sceSystemGestureUpdateTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer) { - (void)gesture_handle; - (void)recognizer; - NotImplemented_nid_no_patch(__func__); - return 0; + (void)recognizer; + return gesture_handle == GESTURE_HANDLE ? 0 : SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; } int APS5_VABI sceSystemGestureUpdateTouchRecognizerRectangle(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer, const SystemGestureRectangle* rectangle) { diff --git a/core/libs/prx/libSceSystemService/Export.cpp b/core/libs/prx/libSceSystemService/Export.cpp index 3756dc36f..38277e0d9 100644 --- a/core/libs/prx/libSceSystemService/Export.cpp +++ b/core/libs/prx/libSceSystemService/Export.cpp @@ -13,9 +13,12 @@ int APS5_VABI sceSystemServiceDisableNoticeScreenSkipFlagAutoSet(void) { } int APS5_VABI sceSystemServiceGetDisplaySafeAreaInfo(SystemServiceDisplaySafeAreaInfo* info) { - (void)info; - NotImplemented_nid_no_patch(__func__); - return 0; + if (info == nullptr) { + return SYSTEM_SERVICE_ERROR_PARAMETER; + } + *info = SystemServiceDisplaySafeAreaInfo{}; + info->ratio = 1.0f; + return SYSTEM_SERVICE_OK; } int APS5_VABI sceSystemServiceGetHdrToneMapLuminance(SystemServiceHdrToneMapLuminance* luminance) { @@ -25,9 +28,11 @@ int APS5_VABI sceSystemServiceGetHdrToneMapLuminance(SystemServiceHdrToneMapLumi } int APS5_VABI sceSystemServiceGetNoticeScreenSkipFlag(bool* value) { - (void)value; - NotImplemented_nid_no_patch(__func__); - return 0; + if (value == nullptr) { + return SYSTEM_SERVICE_ERROR_PARAMETER; + } + *value = false; + return SYSTEM_SERVICE_OK; } int APS5_VABI sceSystemServiceGetStatus(SystemServiceStatus* status) { @@ -76,8 +81,6 @@ int APS5_VABI sceSystemServiceReceiveEvent(SystemServiceEvent* event) { if (event == nullptr) { return SYSTEM_SERVICE_ERROR_PARAMETER; } - event->event_type = -1; - std::memset(event->data, 0, sizeof(event->data)); return SYSTEM_SERVICE_ERROR_NO_EVENT; } @@ -92,4 +95,9 @@ int APS5_VABI sceSystemServiceSetNoticeScreenSkipFlag(void) { return 0; } +int APS5_VABI sceSystemServiceLoadExec() { + NotImplemented_nid_no_patch(__func__); + return 0; +} + } diff --git a/core/libs/prx/libSceUserService/Export.cpp b/core/libs/prx/libSceUserService/Export.cpp index 55c133627..b4d913b5d 100644 --- a/core/libs/prx/libSceUserService/Export.cpp +++ b/core/libs/prx/libSceUserService/Export.cpp @@ -2,6 +2,7 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include #include "prx/libSceUserService/UserService.hpp" extern "C" { @@ -48,17 +49,37 @@ int APS5_VABI sceUserServiceGetAgeLevel(int user_id, uint32_t* age_level) { return 0; } +// The initial user is reported as logging in once; afterwards there are no user events. int APS5_VABI sceUserServiceGetEvent(SceUserServiceEvent* event) { - (void)event; - NotImplemented_nid_no_patch(__func__); - return 0; + if (event == nullptr) { + return USER_SERVICE_ERROR_INVALID_ARGUMENT; + } + static std::atomic loginReported{false}; + if (loginReported.exchange(true)) { + return USER_SERVICE_ERROR_NO_EVENT; + } + constexpr std::uint32_t EventTypeLogin = 0; + event->event_type = EventTypeLogin; + event->user_id = USER_SERVICE_INITIAL_USER_ID; + return USER_SERVICE_OK; } int APS5_VABI sceUserServiceGetGamePresets(int user_id, UserServiceGamePresets* presets) { - (void)user_id; - (void)presets; - NotImplemented_nid_no_patch(__func__); - return 0; + // System-wide game presets (difficulty, view inversion, subtitles, audio language) of the user's + // profile. A fresh console has none set: every field is 0, "not specified", and the title falls + // back to its own defaults. this_size is the caller's. + if (presets == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { + return USER_SERVICE_ERROR_INVALID_ARGUMENT; + } + presets->difficulty = 0; + presets->priority = 0; + presets->invert_vertical_view_for_1st_person_view = 0; + presets->invert_horizontal_view_for_1st_person_view = 0; + presets->invert_vertical_view_for_3rd_person_view = 0; + presets->invert_horizontal_view_for_3rd_person_view = 0; + presets->display_sub_titles = 0; + presets->audio_language = 0; + return USER_SERVICE_OK; } int APS5_VABI sceUserServiceGetInitialUser(int* user_id) { @@ -108,4 +129,12 @@ int APS5_VABI sceUserServiceTerminate(void) { return USER_SERVICE_OK; } +// No PSN account exists, so the platform privacy setting reports the feature as not permitted. +int APS5_VABI sceUserServiceGetPlatformPrivacyWs1(int32_t user_id, int32_t* value) { + (void)user_id; + if (!value) return static_cast(0x80960002); + *value = 0; + return 0; +} + } diff --git a/core/libs/prx/libSceVideoOut/CMakeLists.txt b/core/libs/prx/libSceVideoOut/CMakeLists.txt index 9271b1c57..452f68c24 100644 --- a/core/libs/prx/libSceVideoOut/CMakeLists.txt +++ b/core/libs/prx/libSceVideoOut/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(libSceVideoOut SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Unimplemented.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Event.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Output.cpp diff --git a/core/libs/prx/libSceVideoOut/Unimplemented.cpp b/core/libs/prx/libSceVideoOut/Unimplemented.cpp new file mode 100644 index 000000000..ed9002366 --- /dev/null +++ b/core/libs/prx/libSceVideoOut/Unimplemented.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "SceTypes.hpp" +#include "prx/libc/include/General.hpp" +#include "prx/libSceVideoOut/include/Output.hpp" +#include + +extern "C" { + +int APS5_VABI sceVideoOutAdjustColor_(int handle, const VideoOutColorSettings* settings, uint32_t settings_size) { + if (settings_size < sizeof(VideoOutColorSettings)) throw std::runtime_error("sceVideoOutAdjustColor_: VIDEO_OUT_ERROR_INVALID_VALUE"); + return sceVideoOutAdjustColor(handle, settings); +} + +int APS5_VABI sceVideoOutColorSettingsSetGamma_(VideoOutColorSettings* settings, float gamma, uint32_t settings_size) { + if (settings_size < sizeof(VideoOutColorSettings)) throw std::runtime_error("sceVideoOutColorSettingsSetGamma_: VIDEO_OUT_ERROR_INVALID_VALUE"); + return sceVideoOutColorSettingsSetGamma(settings, gamma); +} + +} diff --git a/core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp b/core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp index e9212806f..608b3caf8 100644 --- a/core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp +++ b/core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp @@ -172,7 +172,8 @@ public: std::shared_ptr GetConfig(int handle); bool IsOpen(int handle); - void SubmitFlip(int handle, int index, int flipMode, int64_t flipArg); + // 0, or VIDEO_OUT_ERROR_FLIP_QUEUE_FULL when the title has VIDEO_OUT_FLIP_QUEUE_CAPACITY flips pending. + int SubmitFlip(int handle, int index, int flipMode, int64_t flipArg); private: bool close(int handle); diff --git a/core/libs/prx/libSceVideoOut/src/Buffer.cpp b/core/libs/prx/libSceVideoOut/src/Buffer.cpp index d76184549..5c260c1fc 100644 --- a/core/libs/prx/libSceVideoOut/src/Buffer.cpp +++ b/core/libs/prx/libSceVideoOut/src/Buffer.cpp @@ -155,12 +155,10 @@ int APS5_VABI sceVideoOutSubmitFlip(int handle, int index, int flipMode, int64_t if (cfg == nullptr) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_HANDLE"); } - if (flipMode < VIDEO_OUT_FLIP_MODE_VSYNC || flipMode > VIDEO_OUT_FLIP_MODE_VSYNC_MULTI) { + // Every mode is presented at the next vsync; HSYNC/WINDOW variants only change tearing behaviour. + if (flipMode < VIDEO_OUT_FLIP_MODE_VSYNC || flipMode > 6) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_VALUE"); } - if (flipMode != VIDEO_OUT_FLIP_MODE_VSYNC) { - throw std::runtime_error(std::string(__func__) + ": flip mode not implemented"); - } if (index < VIDEO_OUT_BUFFER_INDEX_BLACK || index >= VIDEO_OUT_BUFFER_NUM_MAX) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_INDEX"); } @@ -174,8 +172,7 @@ int APS5_VABI sceVideoOutSubmitFlip(int handle, int index, int flipMode, int64_t throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_INDEX"); } lock.unlock(); - VideoOutDriver::Get().SubmitFlip(handle, index, flipMode, flipArg); - return 0; + return VideoOutDriver::Get().SubmitFlip(handle, index, flipMode, flipArg); } } diff --git a/core/libs/prx/libSceVideoOut/src/Output.cpp b/core/libs/prx/libSceVideoOut/src/Output.cpp index c709947a6..c859772ca 100644 --- a/core/libs/prx/libSceVideoOut/src/Output.cpp +++ b/core/libs/prx/libSceVideoOut/src/Output.cpp @@ -181,14 +181,14 @@ int APS5_VABI sceVideoOutSetWindowModeMargins(int handle, int top, int bottom) { if (!VideoOutDriver::Get().IsOpen(handle)) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_HANDLE"); } - throw std::runtime_error(std::string(__func__) + " not implemented"); + return 0; } int APS5_VABI sceVideoOutLatencyControlWaitBeforeInput(int handle) { if (!VideoOutDriver::Get().IsOpen(handle)) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_HANDLE"); } - throw std::runtime_error(std::string(__func__) + " not implemented"); + return 0; } int APS5_VABI sceVideoOutLatencyMeasureSetStartPoint(int handle, uint32_t point) { @@ -196,7 +196,7 @@ int APS5_VABI sceVideoOutLatencyMeasureSetStartPoint(int handle, uint32_t point) if (!VideoOutDriver::Get().IsOpen(handle)) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_HANDLE"); } - throw std::runtime_error(std::string(__func__) + " not implemented"); + return 0; } int APS5_VABI sceVideoOutColorSettingsSetGamma(VideoOutColorSettings* settings, float gamma) { @@ -218,7 +218,8 @@ int APS5_VABI sceVideoOutAdjustColor(int handle, const VideoOutColorSettings* se if (cfg == nullptr) { throw std::runtime_error(std::string(__func__) + ": VIDEO_OUT_ERROR_INVALID_HANDLE"); } - throw std::runtime_error(std::string(__func__) + " not implemented"); + // Output gamma is accepted but not yet applied to presentation. + return 0; } } diff --git a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp index ddd89a77a..e892c5828 100644 --- a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp +++ b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -31,7 +32,8 @@ public: VideoOutput(std::shared_ptr config, std::shared_ptr requests) : cfg(std::move(config)), queue(std::move(requests)) {} std::shared_ptr Reserve(const AgcDriver::FlipInfo& info) override { - require(info.mode == VIDEO_OUT_FLIP_MODE_VSYNC, "unsupported flip mode"); + // All flip modes are presented at the next vsync. + require(info.mode >= VIDEO_OUT_FLIP_MODE_VSYNC && info.mode <= 6, "unsupported flip mode"); require(info.index >= VIDEO_OUT_BUFFER_INDEX_BLACK && info.index < VIDEO_OUT_BUFFER_NUM_MAX, "invalid flip index"); auto request = std::make_shared(); request->cfg = cfg; @@ -119,6 +121,12 @@ void FlipRequest::GpuReady(const std::shared_ptr& frameT ready = true; } queue->changed.notify_all(); + // The worker is done once the request is queued: hardware does not stall the command processor + // on a flip, and the title observes completion through flipPendingNum, which processFlip drops + // after presenting. A presentation failure reaches the worker through ReportFailure at its next + // packet. Debug aid: APS5_SYNC_FLIP=1 parks the worker until the presenter is done, as before. + static const bool syncFlip = std::getenv("APS5_SYNC_FLIP") != nullptr; + if (!syncFlip) return; std::unique_lock lock(cfg->mutex); cfg->vblankCond.wait(lock, [&] { return gpuComplete || cfg->failure || cfg->closing; }); checkConfig(*cfg); @@ -281,11 +289,15 @@ bool VideoOutDriver::IsOpen(int handle) { return GetConfig(handle) != nullptr; } -void VideoOutDriver::SubmitFlip(int handle, int index, int flipMode, int64_t flipArg) { +int VideoOutDriver::SubmitFlip(int handle, int index, int flipMode, int64_t flipArg) { + // A title that does not pace on flipPendingNum can run ahead of the presenter now that the queue + // worker no longer waits per flip; a full queue is the documented error, not a failure. + if (flipQueue->reservations.load() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL; std::array words{AgcDriver::FlipPacketHeader, static_cast(handle), static_cast(index), static_cast(flipMode), static_cast(static_cast(flipArg)), static_cast(static_cast(flipArg) >> 32u)}; Packet packet{words.data(), static_cast(words.size()), 0, {}}; const auto result = sceAgcDriverSubmitDcb(&packet); require(result == 0, "driver rejected flip submission"); + return 0; } void VideoOutDriver::triggerEvents(VideoOutConfig& cfg, int eventKind, void* triggerData) { @@ -406,12 +418,6 @@ void VideoOutDriver::presentLoop(std::stop_token token) { PadInput padInput; try { while (!token.stop_requested()) { - SDL_Event event; - while (SDL_PollEvent(&event)) { - require(event.type != SDL_QUIT, "window was closed"); - padInput.HandleEvent(event, window); - } - padInput.Update(); { std::unique_lock lock(flipQueue->mutex); flipQueue->changed.wait_for(lock, std::chrono::milliseconds(10), [&] { return token.stop_requested() || flipQueue->failure || !flipQueue->requests.empty(); }); @@ -422,6 +428,12 @@ void VideoOutDriver::presentLoop(std::stop_token token) { flipQueue->requests.pop_front(); } } + SDL_Event event; + while (SDL_PollEvent(&event)) { + require(event.type != SDL_QUIT, "window was closed"); + padInput.HandleEvent(event, window); + } + padInput.Update(); if (current) { require(current->timing != nullptr, "missing presentation timing"); const auto dequeued = AgcDriver::FrameTiming::Clock::now(); @@ -451,6 +463,9 @@ void VideoOutDriver::presentLoop(std::stop_token token) { } catch (...) { auto error = std::current_exception(); if (!error) std::terminate(); + // The driver learns first: the worker no longer waits for the presenter, so a title (or test) + // that sees the failed flip's counters must already find the failure in the driver. + AgcDriverReportFailure_nid_postfix(error); PadReportInputFailure_nid_postfix(error); if (current) current->Fail(error); std::list> failed; @@ -470,7 +485,6 @@ void VideoOutDriver::presentLoop(std::stop_token token) { } } flipQueue->changed.notify_all(); - AgcDriverReportFailure_nid_postfix(error); } }