Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cellSyncMutex+SPU #49

Merged
merged 3 commits into from
Jan 12, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions rpcs3/Emu/Cell/MFC.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ enum
MFC_MASK_CMD = 0xffff,
};

// Atomic Status Update
enum
{
MFC_PUTLLC_SUCCESS = 0,
MFC_PUTLLC_FAILURE = 1, //reservation was lost
MFC_PUTLLUC_SUCCESS = 2,
MFC_GETLLAR_SUCCESS = 4,
};

enum
{
MFC_SPU_TO_PPU_MAILBOX_STATUS_MASK = 0x000000FF,
Expand Down
33 changes: 33 additions & 0 deletions rpcs3/Emu/Cell/SPUThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ class SPUThread : public PPCThread
Channel<1> QueryType;
Channel<1> QueryMask;
Channel<1> TagStatus;
Channel<1> AtomicStat;
} Prxy;

struct
Expand Down Expand Up @@ -519,6 +520,31 @@ class SPUThread : public PPCThread
}
break;

case MFC_GETLLAR_CMD:
case MFC_PUTLLC_CMD:
case MFC_PUTLLUC_CMD:
{
extern std::mutex g_SyncMutex;
//can provide compatability for CellSyncMutex through SPU<>PPU and SPU<>SPU
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",
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)
{
g_SyncMutex.unlock();
}
}
break;

default:
ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
op, cmd, lsa, ea, tag, size);
Expand Down Expand Up @@ -549,6 +575,9 @@ class SPUThread : public PPCThread
case SPU_RdSigNotify2:
return SPU.SNR[1].GetCount();

case MFC_RdAtomicStat:
return Prxy.AtomicStat.GetCount();

default:
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
break;
Expand Down Expand Up @@ -641,6 +670,10 @@ class SPUThread : public PPCThread
//ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
break;

case MFC_RdAtomicStat:
while (!Prxy.AtomicStat.Pop(v) && !Emu.IsStopped()) Sleep(1);
break;

default:
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
break;
Expand Down
9 changes: 7 additions & 2 deletions rpcs3/Emu/Memory/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,9 @@ class mem_base_t
return Memory.IsGoodAddr(m_addr, sizeof(T));
}

__forceinline operator bool() const
__forceinline operator u32() const
{
return m_addr != 0;
return m_addr;
}

__forceinline bool operator != (nullptr_t) const
Expand Down Expand Up @@ -592,6 +592,11 @@ template<typename T> class mem_t : public mem_base_t<T>
return *this;
}

__forceinline T GetValue()
{
return (be_t<T>&)Memory[this->m_addr];
}

operator const T() const
{
return (be_t<T>&)Memory[this->m_addr];
Expand Down
110 changes: 77 additions & 33 deletions rpcs3/Emu/SysCalls/Modules/cellSync.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
#include <mutex>

void cellSync_init();
Module cellSync("cellSync", cellSync_init);
void cellSync_unload();
Module cellSync("cellSync", cellSync_init, nullptr, cellSync_unload);
std::mutex g_SyncMutex;

// Return Codes
enum
Expand All @@ -22,78 +25,114 @@ enum
CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114,
};

int cellSyncMutexInitialize(mem32_t mutex)
struct CellSyncMutex {
be_t<u16> m_freed;
be_t<u16> m_order;
/*
(???) Initialize: set zeros
(???) Lock: increase m_order and wait until m_freed == old m_order
(???) Unlock: increase m_freed
(???) TryLock: ?????
*/
};

int cellSyncMutexInitialize(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync.Log("cellSyncMutexInitialize(mutex=0x%x)", mutex.GetAddr());
const u32 mutex_addr = mutex.GetAddr();
if (!mutex_addr)

if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex_addr % 4)
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
mutex = 0;
_mm_sfence();
return CELL_OK;

{ /* global mutex */
std::lock_guard<std::mutex> lock(g_SyncMutex); //???
mutex->m_freed = 0;
mutex->m_order = 0;
return CELL_OK;
}
}

int cellSyncMutexLock(mem32_t mutex)
int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync.Log("cellSyncMutexLock(mutex=0x%x)", mutex.GetAddr());
const u32 mutex_addr = mutex.GetAddr();
if (!mutex_addr)

if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex_addr % 4)
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
while (_InterlockedExchange((volatile long*)(Memory + mutex_addr), 1 << 24));
//need to check how does SPU work with these mutexes, also obtainment order is not guaranteed
_mm_lfence();

be_t<u16> old_order;
{ /* global mutex */
std::lock_guard<std::mutex> lock(g_SyncMutex);
old_order = mutex->m_order;
mutex->m_order = mutex->m_order + 1;
}

int counter = 0;
while (old_order != mutex->m_freed)
{
Sleep(1);
if (++counter >= 5000)
{
Emu.Pause();
cellSync.Error("cellSyncMutexLock(mutex=0x%x, old_order=%d, order=%d, freed=%d): TIMEOUT",
mutex.GetAddr(), (u16)old_order, (u16)mutex->m_order, (u16)mutex->m_freed);
break;
}
}
return CELL_OK;
}

int cellSyncMutexTryLock(mem32_t mutex)
int cellSyncMutexTryLock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync.Log("cellSyncMutexTryLock(mutex=0x%x)", mutex.GetAddr());
const u32 mutex_addr = mutex.GetAddr();
if (!mutex_addr)

if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex_addr % 4)
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
//check cellSyncMutexLock
if (_InterlockedExchange((volatile long*)(Memory + mutex_addr), 1 << 24))
{
return CELL_SYNC_ERROR_BUSY;
{ /* global mutex */
std::lock_guard<std::mutex> lock(g_SyncMutex);
if (mutex->m_order != mutex->m_freed)
{
return CELL_SYNC_ERROR_BUSY;
}
mutex->m_order = mutex->m_order + 1;
return CELL_OK;
}
_mm_lfence();
return CELL_OK;
}

int cellSyncMutexUnlock(mem32_t mutex)
int cellSyncMutexUnlock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync.Log("cellSyncMutexUnlock(mutex=0x%x)", mutex.GetAddr());
const u32 mutex_addr = mutex.GetAddr();
if (!mutex_addr)

if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex_addr % 4)
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
//check cellSyncMutexLock
_mm_sfence();
_InterlockedExchange((volatile long*)(Memory + mutex_addr), 0);
return CELL_OK;

{ /* global mutex */
std::lock_guard<std::mutex> lock(g_SyncMutex);
mutex->m_freed = mutex->m_freed + 1;
return CELL_OK;
}
}

void cellSync_init()
Expand All @@ -102,4 +141,9 @@ void cellSync_init()
cellSync.AddFunc(0x1bb675c2, cellSyncMutexLock);
cellSync.AddFunc(0xd06918c4, cellSyncMutexTryLock);
cellSync.AddFunc(0x91f2b7b0, cellSyncMutexUnlock);
}

void cellSync_unload()
{
g_SyncMutex.unlock();
}
2 changes: 2 additions & 0 deletions rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,12 @@ int cellSysutilGetSystemParamString(s32 id, mem_list_ptr_t<u8> buf, u32 bufsize)
{
case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME:
cellSysutil.Warning("cellSysutilGetSystemParamString: CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME");
memcpy(buf, "Unknown", 8); //for example
break;

case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME:
cellSysutil.Warning("cellSysutilGetSystemParamString: CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME");
memcpy(buf, "Unknown", 8);
break;

default:
Expand Down
51 changes: 39 additions & 12 deletions rpcs3/Emu/SysCalls/Modules/sys_fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#include "Emu/SysCalls/SC_FUNC.h"

void sys_fs_init();
Module sys_fs(0x000e, sys_fs_init);
void sys_fs_unload();
Module sys_fs(0x000e, sys_fs_init, nullptr, sys_fs_unload);
Array<vfsStream*> FDs;

bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp)
{
Expand Down Expand Up @@ -137,13 +139,9 @@ int cellFsSdataOpen(u32 path_addr, int flags, mem32_t fd, mem32_t arg, u64 size)

std::atomic<u32> g_FsAioReadID = 0;

int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func)
void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func)
{
ID id;
u32 fd = (u32)aio->fd;
if(!sys_fs.CheckId(fd, id)) return CELL_ESRCH;
vfsFileBase& orig_file = *(vfsFileBase*)id.m_data;
//open the file again (to prevent access conflicts roughly)
vfsFileBase& orig_file = *(vfsFileBase*)FDs[fd];

u64 nbytes = (u64)aio->size;
const u32 buf_addr = (u32)aio->buf_addr;
Expand All @@ -153,7 +151,8 @@ int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void

if(Memory.IsGoodAddr(buf_addr))
{
vfsFile file(orig_file.GetPath().AfterFirst('/'), vfsRead);
//open the file again (to prevent access conflicts roughly)
vfsLocalFile file(orig_file.GetPath().AfterFirst('/'), vfsRead);
if(!Memory.IsGoodAddr(buf_addr, nbytes))
{
MemoryBlock& block = Memory.GetMemByAddr(buf_addr);
Expand All @@ -175,11 +174,26 @@ int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void
const u32 xid = g_FsAioReadID++;
aio_id = xid;

sys_fs.Warning("cellFsAioRead(aio_addr: 0x%x[%s], id_addr: 0x%x, func_addr: 0x%x[res=%d, addr=0x%x])", aio.GetAddr(),
orig_file.GetPath().c_str(), aio_id.GetAddr(), func.GetAddr(), res, (u32)aio->buf_addr);
//start callback thread
if(func)
func.async(aio.GetAddr(), error, xid, res);
}

int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func)
{
//ID id;
u32 fd = (u32)aio->fd;
//if(!sys_fs.CheckId(fd, id)) return CELL_ESRCH;
if (fd >= FDs.GetCount()) return CELL_ESRCH;
if (FDs[fd] == nullptr) return CELL_ESRCH;
//vfsFileBase& orig_file = *(vfsFileBase*)id.m_data;
vfsFileBase& orig_file = *(vfsFileBase*)FDs[fd];

std::thread t(fsAioRead, fd, aio, aio_id, func);
t.detach();

if(func)
func(aio, error, xid, res);
sys_fs.Warning("cellFsAioRead(aio_addr: 0x%x[%s, addr=0x%x], id_addr: 0x%x, func_addr: 0x%x)", aio.GetAddr(),
orig_file.GetPath().c_str(), (u32)aio->buf_addr, aio_id.GetAddr(), func.GetAddr());

return CELL_OK;
}
Expand All @@ -206,3 +220,16 @@ void sys_fs_init()
sys_fs.AddFunc(0xcb588dba, cellFsFGetBlockSize);
sys_fs.AddFunc(0xc1c507e7, cellFsAioRead);
}

void sys_fs_unload()
{
for (u32 i = 0; i < FDs.GetCount(); i++)
{
if (FDs[i])
{
FDs[i]->Close();
delete FDs[i];
}
}
FDs.Clear();
}
Loading