int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwcond_attribute_t> attr) { sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr()); if (!lwcond.IsGood() /*|| !lwmutex.IsGood()*/ || !attr.IsGood()) { return CELL_EFAULT; } lwcond->lwmutex = lwmutex.GetAddr(); lwcond->lwcond_queue = sys_lwcond.GetNewId(new SleepQueue(attr->name_u64)); if (lwmutex.IsGood()) { if (lwmutex->attribute.ToBE() & se32(SYS_SYNC_RETRY)) { sys_lwcond.Warning("Unsupported SYS_SYNC_RETRY lwmutex protocol"); } if (lwmutex->attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) { sys_lwcond.Warning("Recursive lwmutex(sq=%d)", (u32)lwmutex->sleep_queue); } } else { sys_lwcond.Warning("Invalid lwmutex address(0x%x)", lwmutex.GetAddr()); } sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", wxString(attr->name, 8).wx_str(), lwmutex.GetAddr(), (u32)lwcond->lwcond_queue); return CELL_OK; }
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr) { sysPrxForUser.Warning("sys_lwmutex_create(lwmutex=*0x%x, attr=*0x%x)", lwmutex, attr); const bool recursive = attr->recursive.data() == se32(SYS_SYNC_RECURSIVE); if (!recursive && attr->recursive.data() != se32(SYS_SYNC_NOT_RECURSIVE)) { sysPrxForUser.Error("sys_lwmutex_create(): invalid recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL; } const u32 protocol = attr->protocol; switch (protocol) { case SYS_SYNC_FIFO: break; case SYS_SYNC_RETRY: break; case SYS_SYNC_PRIORITY: break; default: sysPrxForUser.Error("sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL; } lwmutex->lock_var = { { lwmutex::free, lwmutex::zero } }; lwmutex->attribute = attr->recursive | attr->protocol; lwmutex->recursive_count = 0; lwmutex->sleep_queue = Emu.GetIdManager().make<lv2_lwmutex_t>(protocol, attr->name_u64); return CELL_OK; }
int sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout) { switch (int res = trylock(tid)) { case static_cast<int>(CELL_EBUSY): break; default: return res; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) { case se32(SYS_SYNC_PRIORITY): case se32(SYS_SYNC_FIFO): sq->push(tid); default: break; } switch (mutex.lock(tid, timeout)) { case SMR_OK: sq->invalidate(tid); case SMR_SIGNAL: recursive_count = 1; return CELL_OK; case SMR_TIMEOUT: sq->invalidate(tid); return CELL_ETIMEDOUT; case SMR_ABORT: if (Emu.IsStopped()) ConLog.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); default: sq->invalidate(tid); return CELL_EINVAL; } }
s32 sys_semaphore_create(vm::ptr<be_t<u32>> sem, vm::ptr<sys_semaphore_attribute> attr, s32 initial_count, s32 max_count) { sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)", sem.addr(), attr.addr(), initial_count, max_count); if (max_count <= 0 || initial_count > max_count || initial_count < 0) { sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count); return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) { sys_semaphore.Error("sys_semaphore_create(): invalid pshared value(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_semaphore.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; case se32(SYS_SYNC_RETRY): sys_semaphore.Error("SYS_SYNC_RETRY"); return CELL_EINVAL; default: sys_semaphore.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; } *sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64); return CELL_OK; }
int sys_lwmutex_t::trylock(be_t<u32> tid) { if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; be_t<u32> owner_tid = mutex.GetFreeValue(); if (mutex.unlock(owner_tid, owner_tid) != SMR_OK) // check free value { owner_tid = mutex.GetOwner(); /*if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid)) { if (!tt->IsAlive()) { sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid); mutex.unlock(owner_tid, tid); recursive_count = 1; return CELL_OK; } } else { sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid); mutex.unlock(owner_tid, tid); recursive_count = 1; return CELL_OK; }*/ } /*while ((attribute.ToBE() & se32(SYS_SYNC_ATTR_RECURSIVE_MASK)) == 0) { if (Emu.IsStopped()) { ConLog.Warning("(hack) sys_lwmutex_t::(try)lock aborted (waiting for recursive attribute, attr=0x%x)", (u32)attribute); return CELL_ESRCH; } Sleep(1); }*/ if (tid == owner_tid) { if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) { recursive_count += 1; if (!recursive_count.ToBE()) return CELL_EKRESOURCE; return CELL_OK; } else { return CELL_EDEADLK; } } switch (mutex.trylock(tid)) { case SMR_OK: recursive_count = 1; return CELL_OK; case SMR_FAILED: return CELL_EBUSY; default: return CELL_EINVAL; } }
s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id) { sysPrxForUser.Log("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=0x%x)", lwcond, ppu_thread_id); const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex; if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) { // TODO (protocol ignored) //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); } if (lwmutex->owner.read_relaxed() == CPU.GetId()) { // if owns the mutex lwmutex->all_info++; // call the syscall if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 1)) { lwmutex->all_info--; return res; } return CELL_OK; } if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) { // if locking failed if (res != CELL_EBUSY) { return CELL_ESRCH; } // call the syscall return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); } // if locking succeeded lwmutex->all_info++; // call the syscall if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 3)) { lwmutex->all_info--; // unlock the lightweight mutex sys_lwmutex_unlock(CPU, lwmutex); return res; } return CELL_OK; }
s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond) { sysPrxForUser.Log("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond); const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex; if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) { // TODO (protocol ignored) //return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); } if (lwmutex->owner.read_relaxed() == CPU.GetId()) { // if owns the mutex, call the syscall const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); if (res <= 0) { // return error or CELL_OK return res; } lwmutex->all_info += res; return CELL_OK; } if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) { // if locking failed if (res != CELL_EBUSY) { return CELL_ESRCH; } // call the syscall return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); } // if locking succeeded, call the syscall s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); if (res > 0) { lwmutex->all_info += res; res = CELL_OK; } // unlock mutex sys_lwmutex_unlock(CPU, lwmutex); return res; }
void sys_ppu_thread_once(vm::ptr<std::atomic<be_t<u32>>> once_ctrl, u32 entry) { sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, entry=0x%x)", once_ctrl.addr(), entry); be_t<u32> old = be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_ONCE_INIT)); if (once_ctrl->compare_exchange_weak(old, be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_DONE_INIT)))) { GetCurrentPPUThread().FastCall2(Memory.Read32(entry), Memory.Read32(entry + 4)); } }
void sys_ppu_thread_once(PPUThread& CPU, vm::ptr<std::atomic<be_t<u32>>> once_ctrl, vm::ptr<void(*)()> init) { sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, init_addr=0x%x)", once_ctrl.addr(), init.addr()); be_t<u32> old = be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_ONCE_INIT)); if (once_ctrl->compare_exchange_weak(old, be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_DONE_INIT)))) { init.call(CPU); } }
bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& configpath) { std::string path; rXmlDocument doc; Emu.GetVFS().GetDevice(configpath.c_str(), path); doc.Load(path); m_table4.clear(); m_table6.clear(); for (std::shared_ptr<rXmlNode> n = doc.GetRoot()->GetChildren(); n; n = n->GetNext()) { if (n->GetName() == "trophy") { u32 trophy_id = atoi(n->GetAttribute("id").c_str()); u32 trophy_grade; switch (((const char *)n->GetAttribute("ttype").c_str())[0]) { case 'B': trophy_grade = 4; break; case 'S': trophy_grade = 3; break; case 'G': trophy_grade = 2; break; case 'P': trophy_grade = 1; break; default: trophy_grade = 0; } TROPUSREntry4 entry4 = { be_t<u32>::MakeFromBE(se32(4)), be_t<u32>::MakeFromBE(se32(sizeof(TROPUSREntry4) - 0x10)), be_t<u32>::MakeFromLE(m_table4.size()), be_t<u32>::MakeFromBE(se32(0)), be_t<u32>::MakeFromLE(trophy_id), be_t<u32>::MakeFromLE(trophy_grade), be_t<u32>::MakeFromBE(se32(0xFFFFFFFF)) }; TROPUSREntry6 entry6 = { be_t<u32>::MakeFromBE(se32(6)), be_t<u32>::MakeFromBE(se32(sizeof(TROPUSREntry6) - 0x10)), be_t<u32>::MakeFromLE(m_table6.size()), be_t<u32>::MakeFromBE(0), be_t<u32>::MakeFromLE(trophy_id) }; m_table4.push_back(entry4); m_table6.push_back(entry6); } } u64 offset = sizeof(TROPUSRHeader) + 2 * sizeof(TROPUSRTableHeader); TROPUSRTableHeader table4header = { be_t<u32>::MakeFromBE(se32(4)), be_t<u32>::MakeFromBE(se32(sizeof(TROPUSREntry4)-0x10)), be_t<u32>::MakeFromBE(se32(1)), be_t<u32>::MakeFromLE(m_table4.size()), be_t<u64>::MakeFromLE(offset) }; offset += m_table4.size() * sizeof(TROPUSREntry4); TROPUSRTableHeader table6header = { be_t<u32>::MakeFromBE(se32(6)), be_t<u32>::MakeFromBE(se32(sizeof(TROPUSREntry6)-0x10)), be_t<u32>::MakeFromBE(se32(1)), be_t<u32>::MakeFromLE(m_table6.size()), be_t<u64>::MakeFromLE(offset) }; offset += m_table6.size() * sizeof(TROPUSREntry6); m_tableHeaders.clear(); m_tableHeaders.push_back(table4header); m_tableHeaders.push_back(table6header); m_header.magic = 0x818F54AD; m_header.unk1 = 0x00010000; m_header.tables_count = m_tableHeaders.size(); m_header.unk2 = 0; Save(filepath); return true; }
void sys_ppu_thread_once(mem_ptr_t<std::atomic<be_t<u32>>> once_ctrl, u32 entry) { sysPrxForUser->Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, entry=0x%x)", once_ctrl.GetAddr(), entry); be_t<u32> old = be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_ONCE_INIT)); if (once_ctrl->compare_exchange_weak(old, be_t<u32>::MakeFromBE(se32(SYS_PPU_THREAD_DONE_INIT)))) { CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); new_thread.SetEntry(entry); new_thread.Run(); new_thread.Exec(); while (new_thread.IsAlive()) SM_Sleep(); } }
s32 sys_cond_create(vm::ptr<be_t<u32>> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute> attr) { sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", cond_id.addr(), mutex_id, attr.addr()); LV2_LOCK(0); if (attr->pshared.ToBE() != se32(0x200)) { sys_cond.Error("Invalid pshared attribute(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } Mutex* mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } if (mutex->is_recursive) { sys_cond.Warning("*** condition on recursive mutex(%d)", mutex_id); } Cond* cond = new Cond(mutex, attr->name_u64); u32 id = sys_cond.GetNewId(cond, TYPE_COND); *cond_id = id; mutex->cond_count++; sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id); Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_COND, id, std::string(attr->name, 8)); return CELL_OK; }
int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond) { sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); if (!lwcond.IsGood()) { return CELL_EFAULT; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) { return CELL_ESRCH; } mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); be_t<u32> tid = GetCurrentPPUThread().GetId(); if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) { if (mutex->mutex.owner.trylock(target) != SMR_OK) { mutex->mutex.owner.lock(tid); mutex->recursive_count = 1; mutex->mutex.owner.unlock(tid, target); } } if (Emu.IsStopped()) { ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue); } return CELL_OK; }
s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond) { sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.addr()); Lwcond* lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; } auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) { lw->signal.lock(target); if (Emu.IsStopped()) { sys_lwcond.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue); return CELL_OK; } } return CELL_OK; }
s32 sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond) { sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr()); Lwcond* lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; } mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) { lw->signal.lock(target); if (Emu.IsStopped()) { LOG_WARNING(HLE, "sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue); return CELL_OK; } } return CELL_OK; }
int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute> attr) { sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", cond_id.GetAddr(), mutex_id, attr.GetAddr()); if (!cond_id.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } if (attr->pshared.ToBE() != se32(0x200)) { sys_cond.Error("Invalid pshared attribute(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } Mutex* mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } if (mutex->is_recursive) { sys_cond.Warning("*** condition on recursive mutex(%d)", mutex_id); } Cond* cond = new Cond(mutex, attr->name_u64); u32 id = sys_cond.GetNewId(cond); cond_id = id; mutex->cond_count++; sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", wxString(attr->name, 8).wx_str(), mutex_id, cond_id.GetValue()); return CELL_OK; }
s32 sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t<sys_rwlock_attribute_t> attr) { sys_rwlock.Warning("sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.GetAddr(), attr.GetAddr()); switch (attr->attr_protocol.ToBE()) { case se(attr->attr_protocol, SYS_SYNC_PRIORITY): sys_rwlock.Todo("SYS_SYNC_PRIORITY"); break; case se(attr->attr_protocol, SYS_SYNC_RETRY): sys_rwlock.Error("SYS_SYNC_RETRY"); return CELL_EINVAL; case se(attr->attr_protocol, SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; case se(attr->attr_protocol, SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } if (attr->attr_pshared.ToBE() != se32(0x200)) { sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared); return CELL_EINVAL; } rw_lock_id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, attr->name_u64)); sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id = %d", std::string(attr->name, 8).c_str(), (u32) attr->attr_protocol, rw_lock_id.GetValue()); return CELL_OK; }
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr) { sys_cond.Warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr); LV2_LOCK; const auto mutex = Emu.GetIdManager().GetIDData<mutex_t>(mutex_id); if (!mutex) { return CELL_ESRCH; } if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data()) { sys_cond.Error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); return CELL_EINVAL; } if (!++mutex->cond_count) { throw __FUNCTION__; } std::shared_ptr<cond_t> cond(new cond_t(mutex, attr->name_u64)); *cond_id = Emu.GetIdManager().GetNewID(cond, TYPE_COND); return CELL_OK; }
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val) { sys_semaphore.Warning("sys_semaphore_create(sem=*0x%x, attr=*0x%x, initial_val=%d, max_val=%d)", sem, attr, initial_val, max_val); if (!sem || !attr) { return CELL_EFAULT; } if (max_val <= 0 || initial_val > max_val || initial_val < 0) { sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_val=%d, max_val=%d)", initial_val, max_val); return CELL_EINVAL; } const u32 protocol = attr->protocol; switch (protocol) { case SYS_SYNC_FIFO: break; case SYS_SYNC_PRIORITY: break; case SYS_SYNC_PRIORITY_INHERIT: break; default: sys_semaphore.Error("sys_semaphore_create(): unknown protocol (0x%x)", protocol); return CELL_EINVAL; } if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data()) { sys_semaphore.Error("sys_semaphore_create(): unknown attributes (pshared=0x%x, ipc_key=0x%x, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); return CELL_EINVAL; } *sem = semaphore_create(initial_val, max_val, protocol, attr->name_u64); return CELL_OK; }
int sys_lwmutex_t::unlock(be_t<u32> tid) { if (mutex.unlock(tid, tid) != SMR_OK) { return CELL_EPERM; } else { if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) { sc_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value (%d)", (u32)sleep_queue, (u32)recursive_count); recursive_count = 1; } recursive_count -= 1; if (!recursive_count.ToBE()) { be_t<u32> target = 0; switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) { case se32(SYS_SYNC_FIFO): case se32(SYS_SYNC_PRIORITY): SleepQueue* sq; if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; target = attribute.ToBE() & se32(SYS_SYNC_FIFO) ? sq->pop() : sq->pop_prio(); case se32(SYS_SYNC_RETRY): break; } if (target) mutex.unlock(tid, target); else mutex.unlock(tid); } return CELL_OK; } }
s32 sys_spinlock_trylock(vm::ptr<std::atomic<be_t<u32>>> lock) { sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.addr()); // prx: exchange with 0xabadcafe, translate exchanged value if (lock->exchange(be_t<u32>::MakeFromBE(se32(0xabadcafe))).ToBE()) { return CELL_EBUSY; } return CELL_OK; }
int sys_semaphore_create(mem32_t sem, mem_ptr_t<sys_semaphore_attribute> attr, int initial_count, int max_count) { sys_sem.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)", sem.GetAddr(), attr.GetAddr(), initial_count, max_count); if (!sem.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } if (max_count <= 0 || initial_count > max_count || initial_count < 0) { sys_sem.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count); return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) { sys_sem.Error("sys_semaphore_create(): invalid pshared value(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_sem.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT protocol"); break; case se32(SYS_SYNC_RETRY): sys_sem.Error("Invalid SYS_SYNC_RETRY protocol"); return CELL_EINVAL; default: sys_sem.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; } sem = sys_sem.GetNewId(new Semaphore(initial_count, max_count, attr->protocol, attr->name_u64)); ConLog.Write("*** semaphore created [%s] (protocol=0x%x): id = %d", std::string(attr->name, 8).c_str(), (u32)attr->protocol, sem.GetValue()); return CELL_OK; }
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex) { sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); const be_t<u32> tid = be_t<u32>::make(CPU.GetId()); // check owner if (lwmutex->owner.read_relaxed() != tid) { return CELL_EPERM; } if (lwmutex->recursive_count.data()) { // recursive unlocking succeeded lwmutex->recursive_count--; return CELL_OK; } // ensure that waiter is zero if (lwmutex->lock_var.compare_and_swap_test({ tid, lwmutex::zero }, { lwmutex::free, lwmutex::zero })) { // unlocking succeeded return CELL_OK; } if (lwmutex->attribute.data() & se32(SYS_SYNC_RETRY)) { // TODO (protocol is ignored in current implementation) } // set special value lwmutex->owner.exchange(lwmutex::reserved); // call the syscall if (_sys_lwmutex_unlock(lwmutex->sleep_queue) == CELL_ESRCH) { return CELL_ESRCH; } return CELL_OK; }
//128 int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t<sys_event_queue_attr> attr, u64 event_queue_key, int size) { sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)", equeue_id.GetAddr(), attr.GetAddr(), event_queue_key, size); if(size <= 0 || size > 127) { return CELL_EINVAL; } if(!equeue_id.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid SYS_SYNC_RETRY protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_FIFO): break; default: sys_event.Error("Unknown 0x%x protocol attr", (u32)attr->protocol); return CELL_EINVAL; } switch (attr->type.ToBE()) { case se32(SYS_PPU_QUEUE): break; case se32(SYS_SPU_QUEUE): break; default: sys_event.Error("Unknown 0x%x type attr", (u32)attr->type); return CELL_EINVAL; } if (event_queue_key && Emu.GetEventManager().CheckKey(event_queue_key)) { return CELL_EEXIST; } EventQueue* eq = new EventQueue((u32)attr->protocol, (int)attr->type, attr->name_u64, event_queue_key, size); if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) { delete eq; return CELL_EAGAIN; } equeue_id = sys_event.GetNewId(eq); sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x): id = %d", wxString(attr->name, 8).wx_str(), (u32)attr->protocol, (int)attr->type, equeue_id.GetValue()); return CELL_OK; }
s32 sys_event_flag_create(vm::ptr<u32> eflag_id, vm::ptr<sys_event_flag_attr> attr, u64 init) { sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", eflag_id.addr(), attr.addr(), init); if (!eflag_id) { sys_event_flag.Error("sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x)", eflag_id.addr()); return CELL_EFAULT; } if (!attr) { sys_event_flag.Error("sys_event_flag_create(): invalid memory access (attr_addr=0x%x)", attr.addr()); return CELL_EFAULT; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_RETRY"); break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_PRIORITY_INHERIT"); break; case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) return CELL_EINVAL; switch (attr->type.ToBE()) { case se32(SYS_SYNC_WAITER_SINGLE): break; case se32(SYS_SYNC_WAITER_MULTIPLE): break; default: return CELL_EINVAL; } u32 id = sys_event_flag.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type), TYPE_EVENT_FLAG); *eflag_id = id; sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d", std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, id); return CELL_OK; }
s32 sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr) { sys_mutex.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.GetAddr(), attr.GetAddr()); switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mutex.Todo("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT"); break; case se32(SYS_SYNC_RETRY): sys_mutex.Error("sys_mutex_create(): SYS_SYNC_RETRY"); return CELL_EINVAL; default: sys_mutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; } bool is_recursive; switch (attr->recursive.ToBE()) { case se32(SYS_SYNC_RECURSIVE): is_recursive = true; break; case se32(SYS_SYNC_NOT_RECURSIVE): is_recursive = false; break; default: sys_mutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) { sys_mutex.Error("Unknown pshared attribute(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } u32 tid = GetCurrentPPUThread().GetId(); Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64); u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); mutex->m_mutex.lock(tid); mutex->id = id; mutex_id = id; mutex->m_mutex.unlock(tid); sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), mutex_id.GetValue()); // TODO: unlock mutex when owner thread does exit return CELL_OK; }
int sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr) { sys_mtx.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.GetAddr(), attr.GetAddr()); if (!mutex_id.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mtx.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT protocol"); break; case se32(SYS_SYNC_RETRY): sys_mtx.Error("Invalid SYS_SYNC_RETRY protocol"); return CELL_EINVAL; default: sys_mtx.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; } bool is_recursive; switch (attr->recursive.ToBE()) { case se32(SYS_SYNC_RECURSIVE): is_recursive = true; break; case se32(SYS_SYNC_NOT_RECURSIVE): is_recursive = false; break; default: sys_mtx.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) { sys_mtx.Error("Unknown pshared attribute(0x%x)", (u32)attr->pshared); return CELL_EINVAL; } mutex_id = sys_mtx.GetNewId(new Mutex((u32)attr->protocol, is_recursive, attr->name_u64)); sys_mtx.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", wxString(attr->name, 8).wx_str(), (u32)attr->protocol, wxString(is_recursive ? "true" : "false").wx_str(), mutex_id.GetValue()); // TODO: unlock mutex when owner thread does exit return CELL_OK; }
s32 sys_event_queue_create(vm::ptr<be_t<u32>> equeue_id, vm::ptr<sys_event_queue_attr> attr, u64 event_queue_key, int size) { sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)", equeue_id.addr(), attr.addr(), event_queue_key, size); if(size <= 0 || size > 127) { return CELL_EINVAL; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid SYS_SYNC_RETRY protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_FIFO): break; default: sys_event.Error("Unknown 0x%x protocol attr", (u32)attr->protocol); return CELL_EINVAL; } switch (attr->type.ToBE()) { case se32(SYS_PPU_QUEUE): break; case se32(SYS_SPU_QUEUE): break; default: sys_event.Error("Unknown 0x%x type attr", (u32)attr->type); return CELL_EINVAL; } if (event_queue_key && Emu.GetEventManager().CheckKey(event_queue_key)) { return CELL_EEXIST; } EventQueue* eq = new EventQueue((u32)attr->protocol, (int)attr->type, attr->name_u64, event_queue_key, size); if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) { delete eq; return CELL_EAGAIN; } u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); *equeue_id = id; sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x): id = %d", std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, id); return CELL_OK; }
void sys_spinlock_lock(vm::ptr<std::atomic<be_t<u32>>> lock) { sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.addr()); // prx: exchange with 0xabadcafe, repeat until exchanged with 0 while (lock->exchange(be_t<u32>::MakeFromBE(se32(0xabadcafe))).ToBE()) { while (lock->load(std::memory_order_relaxed).ToBE()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { break; } } if (Emu.IsStopped()) { sys_spinlock.Warning("sys_spinlock_lock(0x%x) aborted", lock.addr()); break; } } }
int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init) { sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", eflag_id.GetAddr(), attr.GetAddr(), init); if(!eflag_id.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_event_flag.Warning("TODO: SYS_SYNC_RETRY attr"); break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } if (attr->pshared.ToBE() != se32(0x200)) { return CELL_EINVAL; } switch (attr->type.ToBE()) { case se32(SYS_SYNC_WAITER_SINGLE): break; case se32(SYS_SYNC_WAITER_MULTIPLE): break; default: return CELL_EINVAL; } eflag_id = sys_event_flag.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type)); sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d", std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, eflag_id.GetValue()); return CELL_OK; }