diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 9265e9decd..bdd6dd6a0b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -225,6 +225,139 @@ s32 cellSyncBarrierTryWait(mem_ptr_t barrier) return CELL_OK; } +s32 cellSyncRwmInitialize(mem_ptr_t rwm, u32 buffer_addr, u32 buffer_size) +{ + cellSync->Log("cellSyncRwmInitialize(rwm_addr=0x%x, buffer_addr=0x%x, buffer_size=0x%x)", rwm.GetAddr(), buffer_addr, buffer_size); + + if (!rwm || !buffer_addr) + { + return CELL_SYNC_ERROR_NULL_POINTER; + } + if (rwm.GetAddr() % 16 || buffer_addr % 128) + { + return CELL_SYNC_ERROR_ALIGN; + } + if (buffer_size % 128 || buffer_size > 0x4000) + { + return CELL_SYNC_ERROR_INVAL; + } + + // prx: zeroize first u16 and second u16, write buffer_size in second u32, write buffer_addr in second u64 and sync + rwm->m_data() = 0; + rwm->m_size = buffer_size; + rwm->m_addr = (u64)buffer_addr; + InterlockedCompareExchange(&rwm->m_data(), 0, 0); + return CELL_OK; +} + +s32 cellSyncRwmRead(mem_ptr_t rwm, u32 buffer_addr) +{ + cellSync->Log("cellSyncRwmRead(rwm_addr=0x%x, buffer_addr=0x%x)", rwm.GetAddr(), buffer_addr); + + if (!rwm || !buffer_addr) + { + return CELL_SYNC_ERROR_NULL_POINTER; + } + if (rwm.GetAddr() % 16) + { + return CELL_SYNC_ERROR_ALIGN; + } + + // prx: atomically load first u32, repeat until second u16 == 0, increase first u16 and sync + while (true) + { + const u32 old_data = rwm->m_data(); + CellSyncRwm new_rwm; + new_rwm.m_data() = old_data; + + if (new_rwm.m_writers.ToBE()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + if (Emu.IsStopped()) + { + cellSync->Warning("cellSyncRwmRead(rwm_addr=0x%x) aborted", rwm.GetAddr()); + return CELL_OK; + } + continue; + } + + new_rwm.m_readers++; + if (InterlockedCompareExchange(&rwm->m_data(), new_rwm.m_data(), old_data) == old_data) break; + } + + // copy data to buffer_addr + memcpy(Memory + buffer_addr, Memory + (u64)rwm->m_addr, (u32)rwm->m_size); + + // prx: load first u32, return 0x8041010C if first u16 == 0, atomically decrease it + while (true) + { + const u32 old_data = rwm->m_data(); + CellSyncRwm new_rwm; + new_rwm.m_data() = old_data; + + if (!new_rwm.m_readers.ToBE()) + { + cellSync->Error("cellSyncRwmRead(rwm_addr=0x%x): m_readers == 0 (m_writers=%d)", rwm.GetAddr(), (u16)new_rwm.m_writers); + return CELL_SYNC_ERROR_ABORT; + } + + new_rwm.m_readers--; + if (InterlockedCompareExchange(&rwm->m_data(), new_rwm.m_data(), old_data) == old_data) break; + } + return CELL_OK; +} + +s32 cellSyncRwmTryRead(mem_ptr_t rwm, u32 buffer_addr) +{ + cellSync->Todo("cellSyncRwmTryRead(rwm_addr=0x%x, buffer_addr=0x%x)", rwm.GetAddr(), buffer_addr); + + if (!rwm || !buffer_addr) + { + return CELL_SYNC_ERROR_NULL_POINTER; + } + if (rwm.GetAddr() % 16) + { + return CELL_SYNC_ERROR_ALIGN; + } + + // TODO + return CELL_OK; +} + +s32 cellSyncRwmWrite(mem_ptr_t rwm, u32 buffer_addr) +{ + cellSync->Todo("cellSyncRwmWrite(rwm_addr=0x%x, buffer_addr=0x%x)", rwm.GetAddr(), buffer_addr); + + if (!rwm || !buffer_addr) + { + return CELL_SYNC_ERROR_NULL_POINTER; + } + if (rwm.GetAddr() % 16) + { + return CELL_SYNC_ERROR_ALIGN; + } + + // TODO + return CELL_OK; +} + +s32 cellSyncRwmTryWrite(mem_ptr_t rwm, u32 buffer_addr) +{ + cellSync->Todo("cellSyncRwmTryWrite(rwm_addr=0x%x, buffer_addr=0x%x)", rwm.GetAddr(), buffer_addr); + + if (!rwm || !buffer_addr) + { + return CELL_SYNC_ERROR_NULL_POINTER; + } + if (rwm.GetAddr() % 16) + { + return CELL_SYNC_ERROR_ALIGN; + } + + // TODO + return CELL_OK; +} + void cellSync_init() { cellSync->AddFunc(0xa9072dee, cellSyncMutexInitialize); @@ -237,4 +370,10 @@ void cellSync_init() cellSync->AddFunc(0x268edd6d, cellSyncBarrierTryNotify); cellSync->AddFunc(0x35f21355, cellSyncBarrierWait); cellSync->AddFunc(0x6c272124, cellSyncBarrierTryWait); + + cellSync->AddFunc(0xfc48b03f, cellSyncRwmInitialize); + cellSync->AddFunc(0xcece771f, cellSyncRwmRead); + cellSync->AddFunc(0xa6669751, cellSyncRwmTryRead); + cellSync->AddFunc(0xed773f5f, cellSyncRwmWrite); + cellSync->AddFunc(0xba5bee48, cellSyncRwmTryWrite); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.h b/rpcs3/Emu/SysCalls/Modules/cellSync.h index c9dd86f607..02829fcdb1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.h @@ -3,18 +3,30 @@ // Return Codes enum { - CELL_SYNC_ERROR_AGAIN = 0x80410101, - CELL_SYNC_ERROR_INVAL = 0x80410102, - CELL_SYNC_ERROR_NOMEM = 0x80410104, + CELL_SYNC_ERROR_AGAIN = 0x80410101, + CELL_SYNC_ERROR_INVAL = 0x80410102, + CELL_SYNC_ERROR_NOSYS = 0x80410103, // ??? + CELL_SYNC_ERROR_NOMEM = 0x80410104, + CELL_SYNC_ERROR_SRCH = 0x80410105, // ??? + CELL_SYNC_ERROR_NOENT = 0x80410106, // ??? + CELL_SYNC_ERROR_NOEXEC = 0x80410107, // ??? CELL_SYNC_ERROR_DEADLK = 0x80410108, - CELL_SYNC_ERROR_PERM = 0x80410109, - CELL_SYNC_ERROR_BUSY = 0x8041010A, - CELL_SYNC_ERROR_STAT = 0x8041010F, - CELL_SYNC_ERROR_ALIGN = 0x80410110, - CELL_SYNC_ERROR_NULL_POINTER = 0x80410111, - CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = 0x80410112, - CELL_SYNC_ERROR_NO_NOTIFIER = 0x80410113, - CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, + CELL_SYNC_ERROR_PERM = 0x80410109, + CELL_SYNC_ERROR_BUSY = 0x8041010A, + //////////////////////// 0x8041010B, // ??? + CELL_SYNC_ERROR_ABORT = 0x8041010C, // ??? + CELL_SYNC_ERROR_FAULT = 0x8041010D, // ??? + CELL_SYNC_ERROR_CHILD = 0x8041010E, // ??? + CELL_SYNC_ERROR_STAT = 0x8041010F, + CELL_SYNC_ERROR_ALIGN = 0x80410110, + + CELL_SYNC_ERROR_NULL_POINTER = 0x80410111, + + CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = 0x80410112, // ??? + CELL_SYNC_ERROR_SHOTAGE = 0x80410112, // ??? + CELL_SYNC_ERROR_NO_NOTIFIER = 0x80410113, // ??? + CELL_SYNC_ERROR_UNKNOWNKEY = 0x80410113, // ??? + CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, // ??? }; struct CellSyncMutex @@ -41,4 +53,19 @@ struct CellSyncBarrier }; }; -static_assert(sizeof(CellSyncBarrier) == 4, "CellSyncBarrier: wrong size"); \ No newline at end of file +static_assert(sizeof(CellSyncBarrier) == 4, "CellSyncBarrier: wrong size"); + +struct CellSyncRwm +{ + be_t m_readers; + be_t m_writers; + be_t m_size; + be_t m_addr; + + volatile u32& m_data() + { + return *reinterpret_cast(this); + }; +}; + +static_assert(sizeof(CellSyncRwm) == 16, "CellSyncBarrier: wrong size");