mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 14:31:24 +12:00
* Replace `int` with `s32` as return type for syscalls. * Renamed `SC_Something.*` files with the proper lv2 name `sys_something.*`. * Moving away from the lv2, those functions and folders that doesn't correspond to lv2 functions. E.g. module functions from sys_io, sysPrxForUser, cellGcmSys. * Splitted some files (memory -> memory+mmapper) and merged other ones (event+event_flag ->event, spu+spu_thread -> spu), according to common sense, PSDevWiki docs, and checking firmware files. * Removed external functions from `SysCalls.h`. NOTE: What should we do about: cellGcmCallback? It's not a lv2 syscall but it appears on the sc_table and it is actually called in games. Is this some kind of hack?
958 lines
20 KiB
C++
958 lines
20 KiB
C++
#include "stdafx.h"
|
|
#include "Utilities/Log.h"
|
|
#include "Emu/Memory/Memory.h"
|
|
#include "Emu/System.h"
|
|
#include "Emu/Cell/PPUThread.h"
|
|
#include "Emu/FS/vfsFile.h"
|
|
#include "sys_spu.h"
|
|
#include "Emu/SysCalls/SysCalls.h"
|
|
#include "Emu/SysCalls/SC_FUNC.h"
|
|
#include "Loader/ELF.h"
|
|
#include "Emu/Cell/RawSPUThread.h"
|
|
#include <atomic>
|
|
|
|
static SysCallBase sc_spu("sys_spu");
|
|
extern SysCallBase sys_event;
|
|
|
|
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.AllocAlign(alloc_size);
|
|
l.LoadData(spu_offset);
|
|
spu_ep = l.GetEntry();
|
|
return spu_offset;
|
|
}
|
|
/*u64 g_last_spu_offset = 0;
|
|
static const u64 g_spu_alloc_size = 0x1000000;
|
|
|
|
u32 LoadSpuImage(vfsStream& stream, u64 address)
|
|
{
|
|
ELFLoader l(stream);
|
|
l.LoadInfo();
|
|
l.LoadData(address);
|
|
|
|
return address + l.GetEntry();
|
|
}
|
|
|
|
u32 LoadSpuImage(vfsStream& stream)
|
|
{
|
|
g_last_spu_offset = Memory.MainMem.Alloc(g_spu_alloc_size);
|
|
return LoadSpuImage(stream, g_last_spu_offset);
|
|
}*/
|
|
|
|
/*u32 _max_usable_spu = 0;
|
|
u32 _max_raw_spu = 0;
|
|
|
|
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
|
{
|
|
sc_spu.Log("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
|
|
_max_usable_spu = max_usable_spu;
|
|
_max_raw_spu = max_raw_spu;
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_create(u32 id_addr, u32 attr_addr)
|
|
{
|
|
Memory.Write32(id_addr, Emu.GetIdManager().GetNewID("raw_spu"));
|
|
return CELL_OK;
|
|
}*/
|
|
|
|
//156
|
|
s32 sys_spu_image_open(mem_ptr_t<sys_spu_image> img, u32 path_addr)
|
|
{
|
|
const std::string path = Memory.ReadString(path_addr).c_str();
|
|
sc_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.GetAddr(), path_addr, path.c_str());
|
|
|
|
if(!img.IsGood() || !Memory.IsGoodAddr(path_addr))
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
vfsFile f(path);
|
|
if(!f.IsOpened())
|
|
{
|
|
sc_spu.Error("sys_spu_image_open error: '%s' not found!", path.c_str());
|
|
return CELL_ENOENT;
|
|
}
|
|
|
|
u32 entry;
|
|
u32 offset = LoadSpuImage(f, entry);
|
|
|
|
img->type = 1;
|
|
img->entry_point = entry;
|
|
img->segs_addr = offset;
|
|
img->nsegs = 0;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//172
|
|
s32 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)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_initialize(thread_addr=0x%x, group=0x%x, spu_num=%d, img_addr=0x%x, attr_addr=0x%x, arg_addr=0x%x)",
|
|
thread.GetAddr(), group, spu_num, img.GetAddr(), attr.GetAddr(), arg.GetAddr());
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(group, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if(!thread.IsGood() || !img.IsGood() || !attr.IsGood() || !arg.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
if (attr->name_addr)
|
|
{
|
|
if(!Memory.IsGoodAddr(attr->name_addr, attr->name_len))
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
}
|
|
|
|
if(spu_num >= group_info->list.size())
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
if(group_info->list[spu_num])
|
|
{
|
|
return CELL_EBUSY;
|
|
}
|
|
|
|
u32 spu_ep = (u32)img->entry_point;
|
|
|
|
std::string name = "SPUThread";
|
|
if (attr->name_addr)
|
|
{
|
|
name = Memory.ReadString(attr->name_addr, attr->name_len);
|
|
}
|
|
|
|
u64 a1 = arg->arg1;
|
|
u64 a2 = arg->arg2;
|
|
u64 a3 = arg->arg3;
|
|
u64 a4 = arg->arg4;
|
|
|
|
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU);
|
|
//copy SPU image:
|
|
u32 spu_offset = Memory.MainMem.AllocAlign(256 * 1024);
|
|
Memory.CopyToReal(Memory + spu_offset, (u32)img->segs_addr, 256 * 1024);
|
|
//initialize from new place:
|
|
new_thread.SetOffset(spu_offset);
|
|
new_thread.SetEntry(spu_ep);
|
|
new_thread.SetName(name);
|
|
new_thread.SetArg(0, a1);
|
|
new_thread.SetArg(1, a2);
|
|
new_thread.SetArg(2, a3);
|
|
new_thread.SetArg(3, a4);
|
|
new_thread.Run();
|
|
|
|
thread = group_info->list[spu_num] = new_thread.GetId();
|
|
(*(SPUThread*)&new_thread).group = group_info;
|
|
|
|
sc_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d",
|
|
(attr->name_addr ? name.c_str() : ""), (u32) img->segs_addr, ((SPUThread&) new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue());
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//166
|
|
s32 sys_spu_thread_set_argument(u32 id, mem_ptr_t<sys_spu_thread_argument> arg)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_set_argument(id=%d, arg_addr=0x%x)", id, arg.GetAddr());
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if(!arg.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
thr->SetArg(0, arg->arg1);
|
|
thr->SetArg(1, arg->arg2);
|
|
thr->SetArg(2, arg->arg3);
|
|
thr->SetArg(3, arg->arg4);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//165
|
|
s32 sys_spu_thread_get_exit_status(u32 id, mem32_t status)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status_addr=0x%x)", id, status.GetAddr());
|
|
|
|
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
|
|
s32 sys_spu_thread_group_destroy(u32 id)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_group_destroy(id=%d)", id);
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(id, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (group_info->lock) // ???
|
|
{
|
|
return CELL_EBUSY;
|
|
}
|
|
|
|
for (u32 i = 0; i < group_info->list.size(); i++)
|
|
{
|
|
// TODO: disconnect all event ports
|
|
|
|
Emu.GetCPU().RemoveThread(group_info->list[i]);
|
|
}
|
|
|
|
Emu.GetIdManager().RemoveID(id);
|
|
return CELL_OK;
|
|
}
|
|
|
|
//173
|
|
s32 sys_spu_thread_group_start(u32 id)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_group_start(id=%d)", id);
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(id, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
// TODO: check group state
|
|
|
|
for (u32 i = 0; i < group_info->list.size(); i++)
|
|
{
|
|
CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]);
|
|
if (t)
|
|
{
|
|
t->Exec();
|
|
}
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//174
|
|
s32 sys_spu_thread_group_suspend(u32 id)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_group_suspend(id=%d)", id);
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(id, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
// TODO: check group state
|
|
|
|
for (u32 i = 0; i < group_info->list.size(); i++)
|
|
{
|
|
if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
|
|
{
|
|
t->Pause();
|
|
}
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//175
|
|
s32 sys_spu_thread_group_resume(u32 id)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_group_resume(id=%d)", id);
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(id, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
// TODO: check group state
|
|
|
|
for (u32 i = 0; i < group_info->list.size(); i++)
|
|
{
|
|
if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
|
|
{
|
|
t->Resume();
|
|
}
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//170
|
|
s32 sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu_thread_group_attribute> attr)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_group_create(id_addr=0x%x, num=%d, prio=%d, attr_addr=0x%x)",
|
|
id.GetAddr(), num, prio, attr.GetAddr());
|
|
|
|
if (!id.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
|
|
|
if (!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) return CELL_EFAULT;
|
|
|
|
if (num > 256) return CELL_EINVAL;
|
|
|
|
if (prio < 16 || prio > 255) return CELL_EINVAL;
|
|
|
|
const std::string name = Memory.ReadString(attr->name_addr, attr->name_len);
|
|
|
|
id = sc_spu.GetNewId(new SpuGroupInfo(name, num, prio, attr->type, attr->ct));
|
|
|
|
sc_spu.Warning("*** SPU Thread Group created [%s] (type=0x%x, option.ct=0x%x): id=%d",
|
|
name.c_str(), (int)attr->type, (u32)attr->ct, id.GetValue());
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//178
|
|
s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_group_join(id=%d, cause_addr=0x%x, status_addr=0x%x)", id, cause.GetAddr(), status.GetAddr());
|
|
|
|
SpuGroupInfo* group_info;
|
|
if(!Emu.GetIdManager().GetIDData(id, group_info))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (group_info->lock.exchange(1)) // acquire lock
|
|
{
|
|
return CELL_EBUSY;
|
|
}
|
|
|
|
cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
|
|
status = 0; //unspecified because of ALL_THREADS_EXIT
|
|
|
|
for (u32 i = 0; i < group_info->list.size(); i++)
|
|
{
|
|
while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
|
|
{
|
|
if (!t->IsRunning())
|
|
{
|
|
break;
|
|
}
|
|
if (Emu.IsStopped())
|
|
{
|
|
LOG_WARNING(Log::SPU, "sys_spu_thread_group_join(id=%d, ...) aborted", id);
|
|
return CELL_OK;
|
|
}
|
|
Sleep(1);
|
|
}
|
|
}
|
|
|
|
group_info->lock = 0; // release lock
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_create(mem32_t thread_id, mem32_t entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_create(thread_id_addr=0x%x, entry_addr=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x",
|
|
thread_id.GetAddr(), entry.GetAddr(), arg, prio, stacksize, flags, threadname_addr);
|
|
return CELL_OK;
|
|
}
|
|
|
|
//169
|
|
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
|
{
|
|
sc_spu.Warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
|
|
|
|
if(max_raw_spu > 5)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
//if(!Memory.InitSpuRawMem(max_raw_spu))
|
|
//{
|
|
// return CELL_ENOMEM;
|
|
//}
|
|
|
|
//Ini.HLELogging.SetValue(true);
|
|
//dump_enable = true;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//181
|
|
s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=0x%x)",
|
|
id, address, value, type);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (!thr->IsRunning())
|
|
{
|
|
return CELL_ESTAT;
|
|
}
|
|
|
|
if (!(*(SPUThread*)thr).IsGoodLSA(address) || (address % type)) // +check alignment
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case 1: (*(SPUThread*)thr).WriteLS8(address, value); return CELL_OK;
|
|
case 2: (*(SPUThread*)thr).WriteLS16(address, value); return CELL_OK;
|
|
case 4: (*(SPUThread*)thr).WriteLS32(address, value); return CELL_OK;
|
|
case 8: (*(SPUThread*)thr).WriteLS64(address, value); return CELL_OK;
|
|
default: return CELL_EINVAL;
|
|
}
|
|
}
|
|
|
|
//182
|
|
s32 sys_spu_thread_read_ls(u32 id, u32 address, mem64_t value, u32 type)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value_addr=0x%x, type=0x%x)",
|
|
id, address, value.GetAddr(), type);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (!thr->IsRunning())
|
|
{
|
|
return CELL_ESTAT;
|
|
}
|
|
|
|
if(!value.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
if (!(*(SPUThread*)thr).IsGoodLSA(address) || (address % type)) // +check alignment
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case 1: value = (*(SPUThread*)thr).ReadLS8(address); return CELL_OK;
|
|
case 2: value = (*(SPUThread*)thr).ReadLS16(address); return CELL_OK;
|
|
case 4: value = (*(SPUThread*)thr).ReadLS32(address); return CELL_OK;
|
|
case 8: value = (*(SPUThread*)thr).ReadLS64(address); return CELL_OK;
|
|
default: return CELL_EINVAL;
|
|
}
|
|
}
|
|
|
|
//190
|
|
s32 sys_spu_thread_write_spu_mb(u32 id, u32 value)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_write_spu_mb(id=%d, value=0x%x)", id, value);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
(*(SPUThread*)thr).SPU.In_MBox.PushUncond(value);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//187
|
|
s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_set_spu_cfg(id=%d, value=0x%x)", id, value);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (value > 3)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
(*(SPUThread*)thr).cfg.value = value;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//188
|
|
s32 sys_spu_thread_get_spu_cfg(u32 id, mem64_t value)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value_addr=0x%x)", id, value.GetAddr());
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
value = (*(SPUThread*)thr).cfg.value;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//184
|
|
s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value)
|
|
{
|
|
sc_spu.Log("sys_spu_thread_write_snr(id=%d, number=%d, value=0x%x)", id, number, value);
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (number > 1)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
(*(SPUThread*)thr).WriteSNR(number, value);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_group_connect_event(u32 id, u32 eq, u32 et)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_group_connect_event(id=%d, eq=%d, et=0x%x)", id, eq, et);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_group_disconnect_event(u32 id, u32 et)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_group_disconnect_event(id=%d, et=0x%x)", id, et);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
/*
|
|
SPU-Side functions:
|
|
s32 sys_spu_thread_receive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3);
|
|
s32 sys_spu_thread_send_event(u8 spup, u24 data0, u32 data1);
|
|
s32 sys_spu_thread_throw_event(u8 spup, u24 data0, u32 data1);
|
|
s32 sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3);
|
|
*/
|
|
|
|
s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_connect_event(id=%d, eq_id=%d, event_type=0x%x, spup=%d)", id, eq_id, et, spup);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
EventQueue* eq;
|
|
if (!Emu.GetIdManager().GetIDData(eq_id, eq))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (spup > 63)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup);
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
if (et != SYS_SPU_THREAD_EVENT_USER)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et);
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
// TODO: check if can receive this events
|
|
|
|
SPUThread& spu = *(SPUThread*)thr;
|
|
|
|
EventPort& port = spu.SPUPs[spup];
|
|
|
|
std::lock_guard<std::mutex> lock(port.m_mutex);
|
|
|
|
if (port.eq)
|
|
{
|
|
return CELL_EISCONN;
|
|
}
|
|
|
|
eq->ports.add(&port);
|
|
port.eq = eq;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//
|
|
s32 sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d)", id, et, spup);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (spup > 63)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup);
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
if (et != SYS_SPU_THREAD_EVENT_USER)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et);
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
SPUThread& spu = *(SPUThread*)thr;
|
|
|
|
EventPort& port = spu.SPUPs[spup];
|
|
|
|
std::lock_guard<std::mutex> lock(port.m_mutex);
|
|
|
|
if (!port.eq)
|
|
{
|
|
return CELL_ENOTCONN;
|
|
}
|
|
|
|
port.eq->ports.remove(&port);
|
|
port.eq = nullptr;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=0x%x)", id, eq_id, spuq_num);
|
|
|
|
EventQueue* eq;
|
|
if (!Emu.GetIdManager().GetIDData(eq_id, eq))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (eq->type != SYS_SPU_QUEUE)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (!(*(SPUThread*)thr).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num)))
|
|
{
|
|
return CELL_EBUSY;
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num)
|
|
{
|
|
sc_spu.Warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num);
|
|
|
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
|
|
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (!(*(SPUThread*)thr).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num)))
|
|
{
|
|
return CELL_ESRCH; // may be CELL_EINVAL
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_group_connect_event_all_threads(id=%d, eq=%d, req=0x%llx, spup_addr=0x%x)",
|
|
id, eq, req, spup_addr);
|
|
|
|
EventQueue* equeue;
|
|
if(!sys_event.CheckId(eq, equeue))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if(!req)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
SpuGroupInfo* group;
|
|
if(!Emu.GetIdManager().GetIDData(id, group))
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
/*
|
|
for(u32 i=0; i<group->list.size(); ++i)
|
|
{
|
|
CPUThread* t;
|
|
if(t = Emu.GetCPU().GetThread(group->list[i]))
|
|
{
|
|
bool finded_port = false;
|
|
for(int j=0; j<equeue->pos; ++j)
|
|
{
|
|
if(!equeue->ports[j]->thread)
|
|
{
|
|
finded_port = true;
|
|
equeue->ports[j]->thread = t;
|
|
}
|
|
}
|
|
|
|
if(!finded_port)
|
|
{
|
|
return CELL_EISCONN;
|
|
}
|
|
}
|
|
}*/
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_spu_thread_group_disconnect_event_all_threads(u32 id, u8 spup)
|
|
{
|
|
sc_spu.Error("sys_spu_thread_group_disconnect_event_all_threads(id=%d, spup=%d)", id, spup);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
//160
|
|
s32 sys_raw_spu_create(mem32_t id, u32 attr_addr)
|
|
{
|
|
sc_spu.Warning("sys_raw_spu_create(id_addr=0x%x, attr_addr=0x%x)", id.GetAddr(), attr_addr);
|
|
|
|
//Emu.GetIdManager().GetNewID("sys_raw_spu", new u32(attr_addr));
|
|
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_RAW_SPU);
|
|
id = ((RawSPUThread&)new_thread).GetIndex();
|
|
new_thread.Run();
|
|
new_thread.Exec();
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_destroy(u32 id)
|
|
{
|
|
sc_spu.Error("sys_raw_spu_destroy(id=%d)", id);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, mem32_t intrtag)
|
|
{
|
|
sc_spu.Error("sys_raw_spu_create_interrupt_tag(id=%d, class_id=%d, hwthread=0x%x, intrtag_addr=0x%x)", id, class_id, hwthread, intrtag.GetAddr());
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (class_id != 0 && class_id != 2)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
if (!intrtag.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
if (t->m_intrtag[class_id].enabled)
|
|
{
|
|
return CELL_EAGAIN;
|
|
}
|
|
|
|
t->m_intrtag[class_id].enabled = 1;
|
|
intrtag = (id & 0xff) | (class_id << 8);
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask)
|
|
{
|
|
sc_spu.Warning("sys_raw_spu_set_int_mask(id=%d, class_id=%d, mask=0x%llx)", id, class_id, mask);
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (class_id != 0 && class_id != 2)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
t->m_intrtag[class_id].mask = mask; // TODO: check this
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, mem64_t mask)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_get_int_mask(id=%d, class_id=%d, mask_addr=0x%x)", id, class_id, mask.GetAddr());
|
|
|
|
if (!mask.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (class_id != 0 && class_id != 2)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
mask = t->m_intrtag[class_id].mask;
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_set_int_stat(id=%d, class_id=%d, stat=0x%llx)", id, class_id, stat);
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (class_id != 0 && class_id != 2)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
t->m_intrtag[class_id].stat = stat; // TODO: check this
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, mem64_t stat)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_get_int_stat(id=%d, class_id=%d, stat_addr=0xx)", id, class_id, stat.GetAddr());
|
|
|
|
if (!stat.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
if (class_id != 0 && class_id != 2)
|
|
{
|
|
return CELL_EINVAL;
|
|
}
|
|
|
|
stat = t->m_intrtag[class_id].stat;
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_read_puint_mb(u32 id, mem32_t value)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_read_puint_mb(id=%d, value_addr=0x%x)", id, value.GetAddr());
|
|
|
|
if (!value.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
u32 v;
|
|
t->SPU.Out_IntrMBox.PopUncond(v);
|
|
value = v;
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_set_spu_cfg(id=%d, value=0x%x)", id, value);
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
t->cfg.value = value;
|
|
return CELL_OK;
|
|
}
|
|
|
|
s32 sys_raw_spu_get_spu_cfg(u32 id, mem32_t value)
|
|
{
|
|
sc_spu.Log("sys_raw_spu_get_spu_afg(id=%d, value_addr=0x%x)", id, value.GetAddr());
|
|
|
|
if (!value.IsGood())
|
|
{
|
|
return CELL_EFAULT;
|
|
}
|
|
|
|
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
if (!t)
|
|
{
|
|
return CELL_ESRCH;
|
|
}
|
|
|
|
value = t->cfg.value;
|
|
return CELL_OK;
|
|
}
|