#include "stdafx.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "cellSync.h" //void cellSync_init(); //Module cellSync("cellSync", cellSync_init); Module *cellSync = nullptr; s32 cellSyncMutexInitialize(mem_ptr_t mutex) { cellSync->Log("cellSyncMutexInitialize(mutex_addr=0x%x)", mutex.GetAddr()); if (!mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } if (mutex.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // prx: set zero and sync mutex->m_data() = 0; InterlockedCompareExchange(&mutex->m_data(), 0, 0); return CELL_OK; } s32 cellSyncMutexLock(mem_ptr_t mutex) { cellSync->Log("cellSyncMutexLock(mutex_addr=0x%x)", mutex.GetAddr()); if (!mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } if (mutex.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // prx: increase u16 and remember its old value be_t old_order; while (true) { const u32 old_data = mutex->m_data(); CellSyncMutex new_mutex; new_mutex.m_data() = old_data; old_order = new_mutex.m_order; new_mutex.m_order++; // increase m_order if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break; } // prx: wait until another u16 value == old value while (old_order != mutex->m_freed) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { LOG_WARNING(HLE, "cellSyncMutexLock(mutex_addr=0x%x) aborted", mutex.GetAddr()); break; } } // prx: sync InterlockedCompareExchange(&mutex->m_data(), 0, 0); return CELL_OK; } s32 cellSyncMutexTryLock(mem_ptr_t mutex) { cellSync->Log("cellSyncMutexTryLock(mutex_addr=0x%x)", mutex.GetAddr()); if (!mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } if (mutex.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } while (true) { const u32 old_data = mutex->m_data(); CellSyncMutex new_mutex; new_mutex.m_data() = old_data; // prx: compare two u16 values and exit if not equal if (new_mutex.m_order != new_mutex.m_freed) { return CELL_SYNC_ERROR_BUSY; } else { new_mutex.m_order++; } if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break; } return CELL_OK; } s32 cellSyncMutexUnlock(mem_ptr_t mutex) { cellSync->Log("cellSyncMutexUnlock(mutex_addr=0x%x)", mutex.GetAddr()); if (!mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } if (mutex.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } InterlockedCompareExchange(&mutex->m_data(), 0, 0); while (true) { const u32 old_data = mutex->m_data(); CellSyncMutex new_mutex; new_mutex.m_data() = old_data; new_mutex.m_freed++; if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break; } return CELL_OK; } s32 cellSyncBarrierInitialize(mem_ptr_t barrier, u16 total_count) { cellSync->Log("cellSyncBarrierInitialize(barrier_addr=0x%x, total_count=%d)", barrier.GetAddr(), total_count); if (!barrier) { return CELL_SYNC_ERROR_NULL_POINTER; } if (barrier.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } if (!total_count || total_count > 32767) { return CELL_SYNC_ERROR_INVAL; } // prx: zeroize first u16, write total_count in second u16 and sync barrier->m_value = 0; barrier->m_count = total_count; InterlockedCompareExchange(&barrier->m_data(), 0, 0); return CELL_OK; } s32 cellSyncBarrierNotify(mem_ptr_t barrier) { cellSync->Todo("cellSyncBarrierNotify(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { return CELL_SYNC_ERROR_NULL_POINTER; } if (barrier.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // TODO return CELL_OK; } s32 cellSyncBarrierTryNotify(mem_ptr_t barrier) { cellSync->Todo("cellSyncBarrierTryNotify(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { return CELL_SYNC_ERROR_NULL_POINTER; } if (barrier.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // TODO return CELL_OK; } s32 cellSyncBarrierWait(mem_ptr_t barrier) { cellSync->Todo("cellSyncBarrierWait(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { return CELL_SYNC_ERROR_NULL_POINTER; } if (barrier.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // TODO return CELL_OK; } s32 cellSyncBarrierTryWait(mem_ptr_t barrier) { cellSync->Todo("cellSyncBarrierTryWait(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { return CELL_SYNC_ERROR_NULL_POINTER; } if (barrier.GetAddr() % 4) { return CELL_SYNC_ERROR_ALIGN; } // TODO return CELL_OK; } void cellSync_init() { cellSync->AddFunc(0xa9072dee, cellSyncMutexInitialize); cellSync->AddFunc(0x1bb675c2, cellSyncMutexLock); cellSync->AddFunc(0xd06918c4, cellSyncMutexTryLock); cellSync->AddFunc(0x91f2b7b0, cellSyncMutexUnlock); cellSync->AddFunc(0x07254fda, cellSyncBarrierInitialize); cellSync->AddFunc(0xf06a6415, cellSyncBarrierNotify); cellSync->AddFunc(0x268edd6d, cellSyncBarrierTryNotify); cellSync->AddFunc(0x35f21355, cellSyncBarrierWait); cellSync->AddFunc(0x6c272124, cellSyncBarrierTryWait); }