2014-06-23 03:03:16 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2015-03-06 23:58:42 +01:00
|
|
|
#include "Emu/IdManager.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
2015-03-02 22:09:20 +01:00
|
|
|
#include "Emu/SysCalls/CB_FUNC.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
|
2014-08-26 01:55:37 +02:00
|
|
|
#include "Emu/CPU/CPUThreadManager.h"
|
2014-06-23 03:03:16 +02:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
|
|
|
|
#include "Emu/Cell/RawSPUThread.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_interrupt.h"
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
SysCallBase sys_interrupt("sys_interrupt");
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_interrupt_tag_destroy(u32 intrtag)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2015-03-24 16:17:53 +01:00
|
|
|
sys_interrupt.Warning("sys_interrupt_tag_destroy(intrtag=0x%x)", intrtag);
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
const u32 class_id = intrtag >> 8;
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
if (class_id != 0 && class_id != 2)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 03:36:25 +02:00
|
|
|
const auto t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff);
|
2015-03-02 22:09:20 +01:00
|
|
|
|
|
|
|
|
if (!t)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
RawSPUThread& spu = static_cast<RawSPUThread&>(*t);
|
|
|
|
|
|
|
|
|
|
auto& tag = class_id ? spu.int2 : spu.int0;
|
|
|
|
|
|
|
|
|
|
if (s32 old = tag.assigned.compare_and_swap(0, -1))
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2015-03-02 22:09:20 +01:00
|
|
|
if (old > 0)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_ESRCH;
|
2014-06-23 03:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-11 19:20:01 +02:00
|
|
|
s32 sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u64 intrthread, u64 arg)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2015-03-24 16:17:53 +01:00
|
|
|
sys_interrupt.Warning("sys_interrupt_thread_establish(ih=*0x%x, intrtag=0x%x, intrthread=%lld, arg=0x%llx)", ih, intrtag, intrthread, arg);
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
const u32 class_id = intrtag >> 8;
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
if (class_id != 0 && class_id != 2)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 03:36:25 +02:00
|
|
|
const auto t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff);
|
2015-03-02 22:09:20 +01:00
|
|
|
|
|
|
|
|
if (!t)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
RawSPUThread& spu = static_cast<RawSPUThread&>(*t);
|
|
|
|
|
|
|
|
|
|
auto& tag = class_id ? spu.int2 : spu.int0;
|
|
|
|
|
|
2015-03-04 22:51:14 +01:00
|
|
|
// CELL_ESTAT is not returned (can't detect exact condition)
|
2015-03-02 22:09:20 +01:00
|
|
|
|
2015-04-12 03:36:25 +02:00
|
|
|
const auto it = Emu.GetCPU().GetThread((u32)intrthread);
|
2014-06-23 03:03:16 +02:00
|
|
|
|
|
|
|
|
if (!it)
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
std::shared_ptr<interrupt_handler_t> handler(new interrupt_handler_t{ it });
|
|
|
|
|
|
|
|
|
|
PPUThread& ppu = static_cast<PPUThread&>(*it);
|
|
|
|
|
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2015-03-04 05:42:04 +01:00
|
|
|
LV2_LOCK;
|
2015-03-02 22:09:20 +01:00
|
|
|
|
|
|
|
|
if (ppu.custom_task)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EAGAIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s32 res = tag.assigned.atomic_op<s32>(CELL_OK, [](s32& value) -> s32
|
|
|
|
|
{
|
|
|
|
|
if (value < 0)
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value++;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}))
|
|
|
|
|
{
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ppu.custom_task = [t, &tag, arg](PPUThread& CPU)
|
|
|
|
|
{
|
|
|
|
|
auto func = vm::ptr<void(u64 arg)>::make(CPU.entry);
|
|
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> cond_lock(tag.handler_mutex);
|
|
|
|
|
|
|
|
|
|
while (!Emu.IsStopped())
|
|
|
|
|
{
|
|
|
|
|
if (tag.stat.read_relaxed())
|
|
|
|
|
{
|
|
|
|
|
func(CPU, arg); // call interrupt handler until int status is clear
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tag.cond.wait_for(cond_lock, std::chrono::milliseconds(1));
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-06-23 03:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
*ih = Emu.GetIdManager().GetNewID(handler, TYPE_INTR_SERVICE_HANDLE);
|
2015-03-02 22:09:20 +01:00
|
|
|
ppu.Exec();
|
|
|
|
|
|
2014-06-23 03:03:16 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
s32 _sys_interrupt_thread_disestablish(u32 ih, vm::ptr<u64> r13)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2015-03-24 16:17:53 +01:00
|
|
|
sys_interrupt.Todo("_sys_interrupt_thread_disestablish(ih=0x%x, r13=*0x%x)", ih, r13);
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-04-12 03:36:25 +02:00
|
|
|
const auto handler = Emu.GetIdManager().GetIDData<interrupt_handler_t>(ih);
|
|
|
|
|
|
|
|
|
|
if (!handler)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
PPUThread& ppu = static_cast<PPUThread&>(*handler->handler);
|
2014-06-23 03:03:16 +02:00
|
|
|
|
|
|
|
|
// TODO: wait for sys_interrupt_thread_eoi() and destroy interrupt thread
|
|
|
|
|
|
2015-03-02 22:09:20 +01:00
|
|
|
*r13 = ppu.GPR[13];
|
|
|
|
|
|
2014-06-23 03:03:16 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-24 16:17:53 +01:00
|
|
|
void sys_interrupt_thread_eoi(PPUThread& CPU)
|
2014-06-23 03:03:16 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_interrupt.Log("sys_interrupt_thread_eoi()");
|
2014-06-23 03:03:16 +02:00
|
|
|
|
2015-03-24 16:17:53 +01:00
|
|
|
CPU.FastStop();
|
2014-07-12 09:46:14 +02:00
|
|
|
}
|