diff --git a/core/libs/prx/libSceMove/Export.cpp b/core/libs/prx/libSceMove/Export.cpp index 340a60d887..df4c7fcf1a 100644 --- a/core/libs/prx/libSceMove/Export.cpp +++ b/core/libs/prx/libSceMove/Export.cpp @@ -1,10 +1,10 @@ -#include #include #include #include -#include +#include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include "prx/libSceUserService/UserService.hpp" namespace { @@ -19,7 +19,12 @@ constexpr int32_t MOVE_HANDLE_STEP = 0x100; std::mutex stateMutex; bool initialized = false; int32_t nextHandle = MOVE_FIRST_HANDLE; -std::unordered_set openHandles; +struct Slot { + int32_t type; + int32_t index; +}; + +std::unordered_map openHandles; int checkHandle(const char* function, int32_t handle) { std::lock_guard lock(stateMutex); @@ -48,14 +53,15 @@ int APS5_VABI sceMoveTerm(void) { } int APS5_VABI sceMoveOpen(int32_t userId, int32_t type, int32_t index) { - (void)userId; - (void)type; - (void)index; std::lock_guard lock(stateMutex); if (!initialized) return MOVE_ERROR_NOT_INIT; + if (userId != USER_SERVICE_INITIAL_USER_ID) NotImplemented_nid_no_patch(__func__); + for (const auto& [openHandle, slot] : openHandles) { + if (slot.type == type && slot.index == index) NotImplemented_nid_no_patch(__func__); + } const int32_t handle = nextHandle; nextHandle += MOVE_HANDLE_STEP; - openHandles.insert(handle); + openHandles.emplace(handle, Slot{type, index}); return handle; } diff --git a/core/libs/tests/GuestMove.cpp b/core/libs/tests/GuestMove.cpp index 6d35288a5a..db2b1bc998 100644 --- a/core/libs/tests/GuestMove.cpp +++ b/core/libs/tests/GuestMove.cpp @@ -101,6 +101,8 @@ int main() { const std::int32_t second = sceMoveOpen(kUserId, 0, 1); Require(first == kFirstHandle); Require(second == kFirstHandle + kHandleStep); + Require(Throws([] { sceMoveOpen(kUserId, 0, 0); })); + Require(Throws([] { sceMoveOpen(kUserId + 1, 0, 2); })); Require(sceMoveGetDeviceInfo(first, nullptr) == kInvalidArg); Require(sceMoveGetExtensionPortInfo(first, nullptr) == kInvalidArg); @@ -125,6 +127,9 @@ int main() { Require(sceMoveClose(first) == kOk); RequireUnknownHandleThrows(first); + const std::int32_t reopened = sceMoveOpen(kUserId, 0, 0); + Require(reopened == kFirstHandle + 2 * kHandleStep); + Require(sceMoveClose(reopened) == kOk); Require(sceMoveSetVibration(second, 0) == kNoControllerConnected); Require(sceMoveTerm() == kOk); @@ -133,7 +138,7 @@ int main() { Require(sceMoveInit() == kOk); RequireUnknownHandleThrows(second); const std::int32_t third = sceMoveOpen(kUserId, 0, 0); - Require(third == kFirstHandle + 2 * kHandleStep); + Require(third == kFirstHandle + 3 * kHandleStep); Require(sceMoveClose(third) == kOk); Require(sceMoveTerm() == kOk); } diff --git a/docs/dev/debt/libSceMove.md b/docs/dev/debt/libSceMove.md index 8ef70c92b6..ec7666f106 100644 --- a/docs/dev/debt/libSceMove.md +++ b/docs/dev/debt/libSceMove.md @@ -2,8 +2,9 @@ ### Silent stubs -- [libSceMove](../../../core/libs/prx/libSceMove/Export.cpp) implements only the no-controller path: initialization and termination succeed, `sceMoveOpen` returns a new handle for any user, type and index, `sceMoveClose` and `sceMoveResetLightSphere` succeed for an open handle, and the device info, state, extension port, vibration and `sceMoveSetLightSphere` calls return 1 (no controller connected) and write nothing +- [libSceMove](../../../core/libs/prx/libSceMove/Export.cpp) implements only the no-controller path: initialization and termination succeed, `sceMoveOpen` returns a new handle, `sceMoveClose` and `sceMoveResetLightSphere` succeed for an open handle, and the device info, state, extension port, vibration and `sceMoveSetLightSphere` calls return 1 (no controller connected) and write nothing ### Unknown function info -- [libSceMove](../../../core/libs/prx/libSceMove/Export.cpp) (libSceMove) - behaviour, error codes and the handle values (`0x30B0100`, then every `0x100`) follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/f68923fe807f657348e6719ce658bcbd0a2b1c72/src/core/libraries/move/move.cpp) (PS4), not measured on a PS5. Signatures follow [Orbital](https://github.com/AlexAltea/orbital/blob/master/tools/ida/db_types.json), except `sceMoveGetExtensionPortInfo`, which follows shadPS4. Before `sceMoveInit` and after `sceMoveTerm` every other call returns `NOT_INIT` (`0x80EE0001`); a null output or a negative timestamp returns `INVALID_ARG` (`0x80EE0003`). A handle that was never opened, is closed or was opened before `sceMoveTerm` throws: the console's `INVALID_HANDLE` (`0x80EE0004`) result and its order against `INVALID_ARG` are not known. Whether `sceMoveOpen` rejects an invalid user or a slot that is already open is not known. Closes when: measured on a PS5 +- [libSceMove](../../../core/libs/prx/libSceMove/Export.cpp) (libSceMove) - behaviour, error codes and the handle values (`0x30B0100`, then every `0x100`) follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/f68923fe807f657348e6719ce658bcbd0a2b1c72/src/core/libraries/move/move.cpp) (PS4), which checks no handle or open arguments; none is measured on a PS5. Signatures follow [Orbital](https://github.com/AlexAltea/orbital/blob/master/tools/ida/db_types.json), except `sceMoveGetExtensionPortInfo`, which follows shadPS4. Before `sceMoveInit` and after `sceMoveTerm` every other call returns `NOT_INIT` (`0x80EE0001`); a null output or a negative timestamp returns `INVALID_ARG` (`0x80EE0003`). Closes when: measured on a PS5 +- [libSceMove](../../../core/libs/prx/libSceMove/Export.cpp) (libSceMove) - a handle that was never opened, is closed or was opened before `sceMoveTerm` throws: the console's `INVALID_HANDLE` (`0x80EE0004`) result and its order against `INVALID_ARG` are not known. `sceMoveOpen` throws for a user other than the initial user and for a type and index that are already open, whose console results are not known, and accepts any type and index. Closes when: measured on a PS5