2014-06-23 05:03:16 +04:00
|
|
|
#include "stdafx.h"
|
2018-07-27 22:07:34 +03:00
|
|
|
#include "Emu/Memory/vm.h"
|
2014-06-23 05:03:16 +04:00
|
|
|
#include "Emu/System.h"
|
2015-03-07 01:58:42 +03:00
|
|
|
#include "Emu/IdManager.h"
|
2014-08-23 18:51:51 +04:00
|
|
|
|
2016-04-14 01:23:53 +03:00
|
|
|
#include "Emu/Cell/ErrorCodes.h"
|
2014-06-23 05:03:16 +04:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2016-07-28 00:43:22 +03:00
|
|
|
#include "Emu/Cell/PPUOpcodes.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_interrupt.h"
|
2014-06-23 05:03:16 +04:00
|
|
|
|
2018-02-09 17:49:37 +03:00
|
|
|
|
2016-08-20 00:14:10 +03:00
|
|
|
|
2018-08-25 15:39:00 +03:00
|
|
|
LOG_CHANNEL(sys_interrupt);
|
2014-06-23 05:03:16 +04:00
|
|
|
|
2017-01-29 19:50:18 +03:00
|
|
|
void lv2_int_serv::exec()
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2016-07-28 00:43:22 +03:00
|
|
|
thread->cmd_list
|
|
|
|
|
({
|
2018-03-05 20:36:33 -06:00
|
|
|
{ ppu_cmd::reset_stack, 0 },
|
2016-07-28 00:43:22 +03:00
|
|
|
{ ppu_cmd::set_args, 2 }, arg1, arg2,
|
|
|
|
|
{ ppu_cmd::lle_call, 2 },
|
2017-02-06 21:36:46 +03:00
|
|
|
{ ppu_cmd::sleep, 0 }
|
2016-07-28 00:43:22 +03:00
|
|
|
});
|
2015-07-13 00:02:02 +03:00
|
|
|
|
2016-09-07 01:38:52 +03:00
|
|
|
thread->notify();
|
2016-07-28 00:43:22 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
void lv2_int_serv::join()
|
2016-07-28 00:43:22 +03:00
|
|
|
{
|
|
|
|
|
// Enqueue _sys_ppu_thread_exit call
|
|
|
|
|
thread->cmd_list
|
|
|
|
|
({
|
|
|
|
|
{ ppu_cmd::set_args, 1 }, u64{0},
|
|
|
|
|
{ ppu_cmd::set_gpr, 11 }, u64{41},
|
|
|
|
|
{ ppu_cmd::opcode, ppu_instructions::SC(0) },
|
|
|
|
|
});
|
|
|
|
|
|
2016-09-07 01:38:52 +03:00
|
|
|
thread->notify();
|
2017-02-04 19:30:21 +03:00
|
|
|
thread->join();
|
2015-07-13 00:02:02 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
error_code sys_interrupt_tag_destroy(u32 intrtag)
|
2015-07-13 00:02:02 +03:00
|
|
|
{
|
2016-01-13 00:57:16 +03:00
|
|
|
sys_interrupt.warning("sys_interrupt_tag_destroy(intrtag=0x%x)", intrtag);
|
2015-07-13 00:02:02 +03:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
const auto tag = idm::withdraw<lv2_obj, lv2_int_tag>(intrtag, [](lv2_int_tag& tag) -> CellError
|
|
|
|
|
{
|
|
|
|
|
if (!tag.handler.expired())
|
|
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2015-03-03 00:09:20 +03:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
return {};
|
|
|
|
|
});
|
2015-07-13 00:02:02 +03:00
|
|
|
|
|
|
|
|
if (!tag)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
if (tag.ret)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2017-02-04 19:30:21 +03:00
|
|
|
return tag.ret;
|
2014-06-23 05:03:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
error_code _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread, u64 arg1, u64 arg2)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2016-01-13 00:57:16 +03:00
|
|
|
sys_interrupt.warning("_sys_interrupt_thread_establish(ih=*0x%x, intrtag=0x%x, intrthread=0x%x, arg1=0x%llx, arg2=0x%llx)", ih, intrtag, intrthread, arg1, arg2);
|
2015-07-13 00:02:02 +03:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
CellError error = CELL_EAGAIN;
|
2014-06-23 05:03:16 +04:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
const u32 id = idm::import<lv2_obj, lv2_int_serv>([&]()
|
2015-07-13 00:02:02 +03:00
|
|
|
{
|
2017-02-04 19:30:21 +03:00
|
|
|
std::shared_ptr<lv2_int_serv> result;
|
|
|
|
|
|
|
|
|
|
// Get interrupt tag
|
|
|
|
|
const auto tag = idm::check_unlocked<lv2_obj, lv2_int_tag>(intrtag);
|
|
|
|
|
|
|
|
|
|
if (!tag)
|
|
|
|
|
{
|
|
|
|
|
error = CELL_ESRCH;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get interrupt thread
|
|
|
|
|
const auto it = idm::get_unlocked<ppu_thread>(intrthread);
|
|
|
|
|
|
|
|
|
|
if (!it)
|
|
|
|
|
{
|
|
|
|
|
error = CELL_ESRCH;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If interrupt thread is running, it's already established on another interrupt tag
|
|
|
|
|
if (!test(it->state & cpu_flag::stop))
|
|
|
|
|
{
|
|
|
|
|
error = CELL_EAGAIN;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// It's unclear if multiple handlers can be established on single interrupt tag
|
|
|
|
|
if (!tag->handler.expired())
|
|
|
|
|
{
|
|
|
|
|
error = CELL_ESTAT;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = std::make_shared<lv2_int_serv>(it, arg1, arg2);
|
|
|
|
|
tag->handler = result;
|
|
|
|
|
it->run();
|
|
|
|
|
return result;
|
|
|
|
|
});
|
2014-06-23 05:03:16 +04:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
if (id)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2017-02-04 19:30:21 +03:00
|
|
|
*ih = id;
|
|
|
|
|
return CELL_OK;
|
2014-06-23 05:03:16 +04:00
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
return error;
|
2014-06-23 05:03:16 +04:00
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
error_code _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr<u64> r13)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2016-01-13 00:57:16 +03:00
|
|
|
sys_interrupt.warning("_sys_interrupt_thread_disestablish(ih=0x%x, r13=*0x%x)", ih, r13);
|
2015-07-13 00:02:02 +03:00
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
const auto handler = idm::withdraw<lv2_obj, lv2_int_serv>(ih);
|
2015-04-12 04:36:25 +03:00
|
|
|
|
|
|
|
|
if (!handler)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2017-10-01 04:40:51 +03:00
|
|
|
if (const auto thread = idm::withdraw<ppu_thread>(ih))
|
|
|
|
|
{
|
|
|
|
|
*r13 = thread->gpr[13];
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-23 05:03:16 +04:00
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-13 00:02:02 +03:00
|
|
|
// Wait for sys_interrupt_thread_eoi() and destroy interrupt thread
|
2017-02-04 19:30:21 +03:00
|
|
|
handler->join();
|
2014-06-23 05:03:16 +04:00
|
|
|
|
2015-07-13 00:02:02 +03:00
|
|
|
// Save TLS base
|
2016-07-28 00:43:22 +03:00
|
|
|
*r13 = handler->thread->gpr[13];
|
2015-03-03 00:09:20 +03:00
|
|
|
|
2014-06-23 05:03:16 +04:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
void sys_interrupt_thread_eoi(ppu_thread& ppu)
|
2014-06-23 05:03:16 +04:00
|
|
|
{
|
2017-03-11 02:14:48 +03:00
|
|
|
vm::temporary_unlock(ppu);
|
|
|
|
|
|
2017-02-04 19:30:21 +03:00
|
|
|
sys_interrupt.trace("sys_interrupt_thread_eoi()");
|
2015-04-20 02:49:13 +03:00
|
|
|
|
2016-08-09 17:14:41 +03:00
|
|
|
ppu.state += cpu_flag::ret;
|
2014-07-12 17:46:14 +10:00
|
|
|
}
|