diff --git a/Utilities/BEType.h b/Utilities/BEType.h index cc6a6fed62..cfd2c4265e 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -2,6 +2,10 @@ #include "Utilities/GNU.h" +#define se16(x) const_se_t::value +#define se32(x) const_se_t::value +#define se64(x) const_se_t::value + template struct se_t; template struct se_t { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } }; template struct se_t { static __forceinline void func(T& dst, const T src) { (u16&)dst = _byteswap_ushort((u16&)src); } }; diff --git a/Utilities/SMutex.cpp b/Utilities/SMutex.cpp new file mode 100644 index 0000000000..3c1eecb3fc --- /dev/null +++ b/Utilities/SMutex.cpp @@ -0,0 +1,26 @@ +#include +#include + +__forceinline void SM_Sleep() +{ + Sleep(1); +} + +__forceinline DWORD SM_GetCurrentThreadId() +{ + return GetCurrentThreadId(); +} + +__forceinline u32 SM_GetCurrentCPUThreadId() +{ + if (CPUThread* t = GetCurrentCPUThread()) + { + return t->GetId(); + } + return 0; +} + +__forceinline be_t SM_GetCurrentCPUThreadIdBE() +{ + return SM_GetCurrentCPUThreadId(); +} \ No newline at end of file diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h new file mode 100644 index 0000000000..ac5ec269e8 --- /dev/null +++ b/Utilities/SMutex.h @@ -0,0 +1,155 @@ +#pragma once +#include + +extern void SM_Sleep(); +extern DWORD SM_GetCurrentThreadId(); +extern u32 SM_GetCurrentCPUThreadId(); +extern be_t SM_GetCurrentCPUThreadIdBE(); + +enum SMutexResult +{ + SMR_OK = 0, // succeeded (lock, trylock, unlock) + SMR_FAILED, // failed (trylock, unlock) + SMR_DEADLOCK, // mutex reached deadlock (lock, trylock) + SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread + SMR_PERMITTED, // not owner of the mutex (unlock) + SMR_ABORT, // emulator has been stopped (lock, trylock, unlock) + SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock) + SMR_TIMEOUT, // timed out (lock) +}; + +template +< + typename T, + u32 free_value = 0, + u32 dead_value = ~0, + void (wait)() = SM_Sleep +> +class SMutexBase +{ + static_assert(sizeof(T) == 4, "Invalid SMutexBase typename"); + std::atomic owner; + +public: + SMutexBase() + : owner((T)free_value) + { + } + + ~SMutexBase() + { + lock((T)dead_value); + owner = (T)dead_value; + } + + __forceinline T GetOwner() const + { + return (T&)owner; + } + + SMutexResult trylock(T tid) + { + T old = (T)free_value; + + if (!owner.compare_exchange_strong(old, tid)) + { + if (old == tid) + { + return SMR_DEADLOCK; + } + if (Emu.IsStopped()) + { + return SMR_ABORT; + } + if (old == (T)dead_value) + { + return SMR_DESTROYED; + } + + return SMR_FAILED; + } + + return SMR_OK; + } + + SMutexResult unlock(T tid, T to = (T)free_value) + { + T old = tid; + + if (!owner.compare_exchange_strong(old, to)) + { + if (old == (T)free_value) + { + return SMR_FAILED; + } + if (old == (T)dead_value) + { + return SMR_DESTROYED; + } + + return SMR_PERMITTED; + } + + return SMR_OK; + } + + SMutexResult lock(T tid, u64 timeout = 0) + { + u64 counter = 0; + + while (true) + { + switch (SMutexResult res = trylock(tid)) + { + case SMR_FAILED: break; + default: return res; + } + + wait(); + + if (timeout && counter++ > timeout) + { + return SMR_TIMEOUT; + } + } + } +}; + +template +class SMutexLockerBase +{ + SMutexBase& sm; +public: + const T tid; + + SMutexLockerBase(SMutexBase& _sm) + : sm(_sm) + , tid(get_tid()) + { + if (!tid) + { + ConLog.Error("SMutexLockerBase: thread id == 0"); + Emu.Pause(); + } + sm.lock(tid); + } + + ~SMutexLockerBase() + { + sm.unlock(tid); + } +}; + +typedef SMutexBase + SMutexGeneral; +typedef SMutexBase + SMutex; +typedef SMutexBase> + SMutexBE; + +typedef SMutexLockerBase + SMutexGeneralLocker; +typedef SMutexLockerBase + SMutexLocker; +typedef SMutexLockerBase, SM_GetCurrentCPUThreadIdBE> + SMutexBELocker; \ No newline at end of file diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 1a7ff1b011..df0320a54a 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "CPUThread.h" +reservation_struct reservation; + CPUThread* GetCurrentCPUThread() { return (CPUThread*)GetCurrentNamedThread(); @@ -89,14 +91,12 @@ void CPUThread::Wait(const CPUThread& thr) bool CPUThread::Sync() { - wxCriticalSectionLocker lock(m_cs_sync); - return m_sync_wait; } int CPUThread::ThreadStatus() { - if(Emu.IsStopped()) + if(Emu.IsStopped() || IsStopped() || IsPaused()) { return CPUThread_Stopped; } @@ -236,7 +236,7 @@ void CPUThread::Pause() DoPause(); Emu.CheckStatus(); - ThreadBase::Stop(); + // ThreadBase::Stop(); // "Abort() called" exception #ifndef QT_UI wxGetApp().SendDbgCommand(DID_PAUSED_THREAD, this); #endif diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 1a412ea121..4010adc7c5 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -1,6 +1,25 @@ #pragma once #include "Emu/Memory/MemoryBlock.h" #include "Emu/CPU/CPUDecoder.h" +#include "Utilities/SMutex.h" + +struct reservation_struct +{ + SMutex mutex; // mutex for updating reservation_owner and data + volatile u32 owner; // id of thread that got reservation + volatile u32 addr; + volatile u32 size; + volatile u32 data32; + volatile u64 data64; + // atm, PPU can't break SPU MFC reservation correctly + + __forceinline void clear() + { + owner = 0; + } +}; + +extern reservation_struct reservation; enum CPUThreadType { diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index b8d7aad82f..46bdce578b 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -76,6 +76,8 @@ void CPUThreadManager::RemoveThread(const u32 id) s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id) { + std::lock_guard lock(m_mtx_thread); + s32 num = 0; for(u32 i=0; i lock(m_mtx_thread); + for(u32 i=0; i> sh; - for (uint b = 14; b >= 0; b--) + for (uint b = 14; ~b; b--) { CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] >> sh) | (CPU.VPR[va]._u8[b+1] << (8 - sh)); } @@ -2362,9 +2362,12 @@ private: void LWARX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.reserve_addr = addr; - CPU.reserve = true; - CPU.GPR[rd] = Memory.Read32(addr); + + SMutexLocker lock(reservation.mutex); + reservation.owner = lock.tid; + reservation.addr = addr; + reservation.size = 4; + reservation.data32 = CPU.GPR[rd] = Memory.Read32(addr); } void LDX(u32 rd, u32 ra, u32 rb) { @@ -2535,9 +2538,12 @@ private: void LDARX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.reserve_addr = addr; - CPU.reserve = true; - CPU.GPR[rd] = Memory.Read64(addr); + + SMutexLocker lock(reservation.mutex); + reservation.owner = lock.tid; + reservation.addr = addr; + reservation.size = 8; + reservation.data64 = CPU.GPR[rd] = Memory.Read64(addr); } void DCBF(u32 ra, u32 rb) { @@ -2650,25 +2656,19 @@ private: } void STWCX_(u32 rs, u32 ra, u32 rb) { - CPU.SetCR(0, CPU.XER.SO ? CR_SO : 0); - - if(CPU.reserve) - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if(addr == CPU.reserve_addr) - { - Memory.Write32(addr, CPU.GPR[rs]); - CPU.SetCR_EQ(0, true); - CPU.reserve = false; - } - else - { - static const bool u = 0; - if(u) Memory.Write32(addr, CPU.GPR[rs]); - CPU.SetCR_EQ(0, u); - CPU.reserve = false; - } + SMutexLocker lock(reservation.mutex); + if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 4) + { + // Memory.Write32(addr, CPU.GPR[rs]); + CPU.SetCR_EQ(0, InterlockedCompareExchange((volatile long*)(Memory + addr), (u32)CPU.GPR[rs], reservation.data32) == reservation.data32); + reservation.clear(); + } + else + { + CPU.SetCR_EQ(0, false); + if (lock.tid == reservation.owner) reservation.clear(); } } void STWX(u32 rs, u32 ra, u32 rb) @@ -2709,23 +2709,19 @@ private: } void STDCX_(u32 rs, u32 ra, u32 rb) { - CPU.SetCR(0, CPU.XER.SO ? CR_SO : 0); - if(!CPU.reserve) - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if(addr == CPU.reserve_addr) - { - Memory.Write64(addr, CPU.GPR[rs]); - CPU.SetCR_EQ(0, true); - } - else - { - static const bool u = 0; - if(u) Memory.Write64(addr, CPU.GPR[rs]); - CPU.SetCR_EQ(0, u); - CPU.reserve = false; - } + SMutexLocker lock(reservation.mutex); + if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 8) + { + // Memory.Write64(addr, CPU.GPR[rs]); + CPU.SetCR_EQ(0, InterlockedCompareExchange64((volatile long long*)(Memory + addr), CPU.GPR[rs], reservation.data64) == reservation.data64); + reservation.clear(); + } + else + { + CPU.SetCR_EQ(0, false); + if (lock.tid == reservation.owner) reservation.clear(); } } void STBX(u32 rs, u32 ra, u32 rb) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 6bf0f5337b..e788d0e9f4 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -44,9 +44,6 @@ void PPUThread::DoReset() VSCR.VSCR = 0; cycle = 0; - - reserve = false; - reserve_addr = 0; } void PPUThread::AddArgv(const wxString& arg) @@ -67,14 +64,16 @@ void PPUThread::InitRegs() SetPc(pc); - const s32 thread_num = Emu.GetCPU().GetThreadNumById(GetType(), GetId()); + /* + const s32 thread_num = Emu.GetCPU().GetThread NumById(GetType(), GetId()); if(thread_num < 0) { - ConLog.Error("GetThreadNumById failed."); + ConLog.Error("GetThread NumById failed."); Emu.Pause(); return; } + */ /* const s32 tls_size = Emu.GetTLSFilesz() * thread_num; @@ -119,7 +118,7 @@ void PPUThread::InitRegs() GPR[6] = m_args[3]; } - u32 prx_mem = Memory.PRXMem.Alloc(0x10000); + u32 prx_mem = Memory.PRXMem.AllocAlign(0x10000); Memory.Write64(prx_mem, 0xDEADBEEFABADCAFE); GPR[0] = pc; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index c85f15fd1b..74c200b104 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -602,9 +602,6 @@ public: }; }; - u64 reserve_addr; - bool reserve; - u64 cycle; public: diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 1dcb845bd5..63d67deb2d 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -32,15 +32,8 @@ private: //0 - 10 void STOP(u32 code) { - if(code & 0x2000) - { - CPU.SetExitStatus(code & 0xfff); - } - else - { - ConLog.Warning("STOP: 0x%x", code); - //Emu.Pause(); - } + ConLog.Warning("STOP: 0x%x (m_exit_status -> 0)", code); + CPU.SetExitStatus(0); CPU.Stop(); } void LNOP() @@ -146,7 +139,7 @@ private: void ROTH(u32 rt, u32 ra, u32 rb) { for (int h = 0; h < 8; h++) - CPU.GPR[rt]._u16[h] = (CPU.GPR[ra]._u16[h] << (CPU.GPR[rb]._u16[h] & 0xf)) | (CPU.GPR[ra]._u16[h] >> (16 - (CPU.GPR[rb]._u32[h] & 0xf))); + CPU.GPR[rt]._u16[h] = (CPU.GPR[ra]._u16[h] << (CPU.GPR[rb]._u16[h] & 0xf)) | (CPU.GPR[ra]._u16[h] >> (16 - (CPU.GPR[rb]._u16[h] & 0xf))); } void ROTHM(u32 rt, u32 ra, u32 rb) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 60e3cf9238..6a0d8f5892 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -61,7 +61,7 @@ void SPUThread::InitRegs() u64 SPUThread::GetFreeStackSize() const { - return (GetStackAddr() + GetStackSize()) - GPR[1]._u64[3]; + return (GetStackAddr() + GetStackSize()) - GPR[1]._u32[3]; } void SPUThread::DoRun() diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index e6a446c94b..e4cd1ea0e6 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -4,8 +4,6 @@ #include "MFC.h" #include -extern std::mutex g_SyncMutex; //can provide compatability for CellSyncMutex through SPU<>PPU and SPU<>SPU - static const char* spu_reg_name[128] = { "$LR", "$SP", "$2", "$3", "$4", "$5", "$6", "$7", @@ -391,7 +389,7 @@ public: else { #ifdef _M_X64 - _InterlockedOr64((volatile __int64*)m_indval, ((u64)value << 32) | 1); + InterlockedOr64((volatile __int64*)m_indval, ((u64)value << 32) | 1); #else ConLog.Error("PushUncond_OR(): no code compiled"); #endif @@ -516,34 +514,80 @@ public: case MFC_PUT_CMD: case MFC_GET_CMD: { - if (enable_log) ConLog.Write("DMA %s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x", + /* if (enable_log) ConLog.Write("DMA %s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x", op & MFC_PUT_CMD ? "PUT" : "GET", op & MFC_BARRIER_MASK ? "B" : "", op & MFC_FENCE_MASK ? "F" : "", - lsa, ea, tag, size, cmd); - MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); + lsa, ea, tag, size, cmd); */ + if (op & MFC_PUT_CMD) + { + SMutexLocker lock(reservation.mutex); + MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); + if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) || + (ea + size > reservation.addr && ea <= reservation.addr + reservation.size)) + { + reservation.clear(); + } + } + else + { + MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); + } } break; case MFC_GETLLAR_CMD: case MFC_PUTLLC_CMD: case MFC_PUTLLUC_CMD: + case MFC_PUTQLLUC_CMD: { - if (op == MFC_GETLLAR_CMD) - { - g_SyncMutex.lock(); - } - - ConLog.Warning("DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x", - op == MFC_GETLLAR_CMD ? "GETLLAR" : op == MFC_PUTLLC_CMD ? "PUTLLC" : "PUTLLUC", + if (enable_log) ConLog.Write("DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x", + op == MFC_GETLLAR_CMD ? "GETLLAR" : op == MFC_PUTLLC_CMD ? "PUTLLC" : op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC", lsa, ea, tag, size, cmd); - dmac.ProcessCmd(op == MFC_GETLLAR_CMD ? MFC_GET_CMD : MFC_PUT_CMD, tag, lsa, ea, 128); - Prxy.AtomicStat.PushUncond(op == MFC_GETLLAR_CMD ? MFC_GETLLAR_SUCCESS : op == MFC_PUTLLC_CMD ? MFC_PUTLLC_SUCCESS : MFC_PUTLLUC_SUCCESS); - - if (op == MFC_PUTLLC_CMD || op == MFC_PUTLLUC_CMD) + if (op == MFC_GETLLAR_CMD) // get reservation { - g_SyncMutex.unlock(); + SMutexLocker lock(reservation.mutex); + reservation.owner = lock.tid; + reservation.addr = ea; + reservation.size = 128; + dmac.ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128); + Prxy.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); + } + else if (op == MFC_PUTLLC_CMD) // store conditional + { + SMutexLocker lock(reservation.mutex); + if (reservation.owner == lock.tid) // succeeded + { + if (reservation.addr == ea && reservation.size == 128) + { + dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + } + else + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); + } + reservation.clear(); + } + else // failed + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); + } + } + else // store unconditional + { + SMutexLocker lock(reservation.mutex); + dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + if (op == MFC_PUTLLUC_CMD) + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); + } + if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) || + (ea + size > reservation.addr && ea <= reservation.addr + reservation.size)) + { + reservation.clear(); + } } } break; diff --git a/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl b/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl index bbdafbd80f..7af30bc435 100644 --- a/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl +++ b/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl @@ -10,11 +10,13 @@ DynamicMemoryBlockBase::DynamicMemoryBlockBase() template const u32 DynamicMemoryBlockBase::GetUsedSize() const { + std::lock_guard lock(m_lock); + u32 size = 0; - for(u32 i=0; i::IsInMyRange(const u64 addr, const u32 size) template bool DynamicMemoryBlockBase::IsMyAddress(const u64 addr) { - for(u32 i=0; i= m_used_mem[i].addr && addr < m_used_mem[i].addr + m_used_mem[i].size) - { - return true; - } - } + if (!IsInMyRange(addr)) return false; - return false; + const u32 index = MemoryBlock::FixAddr(addr) >> 12; + + return m_pages[index] && !m_locked[index]; } template MemoryBlock* DynamicMemoryBlockBase::SetRange(const u64 start, const u32 size) { - m_max_size = size; + std::lock_guard lock(m_lock); + + m_max_size = PAGE_4K(size); MemoryBlock::SetRange(start, 0); + const u32 page_count = m_max_size >> 12; + m_pages.SetCount(page_count); + m_locked.SetCount(page_count); + memset(m_pages.GetPtr(), 0, sizeof(u8*) * page_count); + memset(m_locked.GetPtr(), 0, sizeof(u8*) * page_count); + return this; } template void DynamicMemoryBlockBase::Delete() { - m_used_mem.Clear(); + std::lock_guard lock(m_lock); + + m_allocated.Clear(); m_max_size = 0; + m_pages.Clear(); + m_locked.Clear(); + MemoryBlock::Delete(); } template -bool DynamicMemoryBlockBase::Alloc(u64 addr, u32 size) +bool DynamicMemoryBlockBase::AllocFixed(u64 addr, u32 size) { + size = PAGE_4K(size + (addr & 4095)); // align size + + addr &= ~4095; // align start address + if(!IsInMyRange(addr, size)) { assert(0); @@ -78,43 +93,77 @@ bool DynamicMemoryBlockBase::Alloc(u64 addr, u32 size) return false; } - for(u32 i=0; i lock(m_lock); + + for(u32 i=0; i= m_used_mem[i].addr && addr < m_used_mem[i].addr + m_used_mem[i].size) return false; + if(addr >= m_allocated[i].addr && addr < m_allocated[i].addr + m_allocated[i].size) return false; } - AppendUsedMem(addr, size); + AppendMem(addr, size); return true; } template -void DynamicMemoryBlockBase::AppendUsedMem(u64 addr, u32 size) +void DynamicMemoryBlockBase::AppendMem(u64 addr, u32 size) /* private */ { - m_used_mem.Move(new MemBlockInfo(addr, size)); + u8* pointer = (u8*)m_allocated[m_allocated.Move(new MemBlockInfo(addr, size))].mem; + + const u32 first = MemoryBlock::FixAddr(addr) >> 12; + + const u32 last = first + ((size - 1) >> 12); + + for (u32 i = first; i <= last; i++) + { + m_pages[i] = pointer; + m_locked[i] = nullptr; + pointer += 4096; + } } template -u64 DynamicMemoryBlockBase::Alloc(u32 size) +u64 DynamicMemoryBlockBase::AllocAlign(u32 size, u32 align) { - for(u64 addr = MemoryBlock::GetStartAddr(); addr <= MemoryBlock::GetEndAddr() - size;) + size = PAGE_4K(size); + u32 exsize; + + if (align <= 4096) + { + align = 0; + exsize = size; + } + else + { + align &= ~4095; + exsize = size + align - 1; + } + + std::lock_guard lock(m_lock); + + for(u64 addr = MemoryBlock::GetStartAddr(); addr <= MemoryBlock::GetEndAddr() - exsize;) { bool is_good_addr = true; - for(u32 i=0; i= m_used_mem[i].addr && addr < m_used_mem[i].addr + m_used_mem[i].size) || - (m_used_mem[i].addr >= addr && m_used_mem[i].addr < addr + size)) + if((addr >= m_allocated[i].addr && addr < m_allocated[i].addr + m_allocated[i].size) || + (m_allocated[i].addr >= addr && m_allocated[i].addr < addr + exsize)) { is_good_addr = false; - addr = m_used_mem[i].addr + m_used_mem[i].size; + addr = m_allocated[i].addr + m_allocated[i].size; break; } } if(!is_good_addr) continue; - AppendUsedMem(addr, size); + if (align) + { + addr = (addr + (align - 1)) & ~(align - 1); + } + + AppendMem(addr, size); return addr; } @@ -125,18 +174,38 @@ u64 DynamicMemoryBlockBase::Alloc(u32 size) template bool DynamicMemoryBlockBase::Alloc() { - return Alloc(GetSize() - GetUsedSize()) != 0; + return AllocAlign(GetSize() - GetUsedSize()) != 0; } template bool DynamicMemoryBlockBase::Free(u64 addr) -{ - for(u32 i=0; i lock(m_lock); + + for (u32 num = 0; num < m_allocated.GetCount(); num++) { - if(addr == m_used_mem[i].addr) + if (addr == m_allocated[num].addr) { - if(IsLocked(m_used_mem[i].addr)) return false; - m_used_mem.RemoveAt(i); + /* if(IsLocked(m_allocated[num].addr)) return false; */ + + const u32 first = MemoryBlock::FixAddr(addr) >> 12; + + const u32 last = first + ((m_allocated[num].size - 1) >> 12); + + // check if locked: + for (u32 i = first; i <= last; i++) + { + if (!m_pages[i] || m_locked[i]) return false; + } + + // clear pointers: + for (u32 i = first; i <= last; i++) + { + m_pages[i] = nullptr; + m_locked[i] = nullptr; + } + + m_allocated.RemoveAt(num); return true; } } @@ -145,15 +214,15 @@ bool DynamicMemoryBlockBase::Free(u64 addr) } template -u8* DynamicMemoryBlockBase::GetMem(u64 addr) const +u8* DynamicMemoryBlockBase::GetMem(u64 addr) const // lock-free, addr is fixed { - for(u32 i=0; i> 12; - if(addr >= _addr && addr < _addr + m_used_mem[i].size) + if (index < m_pages.GetCount()) + { + if (u8* res = m_pages[index]) { - return (u8*)m_used_mem[i].mem + addr - _addr; + return res + (addr & 4095); } } @@ -163,28 +232,28 @@ u8* DynamicMemoryBlockBase::GetMem(u64 addr) const } template -bool DynamicMemoryBlockBase::IsLocked(const u64 addr) +bool DynamicMemoryBlockBase::IsLocked(u64 addr) // lock-free { - for(u32 i=0; i> 12; + + if (index < m_locked.GetCount()) { - return true; + if (m_locked[index]) return true; } } return false; } -template -void DynamicMemoryBlockBase::AppendLockedMem(u64 addr, u32 size) -{ - m_locked_mem.Move(new MemBlockInfo(addr, size)); -} - template bool DynamicMemoryBlockBase::Lock(u64 addr, u32 size) { + size = PAGE_4K(size); // align size + + addr &= ~4095; // align start address + if(!IsInMyRange(addr, size)) { assert(0); @@ -196,33 +265,58 @@ bool DynamicMemoryBlockBase::Lock(u64 addr, u32 size) return false; } - AppendLockedMem(addr, size); + const u32 first = MemoryBlock::FixAddr(addr) >> 12; + + const u32 last = first + ((size - 1) >> 12); + + for (u32 i = first; i <= last; i++) + { + if (u8* pointer = m_pages[i]) + { + m_locked[i] = pointer; + m_pages[i] = nullptr; + } + else // already locked or empty + { + } + } return true; } template -bool DynamicMemoryBlockBase::Unlock(u64 addr , u32 size) +bool DynamicMemoryBlockBase::Unlock(u64 addr, u32 size) { - for(u32 i=0; i> 12; + + const u32 last = first + ((size - 1) >> 12); + + for (u32 i = first; i <= last; i++) + { + if (u8* pointer = m_locked[i]) + { + m_pages[i] = pointer; + m_locked[i] = nullptr; + } + else // already unlocked or empty { - if(m_locked_mem.Get(i).size > size) - { - m_locked_mem.Get(i).size -= size; - } - else if(m_locked_mem.Get(i).size == size) - { - m_locked_mem.RemoveAt(i); - } - else - { - return false; - } - return true; } } - return false; + return true; } diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 053c0cf38d..b179619fc9 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -341,7 +341,7 @@ public: u64 Alloc(const u32 size, const u32 align) { - return UserMemory->Alloc(AlignAddr(size, align)); + return UserMemory->AllocAlign(size, align); } bool Free(const u64 addr) diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index 8fe58bdcfd..2b0d11c04e 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -1,5 +1,7 @@ #pragma once +#define PAGE_4K(x) (x + 4095) & ~(4095) + struct MemInfo { u64 addr; @@ -21,8 +23,8 @@ struct MemBlockInfo : public MemInfo void* mem; MemBlockInfo(u64 _addr, u32 _size) - : MemInfo(_addr, _size) - , mem(malloc(_size)) + : MemInfo(_addr, PAGE_4K(_size)) + , mem(_aligned_malloc(PAGE_4K(_size), 128)) { if(!mem) { @@ -35,7 +37,7 @@ struct MemBlockInfo : public MemInfo ~MemBlockInfo() { - free(mem); + _aligned_free(mem); mem = nullptr; } }; @@ -120,8 +122,8 @@ public: u8* GetMem() const { return mem; } virtual u8* GetMem(u64 addr) const { return mem + addr; } - virtual bool Alloc(u64 addr, u32 size) { return false; } - virtual u64 Alloc(u32 size) { return 0; } + virtual bool AllocFixed(u64 addr, u32 size) { return false; } + virtual u64 AllocAlign(u32 size, u32 align = 1) { return 0; } virtual bool Alloc() { return false; } virtual bool Free(u64 addr) { return false; } virtual bool Lock(u64 addr, u32 size) { return false; } @@ -190,8 +192,11 @@ class NullMemoryBlock : public MemoryBlock template class DynamicMemoryBlockBase : public PT { - Array m_used_mem; - Array m_locked_mem; + mutable std::mutex m_lock; + Array m_allocated; // allocation info + Array m_pages; // real addresses of every 4096 byte pages (array size should be fixed) + Array m_locked; // locked pages should be moved here + u32 m_max_size; public: @@ -209,8 +214,8 @@ public: virtual void Delete(); - virtual bool Alloc(u64 addr, u32 size); - virtual u64 Alloc(u32 size); + virtual bool AllocFixed(u64 addr, u32 size); + virtual u64 AllocAlign(u32 size, u32 align = 1); virtual bool Alloc(); virtual bool Free(u64 addr); virtual bool Lock(u64 addr, u32 size); @@ -219,8 +224,7 @@ public: virtual u8* GetMem(u64 addr) const; private: - void AppendUsedMem(u64 addr, u32 size); - void AppendLockedMem(u64 addr, u32 size); + void AppendMem(u64 addr, u32 size); }; class VirtualMemoryBlock : public MemoryBlock diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 118abc319a..2cdafe3fe0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -83,7 +83,7 @@ struct CellAudioPortConfig struct CellAudioConfig //custom structure { bool m_is_audio_initialized; - bool m_is_audio_port_open; + bool m_is_audio_port_opened; bool m_is_audio_port_started; }; @@ -216,7 +216,7 @@ int cellAudioPortOpen(mem_ptr_t audioParam, mem32_t portNum) cellAudio.Warning("cellAudioPortOpen(audioParam_addr=0x%x,portNum_addr=0x%x)",audioParam.GetAddr(),portNum.GetAddr()); if(!audioParam.IsGood() || !portNum.IsGood()) return CELL_AUDIO_ERROR_PORT_OPEN; - m_config->m_is_audio_port_open = true; + m_config->m_is_audio_port_opened = true; m_param->nChannel = audioParam->nChannel; m_param->nBlock = audioParam->nBlock; @@ -238,13 +238,13 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t portConfi //if(portNum > 7) return CELL_AUDIO_ERROR_PORT_FULL; - if(m_config->m_is_audio_port_open == false) + if(!m_config->m_is_audio_port_opened) { portConfig->status = CELL_AUDIO_STATUS_CLOSE; return CELL_OK; } - if(m_config->m_is_audio_port_started == true) + if(m_config->m_is_audio_port_started) { portConfig->status = CELL_AUDIO_STATUS_RUN; } @@ -268,7 +268,7 @@ int cellAudioPortStart(u32 portNum) { cellAudio.Warning("cellAudioPortStart(portNum=0x%x)",portNum); - if (m_config->m_is_audio_port_open == true) + if (!m_config->m_is_audio_port_opened) return CELL_AUDIO_ERROR_PORT_OPEN; m_config->m_is_audio_port_started = true; @@ -279,10 +279,10 @@ int cellAudioPortClose(u32 portNum) { cellAudio.Warning("cellAudioPortClose(portNum=0x%x)",portNum); - if (m_config->m_is_audio_port_open == false) + if (!m_config->m_is_audio_port_opened) return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - m_config->m_is_audio_port_open = false; + m_config->m_is_audio_port_opened = false; return CELL_OK; } @@ -1016,6 +1016,6 @@ void cellAudio_init() void cellAudio_unload() { m_config->m_is_audio_initialized = false; - m_config->m_is_audio_port_open = false; + m_config->m_is_audio_port_opened = false; m_config->m_is_audio_port_started = false; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index e3942e2fa0..99927ac4d1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -63,7 +63,7 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) { local_size = 0xf900000; //TODO local_addr = Memory.RSXFBMem.GetStartAddr(); - Memory.RSXFBMem.Alloc(local_size); + Memory.RSXFBMem.AllocAlign(local_size); } cellGcmSys.Warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size); @@ -78,7 +78,7 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) current_config.coreFrequency = re32(500000000); InitOffsetTable(); - Memory.RSXCMDMem.Alloc(cmdSize); + Memory.RSXCMDMem.AllocAlign(cmdSize); Memory.MemoryBlocks.push_back(Memory.RSXIOMem.SetRange(0x50000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase cellGcmMapEaIoAddress(ioAddress, 0, ioSize); @@ -89,7 +89,7 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) current_context.current = current_context.begin; current_context.callback = re32(Emu.GetRSXCallback() - 4); - gcm_info.context_addr = Memory.MainMem.Alloc(0x1000); + gcm_info.context_addr = Memory.MainMem.AllocAlign(0x1000); gcm_info.control_addr = gcm_info.context_addr + 0x40; Memory.WriteData(gcm_info.context_addr, current_context); @@ -167,7 +167,7 @@ int cellGcmSetPrepareFlip(mem_ptr_t ctxt, u32 id) return CELL_GCM_ERROR_FAILURE; } - GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); + GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); // could stall on exit u32 current = re(ctxt->current); u32 end = re(ctxt->end); @@ -682,7 +682,7 @@ int32_t cellGcmMapLocalMemory(u64 address, u64 size) { local_size = 0xf900000; //TODO local_addr = Memory.RSXFBMem.GetStartAddr(); - Memory.RSXFBMem.Alloc(local_size); + Memory.RSXFBMem.AllocAlign(local_size); Memory.Write32(address, local_addr); Memory.Write32(size, local_size); } @@ -749,7 +749,7 @@ int32_t cellGcmUnmapEaIoAddress(u64 ea) ea = ea >> 20; io = Memory.Read16(offsetTable.io + (ea*sizeof(u16))); - for(int i=0; i> 20; ea = Memory.Read16(offsetTable.ea + (io*sizeof(u16))); - for(int i=0; i pSelf, u32 pInfo_addr, pInfo->numberOfChannels = pAudio->channels; pInfo->samplingFrequency = CELL_PAMF_FS_48kHz; - if (pAudio->bps = 0x40) + if (pAudio->bps == 0x40) pInfo->bitsPerSample = CELL_PAMF_BIT_LENGTH_16; else //TODO: CELL_PAMF_BIT_LENGTH_24 diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 452f6b1724..4a7cb65e63 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -4,9 +4,7 @@ #include void cellSync_init(); -void cellSync_unload(); -Module cellSync("cellSync", cellSync_init, nullptr, cellSync_unload); -std::mutex g_SyncMutex; +Module cellSync("cellSync", cellSync_init); // Return Codes enum @@ -56,8 +54,13 @@ int cellSyncMutexInitialize(mem_ptr_t mutex) return CELL_SYNC_ERROR_ALIGN; } - { // global mutex - std::lock_guard lock(g_SyncMutex); //??? + { + SMutexLocker lock(reservation.mutex); + if ((reservation.addr + reservation.size > mutex.GetAddr() && reservation.addr <= mutex.GetAddr() + 4) || + (mutex.GetAddr() + 4 > reservation.addr && mutex.GetAddr() <= reservation.addr + reservation.size)) + { + reservation.clear(); + } mutex->m_data = 0; return CELL_OK; } @@ -77,8 +80,13 @@ int cellSyncMutexLock(mem_ptr_t mutex) } be_t old_order; - { // global mutex - std::lock_guard lock(g_SyncMutex); + { + SMutexLocker lock(reservation.mutex); + if ((reservation.addr + reservation.size > mutex.GetAddr() && reservation.addr <= mutex.GetAddr() + 4) || + (mutex.GetAddr() + 4 > reservation.addr && mutex.GetAddr() <= reservation.addr + reservation.size)) + { + reservation.clear(); + } old_order = mutex->m_order; mutex->m_order = mutex->m_order + 1; if (old_order == mutex->m_freed) @@ -98,7 +106,6 @@ int cellSyncMutexLock(mem_ptr_t mutex) mutex.GetAddr(), (u16)old_order, (u16)mutex->m_order, (u16)mutex->m_freed); } } - //while (_InterlockedExchange((volatile long*)&mutex->m_data, 1)) Sleep(1); _mm_mfence(); return CELL_OK; } @@ -115,8 +122,13 @@ int cellSyncMutexTryLock(mem_ptr_t mutex) { return CELL_SYNC_ERROR_ALIGN; } - { /* global mutex */ - std::lock_guard lock(g_SyncMutex); + { + SMutexLocker lock(reservation.mutex); + if ((reservation.addr + reservation.size > mutex.GetAddr() && reservation.addr <= mutex.GetAddr() + 4) || + (mutex.GetAddr() + 4 > reservation.addr && mutex.GetAddr() <= reservation.addr + reservation.size)) + { + reservation.clear(); + } if (mutex->m_order != mutex->m_freed) { return CELL_SYNC_ERROR_BUSY; @@ -140,7 +152,12 @@ int cellSyncMutexUnlock(mem_ptr_t mutex) } { /* global mutex */ - std::lock_guard lock(g_SyncMutex); + SMutexLocker lock(reservation.mutex); + if ((reservation.addr + reservation.size > mutex.GetAddr() && reservation.addr <= mutex.GetAddr() + 4) || + (mutex.GetAddr() + 4 > reservation.addr && mutex.GetAddr() <= reservation.addr + reservation.size)) + { + reservation.clear(); + } mutex->m_freed = mutex->m_freed + 1; return CELL_OK; } @@ -152,9 +169,4 @@ void cellSync_init() cellSync.AddFunc(0x1bb675c2, cellSyncMutexLock); cellSync.AddFunc(0xd06918c4, cellSyncMutexTryLock); cellSync.AddFunc(0x91f2b7b0, cellSyncMutexUnlock); -} - -void cellSync_unload() -{ - g_SyncMutex.unlock(); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index 7b1b65c290..4b13707b9a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -460,6 +460,11 @@ int cellSysutilCheckCallback() cellSysutil.Log("cellSysutilCheckCallback()"); Emu.GetCallbackManager().m_exit_callback.Check(); + CPUThread& thr = Emu.GetCallbackThread(); + + while(Emu.IsRunning() && thr.IsAlive()) + Sleep(1); + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index dd43be259e..d87bea125e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -164,6 +164,7 @@ void sysPrxForUser_init() //sysPrxForUser.AddFunc(0xaede4b03, sys_heap_free); //sysPrxForUser.AddFunc(0x8a561d92, sys_heap_delete_heap); sysPrxForUser.AddFunc(0xb2fcf2c8, sys_heap_create_heap); + sysPrxForUser.AddFunc(0x44265c08, _sys_heap_memalign); sysPrxForUser.AddFunc(0xb257540b, sys_mmapper_allocate_memory); sysPrxForUser.AddFunc(0xdc578057, sys_mmapper_map_memory); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp index a6fa5a6830..2c5ade09ac 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp @@ -176,8 +176,8 @@ void fsAioRead(u32 fd, mem_ptr_t aio, int xid, mem_func_ptr_toffset, buf_addr, (u64)aio->size, res, xid, path.c_str()); @@ -195,6 +195,7 @@ int cellFsAioRead(mem_ptr_t aio, mem32_t aio_id, mem_func_ptr_t attr, u64 event_queue_key, int size); extern int sys_event_queue_receive(u32 equeue_id, u32 event_addr, u32 timeout); extern int sys_event_port_create(u32 eport_id_addr, int port_type, u64 name); extern int sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id); extern int sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3); +extern int sys_event_queue_drain(u32 event_queue_id); + +//sys_event_flag +extern int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t attr, u64 init); +extern int sys_event_flag_destroy(u32 eflag_id); +extern int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u32 timeout); +extern int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result); +extern int sys_event_flag_set(u32 eflag_id, u64 bitptn); +extern int sys_event_flag_clear(u32 eflag_id, u64 bitptn); +extern int sys_event_flag_cancel(u32 eflag_id, mem32_t num); +extern int sys_event_flag_get(u32 eflag_id, mem64_t flags); //sys_semaphore extern int sys_semaphore_create(u32 sem_addr, u32 attr_addr, int initial_val, int max_val); @@ -188,10 +192,9 @@ extern int sys_ppu_thread_get_priority(u32 thread_id, u32 prio_addr); extern int sys_ppu_thread_get_stack_information(u32 info_addr); extern int sys_ppu_thread_stop(u32 thread_id); extern int sys_ppu_thread_restart(u32 thread_id); -extern int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u32 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr); +extern int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr); extern void sys_ppu_thread_once(u32 once_ctrl_addr, u32 entry); extern int sys_ppu_thread_get_id(const u32 id_addr); -extern int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr); //memory extern int sys_memory_container_create(u32 cid_addr, u32 yield_size); @@ -293,17 +296,20 @@ extern int sys_tty_write(u32 ch, u64 buf_addr, u32 len, u64 pwritelen_addr); //sys_heap extern int sys_heap_create_heap(const u32 heap_addr, const u32 start_addr, const u32 size); extern int sys_heap_malloc(const u32 heap_addr, const u32 size); +extern int _sys_heap_memalign(u32 heap_id, u32 align, u32 size, u64 p4); //sys_spu extern int sys_spu_image_open(mem_ptr_t img, u32 path_addr); extern int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t img, mem_ptr_t attr, mem_ptr_t arg); extern int sys_spu_thread_set_argument(u32 id, mem_ptr_t arg); +extern int sys_spu_thread_group_destroy(u32 id); extern int sys_spu_thread_group_start(u32 id); extern int sys_spu_thread_group_suspend(u32 id); extern int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t attr); extern int sys_spu_thread_create(mem32_t thread_id, mem32_t entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr); extern int sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup); extern int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status); +extern int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr); extern int sys_raw_spu_create(mem32_t id, u32 attr_addr); extern int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); extern int sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type); @@ -312,6 +318,8 @@ extern int sys_spu_thread_write_spu_mb(u32 id, u32 value); extern int sys_spu_thread_set_spu_cfg(u32 id, u64 value); extern int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value); extern int sys_spu_thread_write_snr(u32 id, u32 number, u32 value); +extern int sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num); +extern int sys_spu_thread_get_exit_status(u32 id, mem32_t status); //sys_time extern int sys_time_get_timezone(mem32_t timezone, mem32_t summertime); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp index 723fe1bfc2..92ebc62956 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp @@ -27,7 +27,7 @@ struct condition int sys_cond_create(u32 cond_addr, u32 mutex_id, u32 attr_addr) { - sys_cond.Log("sys_cond_create(cond_addr=0x%x, mutex_id=0x%x, attr_addr=%d)", + sys_cond.Warning("sys_cond_create(cond_addr=0x%x, mutex_id=0x%x, attr_addr=%d)", cond_addr, mutex_id, attr_addr); if(!Memory.IsGoodAddr(cond_addr) || !Memory.IsGoodAddr(attr_addr)) return CELL_EFAULT; @@ -68,9 +68,32 @@ int sys_cond_wait(u32 cond_id, u64 timeout) condition* cond_data = nullptr; if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH; - cond_data->cond.WaitTimeout(timeout ? timeout : INFINITE); + u32 counter = 0; + const u32 max_counter = timeout ? (timeout / 1000) : 20000; + do + { + if (Emu.IsStopped()) return CELL_ETIMEDOUT; - return CELL_OK; + switch (cond_data->cond.WaitTimeout(1)) + { + case wxCOND_NO_ERROR: return CELL_OK; + case wxCOND_TIMEOUT: break; + default: return CELL_EPERM; + } + + if (counter++ > max_counter) + { + if (!timeout) + { + sys_cond.Warning("sys_cond_wait(cond_id=0x%x, timeout=0x%llx): TIMEOUT", cond_id, timeout); + counter = 0; + } + else + { + return CELL_ETIMEDOUT; + } + } + } while (true); } int sys_cond_signal(u32 cond_id) diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp index 1f1461b86c..357f8cbfcf 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp @@ -5,128 +5,25 @@ SysCallBase sys_event("sys_event"); -int sys_event_flag_create(u32 eflag_id_addr, u32 attr_addr, u64 init) -{ - sys_event.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", eflag_id_addr, attr_addr, init); - - if(!Memory.IsGoodAddr(eflag_id_addr, 4) || !Memory.IsGoodAddr(attr_addr, sizeof(sys_event_flag_attr))) - { - return CELL_EFAULT; - } - - sys_event_flag_attr attr = (sys_event_flag_attr&)Memory[attr_addr]; - attr.protocol = re(attr.protocol); - attr.pshared = re(attr.pshared); - attr.ipc_key = re(attr.ipc_key); - attr.flags = re(attr.flags); - attr.type = re(attr.type); - - sys_event.Warning("name = %s", attr.name); - sys_event.Warning("type = %d", attr.type); - - Memory.Write32(eflag_id_addr, sys_event.GetNewId(new event_flag(init, attr))); - - return CELL_OK; -} - -int sys_event_flag_destroy(u32 eflag_id) -{ - sys_event.Warning("sys_event_flag_destroy(eflag_id=0x%x)", eflag_id); - - if(!sys_event.CheckId(eflag_id)) return CELL_ESRCH; - - Emu.GetIdManager().RemoveID(eflag_id); - - return CELL_OK; -} - -int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, u32 result_addr, u32 timeout) -{ - sys_event.Warning("Unimplemented function: sys_event_flag_wait(eflag_id=0x%x, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=0x%x)" - , eflag_id, bitptn, mode, result_addr, timeout); - return CELL_OK; -} - -int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, u32 result_addr) -{ - sys_event.Warning("Unimplemented function: sys_event_flag_trywait(eflag_id=0x%x, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)" - , eflag_id, bitptn, mode, result_addr); - return CELL_OK; -} - -int sys_event_flag_set(u32 eflag_id, u64 bitptn) -{ - sys_event.Warning("sys_event_flag_set(eflag_id=0x%x, bitptn=0x%llx)", eflag_id, bitptn); - - event_flag* event_flag_data = nullptr; - if(!sys_event.CheckId(eflag_id, event_flag_data)) return CELL_ESRCH; - - event_flag_data->pattern |= bitptn; - - return CELL_OK; -} - -int sys_event_flag_clear(u32 eflag_id, u64 bitptn) -{ - sys_event.Warning("sys_event_flag_clear(eflag_id=0x%x, bitptn=0x%llx)", eflag_id, bitptn); - - event_flag* event_flag_data = nullptr; - if(!sys_event.CheckId(eflag_id, event_flag_data)) return CELL_ESRCH; - - event_flag_data->pattern &= bitptn; - - return CELL_OK; -} - -int sys_event_flag_cancel(u32 eflag_id, u32 num_addr) -{ - sys_event.Warning("Unimplemented function: sys_event_flag_cancel(eflag_id=0x%x, num_addr=0x%x)" - , eflag_id, num_addr); - return CELL_OK; -} - -int sys_event_flag_get(u32 eflag_id, u32 flag_addr) -{ - sys_event.Warning("sys_event_flag_get(eflag_id=0x%x, flag_addr=0x%x)", eflag_id, flag_addr); - - if(!Memory.IsGoodAddr(flag_addr, 4)) - { - return CELL_EFAULT; - } - - event_flag* event_flag_data = nullptr; - if(!sys_event.CheckId(eflag_id, event_flag_data)) return CELL_ESRCH; - - Memory.Write64(flag_addr, event_flag_data->pattern); - - return CELL_OK; -} - //128 -int sys_event_queue_create(u32 equeue_id_addr, u32 attr_addr, u64 event_queue_key, int size) +int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t 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); + equeue_id.GetAddr(), attr.GetAddr(), event_queue_key, size); if(size <= 0 || size > 127) { return CELL_EINVAL; } - if(!Memory.IsGoodAddr(equeue_id_addr, 4) || !Memory.IsGoodAddr(attr_addr, sizeof(sys_event_queue_attr))) + if(!equeue_id.IsGood() || !attr.IsGood()) { return CELL_EFAULT; } - auto& attr = (sys_event_queue_attr&)Memory[attr_addr]; - sys_event.Warning("name = %s", attr.name); - sys_event.Warning("type = %d", re(attr.type)); - EventQueue* equeue = new EventQueue(); - equeue->size = size; - equeue->pos = 0; - equeue->type = re(attr.type); - strncpy(equeue->name, attr.name, 8); - Memory.Write32(equeue_id_addr, sys_event.GetNewId(equeue)); + equeue_id = sys_event.GetNewId(new EventQueue((u32)attr->protocol, (int)attr->type, attr->name_u64, event_queue_key, size)); + sys_event.Warning("*** event_queue created[%s] (protocol=0x%x, type=0x%x): id = %d", + attr->name, (u32)attr->protocol, (int)attr->type, equeue_id.GetValue()); return CELL_OK; } @@ -176,10 +73,10 @@ int sys_event_queue_receive(u32 equeue_id, u32 event_addr, u32 timeout) { auto dst = (sys_event_data&)Memory[event_addr]; - re(dst.source, equeue->ports[i]->name); - re(dst.data1, equeue->ports[i]->data1); - re(dst.data2, equeue->ports[i]->data2); - re(dst.data3, equeue->ports[i]->data3); + dst.source = equeue->ports[i]->name; + dst.data1 = equeue->ports[i]->data1; + dst.data2 = equeue->ports[i]->data2; + dst.data3 = equeue->ports[i]->data3; equeue->ports[i]->has_data = false; @@ -264,5 +161,12 @@ int sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3) eport->data2 = data2; eport->data3 = data3; + return CELL_OK; +} + +int sys_event_queue_drain(u32 event_queue_id) +{ + sys_event.Error("sys_event_queue_drain(event_queue_id=0x%x)", event_queue_id); + return CELL_OK; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp new file mode 100644 index 0000000000..607d21aae2 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp @@ -0,0 +1,115 @@ +#include "stdafx.h" +#include "Emu/SysCalls/SysCalls.h" +#include "Emu/SysCalls/lv2/SC_Event_flag.h" + +SysCallBase sys_event_flag("sys_event_flag"); + +int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t 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): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; + case se32(SYS_SYNC_RETRY): break; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; + case se32(SYS_SYNC_FIFO): sys_event_flag.Warning("TODO: SYS_SYNC_FIFO attr"); break; + default: return CELL_EINVAL; + } + + if (attr->pshared.ToBE() != se32(0x200)) + { + return CELL_EINVAL; + } + + switch (attr->type.ToBE()) + { + case se32(SYS_SYNC_WAITER_SINGLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_SINGLE type"); break; + case se32(SYS_SYNC_WAITER_MULTIPLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_MULTIPLE type"); break; + default: return CELL_EINVAL; + } + + eflag_id = sys_event_flag.GetNewId(new event_flag(init, (u32)attr->protocol, (int)attr->type)); + + sys_event_flag.Warning("*** event_flag created[%s] (protocol=%d, type=%d): id = %d", attr->name, (u32)attr->protocol, (int)attr->type, eflag_id.GetValue()); + + return CELL_OK; +} + +int sys_event_flag_destroy(u32 eflag_id) +{ + sys_event_flag.Warning("sys_event_flag_destroy(eflag_id=0x%x)", eflag_id); + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + Emu.GetIdManager().RemoveID(eflag_id); + + return CELL_OK; +} + +int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u32 timeout) +{ + sys_event_flag.Error("sys_event_flag_wait(eflag_id=0x%x, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=0x%x)", + eflag_id, bitptn, mode, result.GetAddr(), timeout); + return CELL_OK; +} + +int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result) +{ + sys_event_flag.Error("sys_event_flag_trywait(eflag_id=0x%x, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)", + eflag_id, bitptn, mode, result.GetAddr()); + return CELL_OK; +} + +int sys_event_flag_set(u32 eflag_id, u64 bitptn) +{ + sys_event_flag.Warning("sys_event_flag_set(eflag_id=0x%x, bitptn=0x%llx)", eflag_id, bitptn); + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + ef->flags |= bitptn; + + return CELL_OK; +} + +int sys_event_flag_clear(u32 eflag_id, u64 bitptn) +{ + sys_event_flag.Warning("sys_event_flag_clear(eflag_id=0x%x, bitptn=0x%llx)", eflag_id, bitptn); + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + ef->flags &= bitptn; + + return CELL_OK; +} + +int sys_event_flag_cancel(u32 eflag_id, mem32_t num) +{ + sys_event_flag.Error("sys_event_flag_cancel(eflag_id=0x%x, num_addr=0x%x)", eflag_id, num.GetAddr()); + return CELL_OK; +} + +int sys_event_flag_get(u32 eflag_id, mem64_t flags) +{ + sys_event_flag.Warning("sys_event_flag_get(eflag_id=0x%x, flags_addr=0x%x)", eflag_id, flags.GetAddr()); + + if (!flags.IsGood()) + { + return CELL_EFAULT; + } + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + flags = ef->flags; + + return CELL_OK; +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h new file mode 100644 index 0000000000..80983e6a6d --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h @@ -0,0 +1,31 @@ +#pragma once + +enum +{ + SYS_SYNC_WAITER_SINGLE = 0x10000, + SYS_SYNC_WAITER_MULTIPLE = 0x20000, +}; + +struct sys_event_flag_attr +{ + be_t protocol; + be_t pshared; + be_t ipc_key; + be_t flags; + be_t type; + char name[8]; +}; + +struct event_flag +{ + std::atomic flags; + const u32 m_protocol; + const int m_type; + + event_flag(u64 pattern, u32 protocol, int type) + : flags(pattern) + , m_protocol(protocol) + , m_type(type) + { + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp index 707651a5e8..cd29d5e144 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp @@ -7,7 +7,7 @@ extern gcmInfo gcm_info; int cellGcmCallback(u32 context_addr, u32 count) { - GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); + GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); // could stall on exit CellGcmContextData& ctx = (CellGcmContextData&)Memory[context_addr]; CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp index ff80ed4700..eff04fb5cc 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp @@ -18,9 +18,12 @@ struct HeapInfo }; int sys_heap_create_heap(const u32 heap_addr, const u32 align, const u32 size) -{ +{ sc_heap.Warning("sys_heap_create_heap(heap_addr=0x%x, align=0x%x, size=0x%x)", heap_addr, align, size); - return sc_heap.GetNewId(new HeapInfo(heap_addr, align, size)); + + u32 heap_id = sc_heap.GetNewId(new HeapInfo(heap_addr, align, size)); + sc_heap.Warning("*** sys_heap created(): id=0x%x", heap_id); + return heap_id; } int sys_heap_malloc(const u32 heap_id, const u32 size) @@ -30,5 +33,15 @@ int sys_heap_malloc(const u32 heap_id, const u32 size) HeapInfo* heap; if(!sc_heap.CheckId(heap_id, heap)) return CELL_ESRCH; - return Memory.Alloc(size, heap->align); + return Memory.Alloc(size, 1); +} + +int _sys_heap_memalign(u32 heap_id, u32 align, u32 size, u64 p4) +{ + sc_heap.Warning("_sys_heap_memalign(heap_id=0x%x, align=0x%x, size=0x%x, p4=0x%llx, ... ???)", heap_id, align, size, p4); + + HeapInfo* heap; + if(!sc_heap.CheckId(heap_id, heap)) return CELL_ESRCH; + + return Memory.Alloc(size, align); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp index 2c2cb84322..33da310eea 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp @@ -7,25 +7,16 @@ SysCallBase sys_lwcond("sys_lwcond"); int sys_lwcond_create(mem_ptr_t lwcond, mem_ptr_t lwmutex, mem_ptr_t attr) { - sys_lwcond.Warning("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", + 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; - u32 protocol = (u32)lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK; - switch (protocol) - { - case SYS_SYNC_PRIORITY: break; - case SYS_SYNC_RETRY: sys_lwcond.Error("Invalid SYS_SYNC_RETRY attr"); break; - case SYS_SYNC_PRIORITY_INHERIT: sys_lwcond.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case SYS_SYNC_FIFO: break; - default: sys_lwcond.Error("Invalid lwmutex protocol(%d)", protocol); break; - } + lwcond->lwmutex = lwmutex.GetAddr(); + lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(attr->name_u64)); - lwcond->lwmutex_addr = lwmutex.GetAddr(); - lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(protocol, *(u64*)&attr->name)); - - sys_lwcond.Warning("*** lwcond created [%s] (protocol=0x%x): id=%d", attr->name, protocol, (u32)lwcond->lwcond_queue); + sys_lwcond.Warning("*** lwcond created [%s] (attr=0x%x, lwmutex.sq=0x%x): id=0x%x", + attr->name, (u32)lwmutex->attribute, (u32)lwmutex->sleep_queue, (u32)lwcond->lwcond_queue); return CELL_OK; } @@ -44,21 +35,21 @@ int sys_lwcond_destroy(mem_ptr_t lwcond) int sys_lwcond_signal(mem_ptr_t lwcond) { - sys_lwcond.Warning("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); + sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); if (!lwcond.IsGood()) return CELL_EFAULT; LWCond* lwc; u32 id = (u32)lwcond->lwcond_queue; if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; - lwc->signal(); + lwc->signal(mem_ptr_t(lwcond->lwmutex)->attribute); return CELL_OK; } int sys_lwcond_signal_all(mem_ptr_t lwcond) { - sys_lwcond.Warning("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr()); + sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr()); if (!lwcond.IsGood()) return CELL_EFAULT; LWCond* lwc; @@ -72,7 +63,7 @@ int sys_lwcond_signal_all(mem_ptr_t lwcond) int sys_lwcond_signal_to(mem_ptr_t lwcond, u32 ppu_thread_id) { - sys_lwcond.Warning("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id); + sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id); if (!lwcond.IsGood()) return CELL_EFAULT; LWCond* lwc; @@ -86,16 +77,17 @@ int sys_lwcond_signal_to(mem_ptr_t lwcond, u32 ppu_thread_id) int sys_lwcond_wait(mem_ptr_t lwcond, u64 timeout) { - sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%llu)", lwcond.GetAddr(), timeout); + sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%llu)", lwcond.GetAddr(), timeout); if (!lwcond.IsGood()) return CELL_EFAULT; LWCond* lwc; u32 id = (u32)lwcond->lwcond_queue; if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; const u32 tid = GetCurrentPPUThread().GetId(); - mem_ptr_t lwmutex((u32)lwcond->lwmutex_addr); - if ((u32)lwmutex->owner != tid) return CELL_EPERM; // caller must own this lwmutex + mem_ptr_t lwmutex(lwcond->lwmutex); + + if ((u32)lwmutex->owner.GetOwner() != tid) return CELL_EPERM; // caller must own this lwmutex lwc->begin_waiting(tid); u32 counter = 0; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h index c72347e3b3..037f47f67b 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h @@ -2,12 +2,16 @@ struct sys_lwcond_attribute_t { - char name[8]; + union + { + char name[8]; + u64 name_u64; + }; }; struct sys_lwcond_t { - be_t lwmutex_addr; + be_t lwmutex; be_t lwcond_queue; }; @@ -18,22 +22,20 @@ struct LWCond std::mutex m_lock; Array waiters; // list of waiting threads Array signaled; // list of signaled threads - u32 m_protocol; // protocol u64 m_name; // not used - LWCond(u32 prot, u64 name) + LWCond(u64 name) : m_name(name) - , m_protocol(prot) { } - void signal() + void signal(u32 _protocol) { std::lock_guard lock(m_lock); if (waiters.GetCount()) { - if (m_protocol == SYS_SYNC_PRIORITY) + if ((_protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_PRIORITY) { u64 max_prio = 0; u32 sel = 0; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index 77a4e93d99..386e99f5f9 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -5,125 +5,87 @@ SysCallBase sc_lwmutex("sys_lwmutex"); -std::mutex g_lwmutex; - int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_t attr) { - sc_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)", + sc_lwmutex.Log("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)", lwmutex.GetAddr(), attr.GetAddr()); if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT; - switch ((u32)attr->attr_recursive) + switch (attr->attr_recursive.ToBE()) { - case SYS_SYNC_RECURSIVE: break; - case SYS_SYNC_NOT_RECURSIVE: break; - default: return CELL_EINVAL; + case se32(SYS_SYNC_RECURSIVE): break; + case se32(SYS_SYNC_NOT_RECURSIVE): break; + default: sc_lwmutex.Error("Unknown 0x%x recursive attr", (u32)attr->attr_recursive); return CELL_EINVAL; } - switch ((u32)attr->attr_protocol) + switch (attr->attr_protocol.ToBE()) { - case SYS_SYNC_PRIORITY: sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; - case SYS_SYNC_RETRY: sc_lwmutex.Warning("TODO: SYS_SYNC_RETRY attr"); break; - case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case SYS_SYNC_FIFO: sc_lwmutex.Warning("TODO: SYS_SYNC_FIFO attr"); break; - default: return CELL_EINVAL; + case se32(SYS_SYNC_PRIORITY): break; + case se32(SYS_SYNC_RETRY): break; + case se32(SYS_SYNC_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; + case se32(SYS_SYNC_FIFO): break; + default: sc_lwmutex.Error("Unknown 0x%x protocol attr", (u32)attr->attr_protocol); return CELL_EINVAL; } - lwmutex->attribute = (u32)attr->attr_protocol | (u32)attr->attr_recursive; + lwmutex->attribute = attr->attr_protocol | attr->attr_recursive; lwmutex->all_info = 0; lwmutex->pad = 0; lwmutex->recursive_count = 0; - lwmutex->sleep_queue = 0; - sc_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): id=???", attr->name, (u32)lwmutex->attribute); + u32 sq_id = sc_lwmutex.GetNewId(new SleepQueue(attr->name_u64)); + lwmutex->sleep_queue = sq_id; + + sc_lwmutex.Log("*** lwmutex created [%s] (attribute=0x%x): sleep_queue=0x%x", + attr->name, (u32)lwmutex->attribute, sq_id); return CELL_OK; } int sys_lwmutex_destroy(mem_ptr_t lwmutex) { - sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); + sc_lwmutex.Log("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); if (!lwmutex.IsGood()) return CELL_EFAULT; - if (!lwmutex->attribute) return CELL_EINVAL; + u32 sq_id = lwmutex->sleep_queue; + if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH; - { // global lock - std::lock_guard lock(g_lwmutex); - - if (!lwmutex->owner) - { - lwmutex->owner = ~0; // make it unable to lock - lwmutex->attribute = 0; - } - else - { - return CELL_EBUSY; - } + // try to make it unable to lock + switch (int res = lwmutex->trylock(~0)) + { + case CELL_OK: + lwmutex->attribute = 0; + lwmutex->sleep_queue = 0; + Emu.GetIdManager().RemoveID(sq_id); + default: return res; } - - return CELL_OK; } int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) { - sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout); + sc_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout); if (!lwmutex.IsGood()) return CELL_EFAULT; - if (!lwmutex->attribute) return CELL_EINVAL; - - const u32 tid = GetCurrentPPUThread().GetId(); - - int res = lwmutex->trylock(tid); - if (res != CELL_EBUSY) return res; - - u32 counter = 0; - const u32 max_counter = timeout ? (timeout / 1000) : 20000; - do // waiting - { - if (Emu.IsStopped()) return CELL_ETIMEDOUT; - Sleep(1); - - res = lwmutex->trylock(tid); - if (res != CELL_EBUSY) return res; - if (!lwmutex->attribute) return CELL_EINVAL; - - if (counter++ > max_counter) - { - if (!timeout) - { - sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr()); - counter = 0; - } - else - { - return CELL_ETIMEDOUT; - } - } - } while (true); + return lwmutex->lock(GetCurrentPPUThread().GetId(), timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0); } int sys_lwmutex_trylock(mem_ptr_t lwmutex) { - sc_lwmutex.Warning("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr()); + sc_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr()); if (!lwmutex.IsGood()) return CELL_EFAULT; - if (!lwmutex->attribute) return CELL_EINVAL; - return lwmutex->trylock(GetCurrentPPUThread().GetId()); } int sys_lwmutex_unlock(mem_ptr_t lwmutex) { - sc_lwmutex.Warning("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr()); + sc_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr()); if (!lwmutex.IsGood()) return CELL_EFAULT; - if (!lwmutex->unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM; - - return CELL_OK; + return lwmutex->unlock(GetCurrentPPUThread().GetId()); } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h index 1072d7eca5..7275724b08 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h @@ -1,4 +1,5 @@ #pragma once +#include // attr_protocol (waiting scheduling policy) enum @@ -9,7 +10,7 @@ enum SYS_SYNC_PRIORITY = 2, // Basic Priority Inheritance Protocol SYS_SYNC_PRIORITY_INHERIT = 3, - // ???? + // Not selected while unlocking SYS_SYNC_RETRY = 4, // SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, @@ -30,10 +31,104 @@ struct sys_lwmutex_attribute_t { be_t attr_protocol; be_t attr_recursive; - char name[8]; + union + { + char name[8]; + u64 name_u64; + }; }; -extern std::mutex g_lwmutex; +class SleepQueue +{ + /* struct q_rec + { + u32 tid; + u64 prio; + q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {} + }; */ + + SMutex m_mutex; + Array list; + u64 m_name; + +public: + SleepQueue(u64 name) + : m_name(name) + { + } + + void push(u32 tid) + { + SMutexLocker lock(m_mutex); + list.AddCpy(tid); + } + + u32 pop() // SYS_SYNC_FIFO + { + SMutexLocker lock(m_mutex); + + while (true) + { + if (list.GetCount()) + { + u32 res = list[0]; + list.RemoveAt(0); + if (Emu.GetIdManager().CheckID(res)) + // check thread + { + return res; + } + } + return 0; + }; + } + + u32 pop_prio() // SYS_SYNC_PRIORITY + { + SMutexLocker lock(m_mutex); + + while (true) + { + if (list.GetCount()) + { + u64 max_prio = 0; + u32 sel = 0; + for (u32 i = 0; i < list.GetCount(); i++) + { + CPUThread* t = Emu.GetCPU().GetThread(list[i]); + if (!t) + { + list[i] = 0; + sel = i; + break; + } + + u64 prio = t->GetPrio(); + if (prio > max_prio) + { + max_prio = prio; + sel = i; + } + } + u32 res = list[sel]; + list.RemoveAt(sel); + /* if (Emu.GetIdManager().CheckID(res)) */ + if (res) + // check thread + { + return res; + } + } + return 0; + } + } + + u32 pop_prio_inherit() // (TODO) + { + ConLog.Error("TODO: SleepQueue::pop_prio_inherit()"); + Emu.Pause(); + } +}; struct sys_lwmutex_t { @@ -41,8 +136,8 @@ struct sys_lwmutex_t { struct // sys_lwmutex_lock_info_t { - /* volatile */ be_t owner; - /* volatile */ be_t waiter; + /* volatile */ SMutexBE owner; + /* volatile */ be_t waiter; // not used }; struct { @@ -54,77 +149,103 @@ struct sys_lwmutex_t be_t sleep_queue; be_t pad; - int trylock(u32 tid) + int trylock(be_t tid) { - std::lock_guard lock(g_lwmutex); // global lock + if (!attribute.ToBE()) return CELL_EINVAL; - if ((u32)attribute & SYS_SYNC_RECURSIVE) + if (tid == owner.GetOwner()) { - if (tid == (u32)owner) + if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) { - recursive_count = (u32)recursive_count + 1; - if ((u32)recursive_count == 0xffffffff) return CELL_EKRESOURCE; + recursive_count += 1; + if (!recursive_count.ToBE()) return CELL_EKRESOURCE; return CELL_OK; } - } - else // recursive not allowed - { - if (tid == (u32)owner) + else { return CELL_EDEADLK; } } - if (!(u32)owner) // try lock + switch (owner.trylock(tid)) { - owner = tid; - recursive_count = 1; - return CELL_OK; - } - else - { - return CELL_EBUSY; + case SMR_OK: recursive_count = 1; return CELL_OK; + case SMR_FAILED: return CELL_EBUSY; + default: return CELL_EINVAL; } } - bool unlock(u32 tid) + int unlock(be_t tid) { - std::lock_guard lock(g_lwmutex); // global lock - - if (tid != (u32)owner) + if (tid != owner.GetOwner()) { - return false; + return CELL_EPERM; } else { - recursive_count = (u32)recursive_count - 1; - if (!(u32)recursive_count) + recursive_count -= 1; + if (!recursive_count.ToBE()) { - waiter = 0; // not used yet - owner = 0; // release + be_t 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): default: owner.unlock(tid, target); break; + } } - return true; + return CELL_OK; + } + } + + int lock(be_t tid, u64 timeout) + { + switch (int res = trylock(tid)) + { + case CELL_EBUSY: break; + default: return res; + } + + switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) + { + case se32(SYS_SYNC_PRIORITY): + case se32(SYS_SYNC_FIFO): + SleepQueue* sq; + if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; + sq->push(tid); + default: break; + } + + switch (owner.lock(tid, timeout)) + { + case SMR_OK: case SMR_SIGNAL: recursive_count = 1; return CELL_OK; + case SMR_TIMEOUT: return CELL_ETIMEDOUT; + default: return CELL_EINVAL; } } }; -struct lwmutex_locker +class lwmutex_locker { -private: mem_ptr_t m_mutex; - u32 m_id; -public: - const int res; + be_t m_id; - lwmutex_locker(u32 lwmutex_addr, u32 tid) + lwmutex_locker(mem_ptr_t lwmutex, be_t tid, u64 timeout = 0) : m_id(tid) - , m_mutex(lwmutex_addr) - , res(m_mutex->trylock(m_id)) + , m_mutex(lwmutex) { + if (int res = m_mutex->lock(m_id, timeout)) + { + ConLog.Error("lwmutex_locker: m_mutex->lock failed(res=0x%x)", res); + Emu.Pause(); + } } ~lwmutex_locker() { - if (res == CELL_OK) m_mutex->unlock(m_id); + m_mutex->unlock(m_id); } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp index 86f24d65dd..526e1d56ab 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp @@ -6,7 +6,7 @@ SysCallBase sc_mem("memory"); int sys_memory_container_create(u32 cid_addr, u32 yield_size) { - sc_mem.Warning("(HACK!) sys_memory_container_create(cid_addr=0x%x,yield_size=0x%x)", cid_addr, yield_size); + sc_mem.Warning("sys_memory_container_create(cid_addr=0x%x,yield_size=0x%x)", cid_addr, yield_size); if(!Memory.IsGoodAddr(cid_addr, 4)) { @@ -15,17 +15,13 @@ int sys_memory_container_create(u32 cid_addr, u32 yield_size) yield_size &= ~0xfffff; //round down to 1 MB granularity - //alignment hack (Memory.Alloc does not support alignment yet): alloc size is increased - u64 addr = Memory.Alloc(yield_size + 0x100000, 0x100000); //1 MB alignment (???) + u64 addr = Memory.Alloc(yield_size, 0x100000); //1 MB alignment if(!addr) { return CELL_ENOMEM; } - //fix alignment: - addr = (addr + 0x100000) & ~0xfffff; - Memory.Write32(cid_addr, sc_mem.GetNewId(new MemoryContainerInfo(addr, yield_size))); return CELL_OK; } @@ -49,20 +45,18 @@ int sys_memory_container_destroy(u32 cid) int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr) { //0x30000100; - sc_mem.Warning("(HACK!) sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags); + sc_mem.Log("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags); u32 addr; switch(flags) { case SYS_MEMORY_PAGE_SIZE_1M: if(size & 0xfffff) return CELL_EALIGN; - addr = Memory.Alloc(size + 0x100000, 0x100000); - addr = (addr + 0x100000) & ~0xfffff; + addr = Memory.Alloc(size, 1); break; case SYS_MEMORY_PAGE_SIZE_64K: if(size & 0xffff) return CELL_EALIGN; - addr = Memory.Alloc(size + 0x10000, 0x10000); - addr = (addr + 0x10000) & ~0xffff; + addr = Memory.Alloc(size, 1); break; default: return CELL_EINVAL; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp index b700ec7ae3..2bd289413a 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp @@ -1,12 +1,13 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "SC_Mutex.h" +#include "Utilities/SMutex.h" SysCallBase sys_mtx("sys_mutex"); int sys_mutex_create(u32 mutex_id_addr, u32 attr_addr) { - sys_mtx.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", + sys_mtx.Warning("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id_addr, attr_addr); if(!Memory.IsGoodAddr(mutex_id_addr) || !Memory.IsGoodAddr(attr_addr)) return CELL_EFAULT; @@ -48,9 +49,28 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout) mutex* mtx_data = nullptr; if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH; - mtx_data->mtx.Lock(); + u32 counter = 0; + const u32 max_counter = timeout ? (timeout / 1000) : 20000; + do + { + if (Emu.IsStopped()) return CELL_ETIMEDOUT; - return CELL_OK; + if (mtx_data->mtx.TryLock() == wxMUTEX_NO_ERROR) return CELL_OK; + Sleep(1); + + if (counter++ > max_counter) + { + if (!timeout) + { + sys_mtx.Warning("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx): TIMEOUT", mutex_id, timeout); + counter = 0; + } + else + { + return CELL_ETIMEDOUT; + } + } + } while (true); } int sys_mutex_trylock(u32 mutex_id) @@ -60,7 +80,7 @@ int sys_mutex_trylock(u32 mutex_id) mutex* mtx_data = nullptr; if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH; - if(mtx_data->mtx.TryLock()) return 1; + if (mtx_data->mtx.TryLock() != wxMUTEX_NO_ERROR) return CELL_EBUSY; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp index 9e8d8f8f70..9ab7bee427 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp @@ -131,7 +131,7 @@ int sys_ppu_thread_restart(u32 thread_id) return CELL_OK; } -int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u32 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr) +int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr) { sysPrxForUser.Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%x, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x('%s'))", thread_id_addr, entry, arg, prio, stacksize, flags, threadname_addr, Memory.ReadString(threadname_addr).mb_str()); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Process.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Process.cpp index 0fd91cbe8e..7e4ddd320c 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Process.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Process.cpp @@ -40,11 +40,8 @@ int sys_process_getppid() int sys_process_exit(int errorcode) { sc_p.Warning("sys_process_exit(%d)", errorcode); -#ifdef _DEBUG - Emu.Pause(); -#else - Emu.Stop(); -#endif + Emu.Pause(); // Emu.Stop() does crash + ConLog.Success("Process finished"); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp index d4f6ecae7a..d07ab05677 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp @@ -10,23 +10,22 @@ int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t attr if (!rw_lock_id.IsGood() || !attr.IsGood()) return CELL_EFAULT; - switch ((u32)attr->attr_protocol) + switch (attr->attr_protocol.ToBE()) { - case SYS_SYNC_PRIORITY: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; - case SYS_SYNC_RETRY: sys_rwlock.Error("Invalid SYS_SYNC_RETRY attr"); break; - case SYS_SYNC_PRIORITY_INHERIT: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case SYS_SYNC_FIFO: break; + case se32(SYS_SYNC_PRIORITY): sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; + case se32(SYS_SYNC_RETRY): sys_rwlock.Error("Invalid SYS_SYNC_RETRY attr"); break; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; + case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } - if ((u32)attr->attr_pshared != 0x200) + 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, (u32)attr->attr_pshared, - (u64)attr->key, (s32)attr->flags, *(u64*)&attr->name)); + 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", attr->name, (u32)attr->attr_protocol, rw_lock_id.GetValue()); @@ -52,7 +51,7 @@ int sys_rwlock_destroy(u32 rw_lock_id) int sys_rwlock_rlock(u32 rw_lock_id, u64 timeout) { - sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); + sys_rwlock.Log("sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; @@ -86,7 +85,7 @@ int sys_rwlock_rlock(u32 rw_lock_id, u64 timeout) int sys_rwlock_tryrlock(u32 rw_lock_id) { - sys_rwlock.Warning("sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Log("sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; @@ -98,7 +97,7 @@ int sys_rwlock_tryrlock(u32 rw_lock_id) int sys_rwlock_runlock(u32 rw_lock_id) { - sys_rwlock.Warning("sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Log("sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; @@ -110,7 +109,7 @@ int sys_rwlock_runlock(u32 rw_lock_id) int sys_rwlock_wlock(u32 rw_lock_id, u64 timeout) { - sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); + sys_rwlock.Log("sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; @@ -146,7 +145,7 @@ int sys_rwlock_wlock(u32 rw_lock_id, u64 timeout) int sys_rwlock_trywlock(u32 rw_lock_id) { - sys_rwlock.Warning("sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Log("sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; @@ -161,7 +160,7 @@ int sys_rwlock_trywlock(u32 rw_lock_id) int sys_rwlock_wunlock(u32 rw_lock_id) { - sys_rwlock.Warning("sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Log("sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id); RWLock* rw; if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h index 720f137db7..dc9c563b6d 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h @@ -6,8 +6,12 @@ struct sys_rwlock_attribute_t be_t attr_pshared; // == 0x200 (NOT SHARED) be_t key; // process-shared key (not used) be_t flags; // process-shared flags (not used) - be_t pad; - char name[8]; + be_t pad; // not used + union + { + char name[8]; + u64 name_u64; + }; }; #pragma pack() @@ -20,21 +24,15 @@ struct RWLock Array rlock_list; // read lock list u32 m_protocol; // TODO - u32 m_pshared; // not used - u64 m_key; // not used - s32 m_flags; // not used union { - u64 m_name_data; // not used + u64 m_name_u64; char m_name[8]; }; - RWLock(u32 protocol, u32 pshared, u64 key, s32 flags, u64 name) + RWLock(u32 protocol, u64 name) : m_protocol(protocol) - , m_pshared(pshared) - , m_key(key) - , m_flags(flags) - , m_name_data(name) + , m_name_u64(name) , wlock_thread(0) { } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index c45680cb8c..d816cffbe9 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -40,7 +40,7 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) ELFLoader l(stream); l.LoadInfo(); const u32 alloc_size = 256 * 1024 /*0x1000000 - stream.GetSize()*/; - u32 spu_offset = Memory.MainMem.Alloc(alloc_size); + u32 spu_offset = Memory.MainMem.AllocAlign(alloc_size); l.LoadData(spu_offset); spu_ep = l.GetEntry(); return spu_offset; @@ -104,7 +104,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< return CELL_ESRCH; } - if(!thread.IsGood() || !img.IsGood() || !attr.IsGood() || !attr.IsGood()) + if(!thread.IsGood() || !img.IsGood() || !attr.IsGood() || !arg.IsGood()) { return CELL_EFAULT; } @@ -133,7 +133,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU); //copy SPU image: - u32 spu_offset = Memory.MainMem.Alloc(256 * 1024); + u32 spu_offset = Memory.MainMem.AllocAlign(256 * 1024); memcpy(Memory + spu_offset, Memory + (u32)img->segs_addr, 256 * 1024); //initialize from new place: new_thread.SetOffset(spu_offset); @@ -177,24 +177,70 @@ int sys_spu_thread_set_argument(u32 id, mem_ptr_t arg) return CELL_OK; } -//173 -int sys_spu_thread_group_start(u32 id) +//165 +int sys_spu_thread_get_exit_status(u32 id, mem32_t status) { - sc_spu.Warning("sys_spu_thread_group_start(id=0x%x)", id); + sc_spu.Warning("sys_spu_thread_get_exit_status(id=0x%x, status_addr=0x%x)", id, status.GetAddr()); - if(!Emu.GetIdManager().CheckID(id)) + if (!status.IsGood()) + { + return CELL_EFAULT; + } + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } + u32 res; + if (!(*(SPUThread*)thr).SPU.Out_MBox.Pop(res) || !thr->IsStopped()) + { + return CELL_ESTAT; + } + + status = res; + return CELL_OK; +} + +//171 +int sys_spu_thread_group_destroy(u32 id) +{ + sc_spu.Warning("sys_spu_thread_group_destroy(id=0x%x)", id); + SpuGroupInfo* group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; } - //Emu.Pause(); - for (int i = 0; i < group_info->list.GetCount(); i++) + if (group_info->lock) // ??? + { + return CELL_EBUSY; + } + + for (u32 i = 0; i < group_info->list.GetCount(); i++) + { + Emu.GetCPU().RemoveThread(group_info->list[i]); + } + + Emu.GetIdManager().RemoveID(id); + return CELL_OK; +} + +//173 +int sys_spu_thread_group_start(u32 id) +{ + sc_spu.Warning("sys_spu_thread_group_start(id=0x%x)", id); + + SpuGroupInfo* group_info; + if(!Emu.GetIdManager().GetIDData(id, group_info)) + { + return CELL_ESRCH; + } + + for (u32 i = 0; i < group_info->list.GetCount(); i++) { CPUThread* t; if (t = Emu.GetCPU().GetThread(group_info->list[i])) @@ -218,10 +264,9 @@ int sys_spu_thread_group_suspend(u32 id) } //Emu.Pause(); - for (int i = 0; i < group_info->list.GetCount(); i++) + for (u32 i = 0; i < group_info->list.GetCount(); i++) { - CPUThread* t; - if (t = Emu.GetCPU().GetThread(group_info->list[i])) + if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { t->Pause(); } @@ -273,14 +318,17 @@ int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; status = 0; //unspecified because of ALL_THREADS_EXIT - for (int i = 0; i < group_info->list.GetCount(); i++) + for (u32 i = 0; i < group_info->list.GetCount(); i++) { - while (Emu.GetCPU().GetThread(group_info->list[i])) + while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { - Sleep(1); + if (!t->IsRunning()) + { + break; + } if (Emu.IsStopped()) return CELL_OK; + Sleep(1); } - group_info->list[i] = 0; } group_info->lock = 0; // release lock @@ -514,7 +562,7 @@ int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 return CELL_ESRCH; } - for(int i=0; ilist.GetCount(); ++i) + for(u32 i=0; ilist.GetCount(); ++i) { CPUThread* t; if(t = Emu.GetCPU().GetThread(group->list[i])) @@ -537,3 +585,10 @@ int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 } return CELL_OK; } + +int sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num) +{ + sc_spu.Error("sys_spu_thread_bind_queue(id=0x%x, spuq=0x%x, spuq_num=0x%x)", id, spuq, spuq_num); + + return CELL_OK; +} diff --git a/rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp b/rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp index 52f6ec1573..f19531243d 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp @@ -11,7 +11,7 @@ int sys_tty_read(u32 ch, u64 buf_addr, u32 len, u64 preadlen_addr) int sys_tty_write(u32 ch, u64 buf_addr, u32 len, u64 pwritelen_addr) { - if(ch < 0 || ch > 15 || len <= 0) return CELL_EINVAL; + if(ch < 0 || ch > 15 || (s32)len <= 0) return CELL_EINVAL; if(!Memory.IsGoodAddr(buf_addr)) return CELL_EFAULT; Emu.GetDbgCon().Write(ch, Memory.ReadString(buf_addr, len)); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_VM.cpp b/rpcs3/Emu/SysCalls/lv2/SC_VM.cpp index 307dcaf75c..827c6214f2 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_VM.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_VM.cpp @@ -108,7 +108,7 @@ int sys_vm_return_memory(u32 addr, u32 size) } // The memory size to return should not be superior to the virtual size in use minus 1MB. - if((current_ct->size - size - 0x100000) < 0) + if(current_ct->size < (size + 0x100000)) { return CELL_EBUSY; } @@ -130,7 +130,7 @@ int sys_vm_lock(u32 addr, u32 size) } // The memory size to return should not be superior to the virtual size to lock minus 1MB. - if((current_ct->size - size - 0x100000) < 0) + if(current_ct->size < (size + 0x100000)) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index dc6301ee77..fb8749efcd 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -305,7 +305,7 @@ void Emulator::Load() ConLog.Write("offset = 0x%llx", Memory.MainMem.GetStartAddr()); ConLog.Write("max addr = 0x%x", l.GetMaxAddr()); thread.SetOffset(Memory.MainMem.GetStartAddr()); - Memory.MainMem.Alloc(Memory.MainMem.GetStartAddr() + l.GetMaxAddr(), 0xFFFFED - l.GetMaxAddr()); + Memory.MainMem.AllocFixed(Memory.MainMem.GetStartAddr() + l.GetMaxAddr(), 0xFFFFED - l.GetMaxAddr()); thread.SetEntry(l.GetEntry() - Memory.MainMem.GetStartAddr()); break; @@ -314,12 +314,12 @@ void Emulator::Load() m_ppu_callback_thr = &GetCPU().AddThread(CPU_THREAD_PPU); thread.SetEntry(l.GetEntry()); - Memory.StackMem.Alloc(0x1000); + Memory.StackMem.AllocAlign(0x1000); thread.InitStack(); thread.AddArgv(m_elf_path); //thread.AddArgv("-emu"); - m_rsx_callback = Memory.MainMem.Alloc(4 * 4) + 4; + m_rsx_callback = Memory.MainMem.AllocAlign(4 * 4) + 4; Memory.Write32(m_rsx_callback - 4, m_rsx_callback); mem32_ptr_t callback_data(m_rsx_callback); @@ -327,7 +327,7 @@ void Emulator::Load() callback_data += SC(2); callback_data += BCLR(0x10 | 0x04, 0, 0, 0); - m_ppu_thr_exit = Memory.MainMem.Alloc(4 * 4); + m_ppu_thr_exit = Memory.MainMem.AllocAlign(4 * 4); mem32_ptr_t ppu_thr_exit_data(m_ppu_thr_exit); ppu_thr_exit_data += ADDI(3, 0, 0); diff --git a/rpcs3/Emu/event.h b/rpcs3/Emu/event.h index 8c5d94c360..516ea06ed7 100644 --- a/rpcs3/Emu/event.h +++ b/rpcs3/Emu/event.h @@ -1,61 +1,62 @@ -#pragma once - -struct sys_event_flag_attr -{ - u32 protocol; - u32 pshared; - u64 ipc_key; - int flags; - int type; - char name[8]; -}; - -struct event_flag -{ - sys_event_flag_attr attr; - u64 pattern; - - event_flag(u64 pattern, sys_event_flag_attr attr) - : pattern(pattern) - , attr(attr) - { - } -}; - -struct sys_event_queue_attr -{ - u32 attr_protocol; - int type; - char name[8]; -}; - -struct sys_event_data -{ - u64 source; - u64 data1; - u64 data2; - u64 data3; -}; - -struct EventQueue; - -struct EventPort -{ - u64 name; - u64 data1; - u64 data2; - u64 data3; - bool has_data; - CPUThread* thread; - EventQueue* queue[127]; - int pos; -}; - -struct EventQueue -{ - EventPort* ports[127]; - int size; - int pos; - int type; - char name[8]; +#pragma once + +enum EventQueueType +{ + SYS_PPU_QUEUE = 1, + SYS_SPU_QUEUE = 2, +}; + +struct sys_event_queue_attr +{ + be_t protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO + be_t type; + union + { + char name[8]; + u64 name_u64; + }; +}; + +struct sys_event_data +{ + be_t source; + be_t data1; + be_t data2; + be_t data3; +}; + +struct EventQueue; + +struct EventPort +{ + u64 name; + u64 data1; + u64 data2; + u64 data3; + bool has_data; + CPUThread* thread; + EventQueue* queue[127]; + int pos; +}; + +struct EventQueue +{ + EventPort* ports[127]; + int size; + int pos; + + u32 m_protocol; + int m_type; + u64 m_name; + u64 m_key; + + EventQueue(u32 protocol, int type, u64 name, u64 key, int size) + : m_type(type) + , m_protocol(protocol) + , m_name(name) + , m_key(key) + , size(size) + , pos(0) + { + } }; \ No newline at end of file diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 34e997753b..5db69803d1 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -181,9 +181,9 @@ bool ELF32Loader::LoadPhdrData(u64 _offset) switch(machine) { - case MACHINE_SPU: Memory.MainMem.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; - case MACHINE_MIPS: Memory.PSPMemory.RAM.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; - case MACHINE_ARM: Memory.PSVMemory.RAM.Alloc(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; + case MACHINE_SPU: Memory.MainMem.AllocFixed(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; + case MACHINE_MIPS: Memory.PSPMemory.RAM.AllocFixed(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; + case MACHINE_ARM: Memory.PSVMemory.RAM.AllocFixed(phdr_arr[i].p_vaddr + offset, phdr_arr[i].p_memsz); break; default: continue; diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index d770aa5c91..e8180408ba 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -240,7 +240,7 @@ bool ELF64Loader::LoadPhdrData(u64 offset) case 0x00000001: //LOAD if(phdr_arr[i].p_memsz) { - Memory.MainMem.Alloc(offset + phdr_arr[i].p_vaddr, phdr_arr[i].p_memsz); + Memory.MainMem.AllocFixed(offset + phdr_arr[i].p_vaddr, phdr_arr[i].p_memsz); if(phdr_arr[i].p_filesz) { @@ -358,8 +358,8 @@ bool ELF64Loader::LoadPhdrData(u64 offset) ConLog.Write("*** text: 0x%x", stub.s_text); #endif static const u32 section = 4 * 3; - u64 tbl = Memory.MainMem.Alloc(stub.s_imports * 4 * 2); - u64 dst = Memory.MainMem.Alloc(stub.s_imports * section); + u64 tbl = Memory.MainMem.AllocAlign(stub.s_imports * 4 * 2); + u64 dst = Memory.MainMem.AllocAlign(stub.s_imports * section); for(u32 i=0; i - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath) + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) $(ProjectName)-$(PlatformShortName)-dbg - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath) + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) $(ProjectName)-$(PlatformShortName)-dbg false - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath) + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) false @@ -91,7 +91,7 @@ false - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath) + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) false @@ -205,6 +205,7 @@ NotUsing NotUsing + @@ -247,6 +248,7 @@ + @@ -324,6 +326,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index abbb2365a1..302473ead6 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -379,6 +379,12 @@ Emu\FS + + Utilities + + + Emu\SysCalls\lv2 + @@ -558,5 +564,8 @@ Include + + Utilities + \ No newline at end of file