1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-26 04:32:35 +01:00

Merge pull request #64 from Nekotekina/master

Last changes
This commit is contained in:
Alexandro Sánchez Bach 2014-02-09 14:50:35 +01:00
commit 4ebd974f5e
51 changed files with 1218 additions and 618 deletions

View File

@ -2,6 +2,10 @@
#include "Utilities/GNU.h"
#define se16(x) const_se_t<u16, x>::value
#define se32(x) const_se_t<u32, x>::value
#define se64(x) const_se_t<u64, x>::value
template<typename T, int size = sizeof(T)> struct se_t;
template<typename T> struct se_t<T, 1> { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } };
template<typename T> struct se_t<T, 2> { static __forceinline void func(T& dst, const T src) { (u16&)dst = _byteswap_ushort((u16&)src); } };

26
Utilities/SMutex.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <stdafx.h>
#include <Utilities/SMutex.h>
__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<u32> SM_GetCurrentCPUThreadIdBE()
{
return SM_GetCurrentCPUThreadId();
}

155
Utilities/SMutex.h Normal file
View File

@ -0,0 +1,155 @@
#pragma once
#include <atomic>
extern void SM_Sleep();
extern DWORD SM_GetCurrentThreadId();
extern u32 SM_GetCurrentCPUThreadId();
extern be_t<u32> 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<T> 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<typename T, T (get_tid)()>
class SMutexLockerBase
{
SMutexBase<T>& sm;
public:
const T tid;
SMutexLockerBase(SMutexBase<T>& _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<DWORD>
SMutexGeneral;
typedef SMutexBase<u32>
SMutex;
typedef SMutexBase<be_t<u32>>
SMutexBE;
typedef SMutexLockerBase<DWORD, SM_GetCurrentThreadId>
SMutexGeneralLocker;
typedef SMutexLockerBase<u32, SM_GetCurrentCPUThreadId>
SMutexLocker;
typedef SMutexLockerBase<be_t<u32>, SM_GetCurrentCPUThreadIdBE>
SMutexBELocker;

View File

@ -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

View File

@ -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
{

View File

@ -76,6 +76,8 @@ void CPUThreadManager::RemoveThread(const u32 id)
s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id)
{
std::lock_guard<std::mutex> lock(m_mtx_thread);
s32 num = 0;
for(u32 i=0; i<m_threads.GetCount(); ++i)
@ -89,16 +91,17 @@ s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id)
CPUThread* CPUThreadManager::GetThread(u32 id)
{
for(u32 i=0; i<m_threads.GetCount(); ++i)
{
if(m_threads[i].GetId() == id) return &m_threads[i];
}
CPUThread* res;
return nullptr;
if (!Emu.GetIdManager().GetIDData(id, res)) return nullptr;
return res;
}
void CPUThreadManager::Exec()
{
std::lock_guard<std::mutex> lock(m_mtx_thread);
for(u32 i=0; i<m_threads.GetCount(); ++i)
{
m_threads[i].Exec();

View File

@ -16,6 +16,7 @@ PPCThread* GetCurrentPPCThread()
PPCThread::PPCThread(CPUThreadType type) : CPUThread(type)
{
memset(m_args, 0, sizeof(m_args));
}
PPCThread::~PPCThread()
@ -24,14 +25,13 @@ PPCThread::~PPCThread()
void PPCThread::DoReset()
{
memset(m_args, 0, sizeof(u64) * 4);
}
void PPCThread::InitStack()
{
if(m_stack_addr) return;
if(m_stack_size == 0) m_stack_size = 0x10000;
m_stack_addr = Memory.StackMem.Alloc(Memory.AlignAddr(m_stack_size, 0x100));
m_stack_addr = Memory.StackMem.AllocAlign(m_stack_size, 0x100);
m_stack_point = m_stack_addr + m_stack_size;
/*

View File

@ -1656,7 +1656,7 @@ private:
{
CPU.VPR[vd]._u8[15] = CPU.VPR[va]._u8[15] >> 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)

View File

@ -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;

View File

@ -602,9 +602,6 @@ public:
};
};
u64 reserve_addr;
bool reserve;
u64 cycle;
public:

View File

@ -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)
{

View File

@ -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()

View File

@ -4,8 +4,6 @@
#include "MFC.h"
#include <mutex>
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;

View File

@ -10,11 +10,13 @@ DynamicMemoryBlockBase<PT>::DynamicMemoryBlockBase()
template<typename PT>
const u32 DynamicMemoryBlockBase<PT>::GetUsedSize() const
{
std::lock_guard<std::mutex> lock(m_lock);
u32 size = 0;
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
for(u32 i=0; i<m_allocated.GetCount(); ++i)
{
size += m_used_mem[i].size;
size += m_allocated[i].size;
}
return size;
@ -35,38 +37,51 @@ bool DynamicMemoryBlockBase<PT>::IsInMyRange(const u64 addr, const u32 size)
template<typename PT>
bool DynamicMemoryBlockBase<PT>::IsMyAddress(const u64 addr)
{
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
if(addr >= 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<typename PT>
MemoryBlock* DynamicMemoryBlockBase<PT>::SetRange(const u64 start, const u32 size)
{
m_max_size = size;
std::lock_guard<std::mutex> 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<typename PT>
void DynamicMemoryBlockBase<PT>::Delete()
{
m_used_mem.Clear();
std::lock_guard<std::mutex> lock(m_lock);
m_allocated.Clear();
m_max_size = 0;
m_pages.Clear();
m_locked.Clear();
MemoryBlock::Delete();
}
template<typename PT>
bool DynamicMemoryBlockBase<PT>::Alloc(u64 addr, u32 size)
bool DynamicMemoryBlockBase<PT>::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<PT>::Alloc(u64 addr, u32 size)
return false;
}
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
std::lock_guard<std::mutex> lock(m_lock);
for(u32 i=0; i<m_allocated.GetCount(); ++i)
{
if(addr >= 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<typename PT>
void DynamicMemoryBlockBase<PT>::AppendUsedMem(u64 addr, u32 size)
void DynamicMemoryBlockBase<PT>::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<typename PT>
u64 DynamicMemoryBlockBase<PT>::Alloc(u32 size)
u64 DynamicMemoryBlockBase<PT>::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<std::mutex> 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.GetCount(); ++i)
for(u32 i=0; i<m_allocated.GetCount(); ++i)
{
if((addr >= 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<PT>::Alloc(u32 size)
template<typename PT>
bool DynamicMemoryBlockBase<PT>::Alloc()
{
return Alloc(GetSize() - GetUsedSize()) != 0;
return AllocAlign(GetSize() - GetUsedSize()) != 0;
}
template<typename PT>
bool DynamicMemoryBlockBase<PT>::Free(u64 addr)
{
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
std::lock_guard<std::mutex> 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<PT>::Free(u64 addr)
}
template<typename PT>
u8* DynamicMemoryBlockBase<PT>::GetMem(u64 addr) const
u8* DynamicMemoryBlockBase<PT>::GetMem(u64 addr) const // lock-free, addr is fixed
{
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
u64 _addr = MemoryBlock::FixAddr(m_used_mem[i].addr);
const u32 index = addr >> 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<PT>::GetMem(u64 addr) const
}
template<typename PT>
bool DynamicMemoryBlockBase<PT>::IsLocked(const u64 addr)
bool DynamicMemoryBlockBase<PT>::IsLocked(u64 addr) // lock-free
{
for(u32 i=0; i<m_locked_mem.GetCount(); ++i)
if (IsInMyRange(addr))
{
if(addr == m_locked_mem[i].addr)
const u32 index = MemoryBlock::FixAddr(addr) >> 12;
if (index < m_locked.GetCount())
{
return true;
if (m_locked[index]) return true;
}
}
return false;
}
template<typename PT>
void DynamicMemoryBlockBase<PT>::AppendLockedMem(u64 addr, u32 size)
{
m_locked_mem.Move(new MemBlockInfo(addr, size));
}
template<typename PT>
bool DynamicMemoryBlockBase<PT>::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<PT>::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<typename PT>
bool DynamicMemoryBlockBase<PT>::Unlock(u64 addr , u32 size)
bool DynamicMemoryBlockBase<PT>::Unlock(u64 addr, u32 size)
{
for(u32 i=0; i<m_locked_mem.GetCount(); ++i)
size = PAGE_4K(size); // align size
addr &= ~4095; // align start address
if(!IsInMyRange(addr, size))
{
if(addr == m_locked_mem[i].addr)
assert(0);
return false;
}
if(IsMyAddress(addr) || IsMyAddress(addr + size - 1))
{
return false;
}
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_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;
}

View File

@ -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)

View File

@ -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<typename PT>
class DynamicMemoryBlockBase : public PT
{
Array<MemBlockInfo> m_used_mem;
Array<MemBlockInfo> m_locked_mem;
mutable std::mutex m_lock;
Array<MemBlockInfo> m_allocated; // allocation info
Array<u8*> m_pages; // real addresses of every 4096 byte pages (array size should be fixed)
Array<u8*> 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

View File

@ -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<CellAudioPortParam> 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<CellAudioPortConfig> 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;
}

View File

@ -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<CellGcmContextData> 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<size; i++)
for(u32 i=0; i<size; i++)
{
Memory.Write16(offsetTable.io + ((ea+i)*sizeof(u16)), 0xFFFF);
Memory.Write16(offsetTable.ea + ((io+i)*sizeof(u16)), 0xFFFF);
@ -772,7 +772,7 @@ int32_t cellGcmUnmapIoAddress(u64 io)
io = io >> 20;
ea = Memory.Read16(offsetTable.ea + (io*sizeof(u16)));
for(int i=0; i<size; i++)
for(u32 i=0; i<size; i++)
{
Memory.Write16(offsetTable.io + ((ea+i)*sizeof(u16)), 0xFFFF);
Memory.Write16(offsetTable.ea + ((io+i)*sizeof(u16)), 0xFFFF);

View File

@ -480,7 +480,7 @@ int cellPamfReaderGetStreamInfo(mem_ptr_t<CellPamfReader> 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

View File

@ -4,9 +4,7 @@
#include <mutex>
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<CellSyncMutex> mutex)
return CELL_SYNC_ERROR_ALIGN;
}
{ // global mutex
std::lock_guard<std::mutex> 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<CellSyncMutex> mutex)
}
be_t<u16> old_order;
{ // global mutex
std::lock_guard<std::mutex> 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<CellSyncMutex> 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<CellSyncMutex> mutex)
{
return CELL_SYNC_ERROR_ALIGN;
}
{ /* global mutex */
std::lock_guard<std::mutex> 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<CellSyncMutex> mutex)
}
{ /* global mutex */
std::lock_guard<std::mutex> 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();
}

View File

@ -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;
}

View File

@ -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);

View File

@ -176,8 +176,8 @@ void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, int xid, mem_func_ptr_t<void (*
}
//start callback thread
//if(func)
//func.async(aio, error, xid, res);
if(func)
func.async(aio, error, xid, res);
ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=%d, res=%d, xid=%d [%s])",
fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.c_str());
@ -195,6 +195,7 @@ int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void
thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func));
t.detach();
//fsAioRead(fd, aio, xid, func);
aio_id = xid;

View File

@ -87,20 +87,20 @@ static func_caller* sc_table[1024] =
bind_func(sys_rwlock_wunlock), //127 (0x07F)
bind_func(sys_event_queue_create), //128 (0x080)
null_func, //129 (0x081)
bind_func(sys_event_queue_receive), null_func, bind_func(sys_event_flag_cancel), null_func, bind_func(sys_event_port_create), //134
bind_func(sys_event_queue_receive), null_func, bind_func(sys_event_flag_cancel), bind_func(sys_event_queue_drain), bind_func(sys_event_port_create), //134
null_func, bind_func(sys_event_port_connect_local), null_func, bind_func(sys_event_port_send), bind_func(sys_event_flag_get), //139
null_func, bind_func(sys_timer_usleep), bind_func(sys_timer_sleep), null_func, bind_func(sys_time_get_timezone), //144
bind_func(sys_time_get_current_time), bind_func(sys_time_get_system_time), bind_func(sys_time_get_timebase_frequency), null_func, null_func, //149
null_func, null_func, null_func, null_func, null_func, //154
null_func, bind_func(sys_spu_image_open), null_func, null_func, null_func, //159
bind_func(sys_raw_spu_create), null_func, null_func, null_func, null_func, //164
null_func, null_func, null_func, null_func, bind_func(sys_spu_initialize), //169
bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_set_argument), bind_func(sys_spu_thread_initialize), //172
bind_func(sys_spu_thread_get_exit_status), bind_func(sys_spu_thread_set_argument), null_func, null_func, bind_func(sys_spu_initialize), //169
bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_group_destroy), bind_func(sys_spu_thread_initialize), //172
bind_func(sys_spu_thread_group_start), bind_func(sys_spu_thread_group_suspend), //174
null_func, null_func, null_func, bind_func(sys_spu_thread_group_join), null_func, //179
null_func, bind_func(sys_spu_thread_write_ls), bind_func(sys_spu_thread_read_ls), null_func, bind_func(sys_spu_thread_write_snr), //184
null_func, null_func, bind_func(sys_spu_thread_set_spu_cfg), bind_func(sys_spu_thread_get_spu_cfg), null_func, //189
bind_func(sys_spu_thread_write_spu_mb), bind_func(sys_spu_thread_connect_event), null_func, null_func, null_func, //194
bind_func(sys_spu_thread_write_spu_mb), bind_func(sys_spu_thread_connect_event), null_func, bind_func(sys_spu_thread_bind_queue), null_func, //194
null_func, null_func, null_func, null_func, null_func, //199
null_func, null_func, null_func, null_func, null_func, //204
null_func, null_func, null_func, null_func, null_func, //209

View File

@ -7,6 +7,7 @@
#include "lv2/SC_SPU_Thread.h"
#include "lv2/SC_Lwmutex.h"
#include "lv2/SC_Lwcond.h"
#include "lv2/SC_Event_flag.h"
#include "Emu/event.h"
//#define SYSCALLS_DEBUG
@ -126,19 +127,22 @@ extern int sys_game_process_exitspawn(u32 path_addr, u32 argv_addr, u32 envp_add
u32 data, u32 data_size, int prio, u64 flags );
//sys_event
extern int sys_event_flag_create(u32 eflag_id_addr, u32 attr_addr, u64 init);
extern int sys_event_flag_destroy(u32 eflag_id);
extern int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, u32 result_addr, u32 timeout);
extern int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, u32 result_addr);
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, u32 num_addr);
extern int sys_event_flag_get(u32 eflag_id, u32 flag_addr);
extern int sys_event_queue_create(u32 equeue_id_addr, u32 attr_addr, u64 event_queue_key, int size);
extern int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t<sys_event_queue_attr> 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<sys_event_flag_attr> 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<sys_spu_image> img, u32 path_addr);
extern int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<sys_spu_image> img, mem_ptr_t<sys_spu_thread_attribute> attr, mem_ptr_t<sys_spu_thread_argument> arg);
extern int sys_spu_thread_set_argument(u32 id, mem_ptr_t<sys_spu_thread_argument> 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<sys_spu_thread_group_attribute> 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);

View File

@ -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)

View File

@ -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<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);
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;
}

View File

@ -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<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): 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;
}

View File

@ -0,0 +1,31 @@
#pragma once
enum
{
SYS_SYNC_WAITER_SINGLE = 0x10000,
SYS_SYNC_WAITER_MULTIPLE = 0x20000,
};
struct sys_event_flag_attr
{
be_t<u32> protocol;
be_t<u32> pshared;
be_t<u64> ipc_key;
be_t<int> flags;
be_t<int> type;
char name[8];
};
struct event_flag
{
std::atomic<u64> 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)
{
}
};

View File

@ -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];

View File

@ -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);
}

View File

@ -7,25 +7,16 @@ SysCallBase sys_lwcond("sys_lwcond");
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.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<sys_lwcond_t> lwcond)
int sys_lwcond_signal(mem_ptr_t<sys_lwcond_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<sys_lwmutex_t>(lwcond->lwmutex)->attribute);
return CELL_OK;
}
int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_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<sys_lwcond_t> lwcond)
int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_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<sys_lwcond_t> lwcond, u32 ppu_thread_id)
int sys_lwcond_wait(mem_ptr_t<sys_lwcond_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<sys_lwmutex_t> lwmutex((u32)lwcond->lwmutex_addr);
if ((u32)lwmutex->owner != tid) return CELL_EPERM; // caller must own this lwmutex
mem_ptr_t<sys_lwmutex_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;

View File

@ -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<u32> lwmutex_addr;
be_t<u32> lwmutex;
be_t<u32> lwcond_queue;
};
@ -18,22 +22,20 @@ struct LWCond
std::mutex m_lock;
Array<u32> waiters; // list of waiting threads
Array<u32> 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<std::mutex> 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;

View File

@ -5,125 +5,87 @@
SysCallBase sc_lwmutex("sys_lwmutex");
std::mutex g_lwmutex;
int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_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<sys_lwmutex_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<std::mutex> 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<sys_lwmutex_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<sys_lwmutex_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<sys_lwmutex_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());
}

View File

@ -1,4 +1,5 @@
#pragma once
#include <Utilities/SMutex.h>
// 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<u32> attr_protocol;
be_t<u32> 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<u32> 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<u32> owner;
/* volatile */ be_t<u32> waiter;
/* volatile */ SMutexBE owner;
/* volatile */ be_t<u32> waiter; // not used
};
struct
{
@ -54,77 +149,103 @@ struct sys_lwmutex_t
be_t<u32> sleep_queue;
be_t<u32> pad;
int trylock(u32 tid)
int trylock(be_t<u32> tid)
{
std::lock_guard<std::mutex> 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<u32> tid)
{
std::lock_guard<std::mutex> 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<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): default: owner.unlock(tid, target); break;
}
}
return true;
return CELL_OK;
}
}
int lock(be_t<u32> 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<sys_lwmutex_t> m_mutex;
u32 m_id;
public:
const int res;
be_t<u32> m_id;
lwmutex_locker(u32 lwmutex_addr, u32 tid)
lwmutex_locker(mem_ptr_t<sys_lwmutex_t> lwmutex, be_t<u32> 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);
}
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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());

View File

@ -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;
}

View File

@ -10,23 +10,22 @@ int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t<sys_rwlock_attribute_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;

View File

@ -6,8 +6,12 @@ struct sys_rwlock_attribute_t
be_t<u32> attr_pshared; // == 0x200 (NOT SHARED)
be_t<u64> key; // process-shared key (not used)
be_t<s32> flags; // process-shared flags (not used)
be_t<u32> pad;
char name[8];
be_t<u32> pad; // not used
union
{
char name[8];
u64 name_u64;
};
};
#pragma pack()
@ -20,21 +24,15 @@ struct RWLock
Array<u32> 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)
{
}

View File

@ -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<sys_spu_thread_argument> 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; i<group->list.GetCount(); ++i)
for(u32 i=0; i<group->list.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;
}

View File

@ -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));

View File

@ -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;
}

View File

@ -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);

View File

@ -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<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
be_t<int> type;
union
{
char name[8];
u64 name_u64;
};
};
struct sys_event_data
{
be_t<u64> source;
be_t<u64> data1;
be_t<u64> data2;
be_t<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;
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)
{
}
};

View File

@ -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;

View File

@ -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<stub.s_imports; ++i)
{

View File

@ -197,7 +197,7 @@ public:
u32 GetEntry() { return entry; }
u32 GetMinAddr() { return min_addr; }
u32 GetMaxAddr() { return min_addr; }
u32 GetMaxAddr() { return max_addr; }
};
class Loader : public LoaderBase

View File

@ -69,20 +69,20 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath)</IncludePath>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\</OutDir>
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
<TargetName>$(ProjectName)-$(PlatformShortName)-dbg</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath)</IncludePath>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\</OutDir>
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
<TargetName>$(ProjectName)-$(PlatformShortName)-dbg</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath)</IncludePath>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\</OutDir>
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
<LinkIncremental>false</LinkIncremental>
@ -91,7 +91,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;$(IncludePath)</IncludePath>
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\</OutDir>
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
<LinkIncremental>false</LinkIncremental>
@ -205,6 +205,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\SMutex.cpp" />
<ClCompile Include="..\Utilities\Thread.cpp" />
<ClCompile Include="AppConnector.cpp" />
<ClCompile Include="Emu\Audio\AudioManager.cpp" />
@ -247,6 +248,7 @@
<ClCompile Include="Emu\SysCalls\FuncList.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_Condition.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_Event.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_Event_flag.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_FileSystem.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_GCM.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\SC_Heap.cpp" />
@ -324,6 +326,7 @@
<ClInclude Include="..\Utilities\BEType.h" />
<ClInclude Include="..\Utilities\IdManager.h" />
<ClInclude Include="..\Utilities\MTProgressDialog.h" />
<ClInclude Include="..\Utilities\SMutex.h" />
<ClInclude Include="..\Utilities\Thread.h" />
<ClInclude Include="..\Utilities\Timer.h" />
<ClInclude Include="Emu\Audio\AudioManager.h" />

View File

@ -379,6 +379,12 @@
<ClCompile Include="Emu\FS\vfsLocalDir.cpp">
<Filter>Emu\FS</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\SMutex.cpp">
<Filter>Utilities</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\lv2\SC_Event_flag.cpp">
<Filter>Emu\SysCalls\lv2</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="rpcs3.rc" />
@ -558,5 +564,8 @@
<ClInclude Include="Emu\Audio\AudioManager.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\SMutex.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup>
</Project>