From 4136a04ba7879fef358fb36bab01ed6ba91e5221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Franch?= Date: Mon, 5 Oct 2026 19:25:46 +0200 Subject: [PATCH] feat(ulobjmgr): register and unregister object Co-Authored-By: Claude --- core/libs/prx/ulobjmgr/CMakeLists.txt | 20 +++++++++++++++++ core/libs/prx/ulobjmgr/Export.cpp | 18 ++++++++++----- core/libs/tests/GuestUlobjmgr.cpp | 32 +++++++++++++++++++++++++++ docs/dev/TechnicalDebt.md | 2 ++ 4 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 core/libs/prx/ulobjmgr/CMakeLists.txt create mode 100644 core/libs/tests/GuestUlobjmgr.cpp diff --git a/core/libs/prx/ulobjmgr/CMakeLists.txt b/core/libs/prx/ulobjmgr/CMakeLists.txt new file mode 100644 index 000000000..84d347d1a --- /dev/null +++ b/core/libs/prx/ulobjmgr/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library(ulobjmgr SHARED EXCLUDE_FROM_ALL Export.cpp) +target_include_directories(ulobjmgr PRIVATE ${LIBS_INCLUDE_DIR}) +configure_windows_unwind(ulobjmgr) + +if(MINGW) + foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static) + string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + endforeach() +endif() + +if(BUILD_TESTING) + add_test_executable(guest_ulobjmgr_tests ${LIBS_INCLUDE_DIR}/tests/GuestUlobjmgr.cpp) + target_include_directories(guest_ulobjmgr_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_ulobjmgr_tests PRIVATE ulobjmgr) + add_test(NAME guest_ulobjmgr COMMAND guest_ulobjmgr_tests) + if(WIN32) + set_tests_properties(guest_ulobjmgr PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/ulobjmgr/Export.cpp b/core/libs/prx/ulobjmgr/Export.cpp index 528a0dfc2..25b7f547b 100644 --- a/core/libs/prx/ulobjmgr/Export.cpp +++ b/core/libs/prx/ulobjmgr/Export.cpp @@ -3,17 +3,23 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +namespace { + +constexpr int ULOBJMGR_EINVAL = 22; +constexpr std::uint32_t ULOBJMGR_ID_LIMIT = 0x4000; + +} + extern "C" { -int APS5_VABI _sceUlobjmgrRegisterObject(void* object) { - (void)object; - NotImplemented_nid_no_patch(__func__); +int APS5_VABI _sceUlobjmgrRegisterObject(std::uint64_t object, std::int32_t kind, std::uint32_t* id) { + if (object == 0 || kind == 0 || id == nullptr) return ULOBJMGR_EINVAL; + *id = 0; return 0; } -int APS5_VABI _sceUlobjmgrUnregisterObject(void* object) { - (void)object; - NotImplemented_nid_no_patch(__func__); +int APS5_VABI _sceUlobjmgrUnregisterObject(std::uint32_t id) { + if (id >= ULOBJMGR_ID_LIMIT) return ULOBJMGR_EINVAL; return 0; } diff --git a/core/libs/tests/GuestUlobjmgr.cpp b/core/libs/tests/GuestUlobjmgr.cpp new file mode 100644 index 000000000..0fd79500f --- /dev/null +++ b/core/libs/tests/GuestUlobjmgr.cpp @@ -0,0 +1,32 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include + +extern "C" { +int APS5_VABI _sceUlobjmgrRegisterObject(std::uint64_t object, std::int32_t kind, std::uint32_t* id); +int APS5_VABI _sceUlobjmgrUnregisterObject(std::uint32_t id); +} + +namespace { + +constexpr int einval = 22; + +void Require(bool value) { if (!value) std::abort(); } + +} + +int main() { + std::uint32_t id = 0xffffffffu; + Require(_sceUlobjmgrRegisterObject(0, 1, &id) == einval); + Require(id == 0xffffffffu); + Require(_sceUlobjmgrRegisterObject(0x1000, 0, &id) == einval); + Require(id == 0xffffffffu); + Require(_sceUlobjmgrRegisterObject(0x1000, 1, nullptr) == einval); + Require(_sceUlobjmgrRegisterObject(0x1000, -1, &id) == 0); + Require(id == 0); + + Require(_sceUlobjmgrUnregisterObject(id) == 0); + Require(_sceUlobjmgrUnregisterObject(0x3fff) == 0); + Require(_sceUlobjmgrUnregisterObject(0x4000) == einval); + Require(_sceUlobjmgrUnregisterObject(0xffffffffu) == einval); +} diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 02ea84a84..c3205955e 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -21,6 +21,7 @@ Throughout the project, every function at every stage either **does exactly what - The shader recompiler [skips baryctric coordinates](../../core/shader/recompiler/Recompiler.cpp) (is not even passed to SpirvTargetOptions at row 212). - [libSceAvPlayer](../../core/libs/prx/libSceAvPlayer/Export.cpp): `sceAvPlayerSetLogCallback` accepts a callback that is never called, as the player produces no log messages, and `sceAvPlayerSetAvailableBandwidth` has no effect, as it governs HLS sources, which `sceAvPlayerAddSource` does not implement. - [sceAvPlayerSetTrickSpeed](../../core/libs/prx/libSceAvPlayer/src/Source.cpp) (libSceAvPlayer) with a negative speed runs the clock backwards but delivers no frames; when a forward speed is set again, playback resumes from the rewound time. +- [ulobjmgr](../../core/libs/prx/ulobjmgr/Export.cpp) registers no object: `_sceUlobjmgrRegisterObject` always hands out id 0 and `_sceUlobjmgrUnregisterObject` releases nothing, as shadPS4 does ### Unknown function info @@ -80,6 +81,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceVoiceSetMuteFlag](../../core/libs/prx/libSceVoice/Export.cpp) (libSceVoice) - unknown signature - [snwprintf_s](../../core/libs/prx/libc/src/FormattingWide.cpp) (libc) - follows C11 K.3.9.1.3 with `RSIZE_MAX` assumed to be `SIZE_MAX >> 1`. A runtime-constraint violation only returns a negative value: `set_constraint_handler_s` is not exported and the console's default handler is unknown. An invalid multibyte `%s` argument is copied byte by byte instead of being reported as an encoding error, as in `vswprintf` - [libSceUlt queues](../../core/libs/prx/libSceUlt/Export.cpp) - the added `sceUltQueuePop`, `sceUltQueueTryPush`, `sceUltQueueDestroy` and `sceUltQueueDataResourcePoolDestroy` signatures are inferred from the existing push/pop and object APIs. Queue destruction is assumed to reject blocked callers with `ULT_ERROR_BUSY` and otherwise discard queued data; pool exhaustion returns `ULT_ERROR_AGAIN`. These rules, alignment checks and shared slot limits have not been confirmed on PS5 hardware or a title. Non-null queue and data-pool option parameters throw because their layouts are unknown. +- [_sceUlobjmgrRegisterObject](../../core/libs/prx/ulobjmgr/Export.cpp) (ulobjmgr) - parameters taken from shadPS4 (PS4): a nonzero 64-bit object, a nonzero 32-bit kind and a 32-bit id output; the meaning of the first two and the PS5 signature are unverified. The id bound of `_sceUlobjmgrUnregisterObject` (below 0x4000) and the raw `EINVAL` (22) return also come from shadPS4 ### Functional