From e2954aa188c5aaa0a93f202e72ecab58e5501ec2 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 11 Oct 2026 09:42:43 +0200 Subject: [PATCH] feat(libSceNpPartner001): implement sceNpEAAccessInitialize and sceNpEAAccessTerminate UFC 6 (PPSA23566) imports both. Initialization marks the library initialized and termination clears it, as in shadPS4. Termination without initialization and a second initialization throw, since no PS5 source settles their results. Co-Authored-By: Claude Fable 5.1 (cherry picked from commit d2866a886a7702cdaad56d161460a3ce86ede629) --- .../prx/libSceNpPartner001/CMakeLists.txt | 15 ++++++++ core/libs/prx/libSceNpPartner001/Export.cpp | 13 +++++-- core/libs/tests/GuestNpPartner.cpp | 34 +++++++++++++++++++ docs/dev/debt/libSceNpPartner001.md | 4 +++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 core/libs/prx/libSceNpPartner001/CMakeLists.txt create mode 100644 core/libs/tests/GuestNpPartner.cpp diff --git a/core/libs/prx/libSceNpPartner001/CMakeLists.txt b/core/libs/prx/libSceNpPartner001/CMakeLists.txt new file mode 100644 index 000000000..c339e97d9 --- /dev/null +++ b/core/libs/prx/libSceNpPartner001/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(libSceNpPartner001 SHARED EXCLUDE_FROM_ALL Export.cpp) +target_include_directories(libSceNpPartner001 PRIVATE ${LIBS_INCLUDE_DIR}) +configure_windows_unwind(libSceNpPartner001) + +if(BUILD_TESTING) + add_test_executable(guest_np_partner_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpPartner.cpp) + target_include_directories(guest_np_partner_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_np_partner_tests PRIVATE libSceNpPartner001 libc) + configure_windows_unwind(guest_np_partner_tests) + add_test(NAME guest_np_partner COMMAND guest_np_partner_tests) + if(WIN32) + set_tests_properties(guest_np_partner PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceNpPartner001/Export.cpp b/core/libs/prx/libSceNpPartner001/Export.cpp index 74e81b2df..9d2e08977 100644 --- a/core/libs/prx/libSceNpPartner001/Export.cpp +++ b/core/libs/prx/libSceNpPartner001/Export.cpp @@ -1,14 +1,23 @@ #include "prx/libc/include/General.hpp" +#include +#include +#include + +namespace { +std::atomic g_initialized{false}; +} extern "C" { int APS5_VABI sceNpEAAccessInitialize(void) { - NotImplemented_nid_no_patch(__func__); + bool expected = false; + if (!g_initialized.compare_exchange_strong(expected, true)) throw std::logic_error(std::string(__func__) + ": already initialized"); return 0; } int APS5_VABI sceNpEAAccessTerminate(void) { - NotImplemented_nid_no_patch(__func__); + bool expected = true; + if (!g_initialized.compare_exchange_strong(expected, false)) throw std::logic_error(std::string(__func__) + ": not initialized"); return 0; } diff --git a/core/libs/tests/GuestNpPartner.cpp b/core/libs/tests/GuestNpPartner.cpp new file mode 100644 index 000000000..0121f30c8 --- /dev/null +++ b/core/libs/tests/GuestNpPartner.cpp @@ -0,0 +1,34 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include + +extern "C" { +int APS5_VABI sceNpEAAccessInitialize(void); +int APS5_VABI sceNpEAAccessTerminate(void); +} + +namespace { + +void Require(bool value) { if (!value) std::abort(); } + +template +bool Throws(TAction action) { + try { + action(); + } catch (const std::logic_error&) { + return true; + } + return false; +} + +} + +int main() { + Require(Throws([] { sceNpEAAccessTerminate(); })); + Require(sceNpEAAccessInitialize() == 0); + Require(Throws([] { sceNpEAAccessInitialize(); })); + Require(sceNpEAAccessTerminate() == 0); + Require(Throws([] { sceNpEAAccessTerminate(); })); + Require(sceNpEAAccessInitialize() == 0); + Require(sceNpEAAccessTerminate() == 0); +} diff --git a/docs/dev/debt/libSceNpPartner001.md b/docs/dev/debt/libSceNpPartner001.md index f032f97da..02e1a7ab4 100644 --- a/docs/dev/debt/libSceNpPartner001.md +++ b/docs/dev/debt/libSceNpPartner001.md @@ -3,3 +3,7 @@ ### Unknown function info - [sceNpEAAccessInitialize, sceNpEAAccessTerminate](../../../core/libs/prx/libSceNpPartner001/Export.cpp) (libSceNpPartner001) - names and the no-argument signatures follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/np/np_partner.cpp); imported by PPSA23566, not confirmed on a PS5 title + +### Functional + +- [sceNpEAAccessInitialize, sceNpEAAccessTerminate](../../../core/libs/prx/libSceNpPartner001/Export.cpp) (libSceNpPartner001) - initialization marks the library initialized without contacting the server and termination clears it, as in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/np/np_partner.cpp); whether the console fails initialization while signed out is unknown. Termination without initialization throws where shadPS4 returns the PS4 error `0x819D0001`, whose PS5 value is unverified, and a second initialization throws where shadPS4 returns 0 without checking. PPSA23566 imports both, not confirmed on its start-up path