mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
Partial commit: Syscalls
This commit is contained in:
parent
5637c22363
commit
42e1d4d752
@ -1,42 +1,39 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/AutoPause.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/state.h"
|
||||
#include "Modules.h"
|
||||
|
||||
#include "lv2/sys_lwmutex.h"
|
||||
#include "lv2/sys_lwcond.h"
|
||||
#include "lv2/sys_mutex.h"
|
||||
#include "lv2/sys_cond.h"
|
||||
#include "lv2/sys_event.h"
|
||||
#include "lv2/sys_event_flag.h"
|
||||
#include "lv2/sys_interrupt.h"
|
||||
#include "lv2/sys_memory.h"
|
||||
#include "lv2/sys_mmapper.h"
|
||||
#include "lv2/sys_ppu_thread.h"
|
||||
#include "lv2/sys_process.h"
|
||||
#include "lv2/sys_prx.h"
|
||||
#include "lv2/sys_rsx.h"
|
||||
#include "lv2/sys_rwlock.h"
|
||||
#include "lv2/sys_semaphore.h"
|
||||
#include "lv2/sys_spu.h"
|
||||
#include "lv2/sys_time.h"
|
||||
#include "lv2/sys_timer.h"
|
||||
#include "lv2/sys_trace.h"
|
||||
#include "lv2/sys_tty.h"
|
||||
#include "lv2/sys_vm.h"
|
||||
#include "lv2/sys_fs.h"
|
||||
#include "lv2/sys_dbg.h"
|
||||
#include "Emu/Cell/PPUFunction.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_lwmutex.h"
|
||||
#include "sys_lwcond.h"
|
||||
#include "sys_mutex.h"
|
||||
#include "sys_cond.h"
|
||||
#include "sys_event.h"
|
||||
#include "sys_event_flag.h"
|
||||
#include "sys_interrupt.h"
|
||||
#include "sys_memory.h"
|
||||
#include "sys_mmapper.h"
|
||||
#include "sys_ppu_thread.h"
|
||||
#include "sys_process.h"
|
||||
#include "sys_prx.h"
|
||||
#include "sys_rsx.h"
|
||||
#include "sys_rwlock.h"
|
||||
#include "sys_semaphore.h"
|
||||
#include "sys_spu.h"
|
||||
#include "sys_time.h"
|
||||
#include "sys_timer.h"
|
||||
#include "sys_trace.h"
|
||||
#include "sys_tty.h"
|
||||
#include "sys_vm.h"
|
||||
#include "sys_fs.h"
|
||||
#include "sys_dbg.h"
|
||||
|
||||
#include "Emu/SysCalls/Modules/cellGcmSys.h"
|
||||
extern std::string ppu_get_syscall_name(u64 code);
|
||||
|
||||
#include "SysCalls.h"
|
||||
|
||||
void null_func(PPUThread& ppu)
|
||||
static void null_func(PPUThread& ppu)
|
||||
{
|
||||
const u64 code = ppu.GPR[11];
|
||||
LOG_TODO(HLE, "Unimplemented syscall %lld: %s -> CELL_OK", code, get_ps3_function_name(~code));
|
||||
LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(ppu.GPR[11]));
|
||||
ppu.GPR[3] = 0;
|
||||
}
|
||||
|
||||
@ -45,7 +42,7 @@ void null_func(PPUThread& ppu)
|
||||
// DBG = Debug
|
||||
// PM = Product Mode
|
||||
// AuthID = Authentication ID
|
||||
const ppu_func_caller g_sc_table[1024] =
|
||||
std::array<ppu_function_t, 1024> g_ppu_syscall_table
|
||||
{
|
||||
null_func,
|
||||
BIND_FUNC(sys_process_getpid), //1 (0x001)
|
||||
@ -887,24 +884,34 @@ const ppu_func_caller g_sc_table[1024] =
|
||||
null_func, null_func, null_func, null_func, null_func, //1009 UNS
|
||||
null_func, null_func, null_func, null_func, null_func, //1014 UNS
|
||||
null_func, null_func, null_func, null_func, null_func, //1019 UNS
|
||||
null_func, null_func, null_func, BIND_FUNC(cellGcmCallback), //1023 UNS
|
||||
null_func, null_func, null_func, null_func, //1023 UNS
|
||||
};
|
||||
|
||||
void execute_syscall_by_index(PPUThread& ppu, u64 code)
|
||||
extern void ppu_execute_syscall(PPUThread& ppu, u64 code)
|
||||
{
|
||||
if (code >= 1024)
|
||||
if (code >= g_ppu_syscall_table.size())
|
||||
{
|
||||
throw EXCEPTION("Invalid syscall number (0x%llx)", code);
|
||||
throw fmt::exception("Invalid syscall number (%llu)", code);
|
||||
}
|
||||
|
||||
// If autopause occures, check_status() will hold the thread till unpaused.
|
||||
if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret;
|
||||
|
||||
const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something
|
||||
|
||||
auto last_code = ppu.hle_code;
|
||||
ppu.hle_code = ~code;
|
||||
try
|
||||
{
|
||||
g_ppu_syscall_table[code](ppu);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_WARNING(PPU, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code);
|
||||
ppu.last_function = previous_function;
|
||||
throw;
|
||||
}
|
||||
|
||||
LOG_TRACE(PPU, "Syscall %lld called: %s", code, get_ps3_function_name(~code));
|
||||
|
||||
g_sc_table[code](ppu);
|
||||
|
||||
LOG_TRACE(PPU, "Syscall %lld finished: %s -> 0x%llx", code, get_ps3_function_name(~code), ppu.GPR[3]);
|
||||
|
||||
ppu.hle_code = last_code;
|
||||
LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]);
|
||||
ppu.last_function = previous_function;
|
||||
}
|
||||
|
||||
lv2_lock_t::type::mutex_type lv2_lock_t::mutex;
|
@ -1,22 +1,20 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_mutex.h"
|
||||
#include "sys_cond.h"
|
||||
|
||||
SysCallBase sys_cond("sys_cond");
|
||||
LOG_CHANNEL(sys_cond);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread)
|
||||
void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
if (mutex->owner)
|
||||
{
|
||||
// add thread to the mutex sleep queue if cannot lock immediately
|
||||
@ -24,12 +22,10 @@ void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread)
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->owner = thread;
|
||||
mutex->owner = std::static_pointer_cast<cpu_thread>(thread->shared_from_this());
|
||||
|
||||
if (!thread->signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,9 +146,9 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread)
|
||||
const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread)
|
||||
{
|
||||
return thread->get_id() == thread_id;
|
||||
return thread->id == thread_id;
|
||||
});
|
||||
|
||||
// TODO: check if CELL_ESRCH is returned if thread_id is invalid
|
||||
@ -196,12 +192,12 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout)
|
||||
cond->mutex->unlock(lv2_lock);
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, cond->sq);
|
||||
sleep_entry<cpu_thread> waiter(cond->sq, ppu);
|
||||
|
||||
// potential mutex waiter (not added immediately)
|
||||
sleep_queue_entry_t mutex_waiter(ppu, cond->mutex->sq, defer_sleep);
|
||||
sleep_entry<cpu_thread> mutex_waiter(cond->mutex->sq, ppu, defer_sleep);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -215,7 +211,7 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout)
|
||||
// try to reown mutex and exit if timed out
|
||||
if (!cond->mutex->owner)
|
||||
{
|
||||
cond->mutex->owner = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());
|
||||
cond->mutex->owner = std::static_pointer_cast<cpu_thread>(ppu.shared_from_this());
|
||||
break;
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
struct lv2_mutex_t;
|
||||
|
||||
@ -24,7 +22,7 @@ struct lv2_cond_t
|
||||
const u64 name;
|
||||
const std::shared_ptr<lv2_mutex_t> mutex; // associated mutex
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_cond_t(const std::shared_ptr<lv2_mutex_t>& mutex, u64 name)
|
||||
: mutex(mutex)
|
||||
@ -32,7 +30,7 @@ struct lv2_cond_t
|
||||
{
|
||||
}
|
||||
|
||||
void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread);
|
||||
void notify(lv2_lock_t, cpu_thread* thread);
|
||||
};
|
||||
|
||||
class PPUThread;
|
@ -1,9 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_dbg.h"
|
||||
|
||||
SysCallBase sys_dbg("sys_dbg");
|
||||
LOG_CHANNEL(sys_dbg);
|
@ -1,49 +1,65 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Event.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_process.h"
|
||||
#include "sys_event.h"
|
||||
|
||||
SysCallBase sys_event("sys_event");
|
||||
LOG_CHANNEL(sys_event);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
lv2_event_queue_t::lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size)
|
||||
: id(idm::get_last_id())
|
||||
, protocol(protocol)
|
||||
, type(type)
|
||||
, name(name)
|
||||
, key(key)
|
||||
, size(size)
|
||||
static ipc_manager<lv2_event_queue_t>& get_ipc_manager()
|
||||
{
|
||||
// Use magic static
|
||||
static ipc_manager<lv2_event_queue_t> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3)
|
||||
std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
auto make_expr = WRAP_EXPR(idm::import<lv2_event_queue_t>(WRAP_EXPR(std::make_shared<lv2_event_queue_t>(protocol, type, name, ipc_key, size))));
|
||||
|
||||
// save event if no waiters
|
||||
if (sq.empty())
|
||||
if (ipc_key == SYS_EVENT_QUEUE_LOCAL)
|
||||
{
|
||||
return events.emplace_back(source, data1, data2, data3);
|
||||
// Not an IPC queue
|
||||
return make_expr();
|
||||
}
|
||||
|
||||
if (events.size())
|
||||
// IPC queue
|
||||
return get_ipc_manager().add(ipc_key, make_expr);
|
||||
}
|
||||
|
||||
std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::find(u64 ipc_key)
|
||||
{
|
||||
if (ipc_key == SYS_EVENT_QUEUE_LOCAL)
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
// Invalid IPC key
|
||||
return{};
|
||||
}
|
||||
|
||||
return get_ipc_manager().get(ipc_key);
|
||||
}
|
||||
|
||||
void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
Expects(m_sq.empty() || m_events.empty());
|
||||
|
||||
// save event if no waiters
|
||||
if (m_sq.empty())
|
||||
{
|
||||
return m_events.emplace_back(source, data1, data2, data3);
|
||||
}
|
||||
|
||||
// notify waiter; protocol is ignored in current implementation
|
||||
auto& thread = sq.front();
|
||||
auto& thread = m_sq.front();
|
||||
|
||||
if (type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU)
|
||||
if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
|
||||
{
|
||||
// store event data in registers
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
@ -53,7 +69,7 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da
|
||||
ppu.GPR[6] = data2;
|
||||
ppu.GPR[7] = data3;
|
||||
}
|
||||
else if (type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU)
|
||||
else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
|
||||
{
|
||||
// store event data in In_MBox
|
||||
auto& spu = static_cast<SPUThread&>(*thread);
|
||||
@ -62,15 +78,21 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", type, thread->get_type());
|
||||
throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, type, thread->type);
|
||||
}
|
||||
|
||||
if (!sq.front()->signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
|
||||
return sq.pop_front();
|
||||
return m_sq.pop_front();
|
||||
}
|
||||
|
||||
lv2_event_queue_t::event_type lv2_event_queue_t::pop(lv2_lock_t)
|
||||
{
|
||||
Expects(m_events.size());
|
||||
auto result = m_events.front();
|
||||
m_events.pop_front();
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attribute_t> attr, u64 event_queue_key, s32 size)
|
||||
@ -98,7 +120,7 @@ s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attri
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto queue = Emu.GetEventManager().MakeEventQueue(event_queue_key, protocol, type, reinterpret_cast<u64&>(attr->name), event_queue_key, size);
|
||||
const auto queue = lv2_event_queue_t::make(protocol, type, reinterpret_cast<u64&>(attr->name), event_queue_key, size);
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
@ -128,32 +150,32 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!mode && queue->sq.size())
|
||||
if (!mode && queue->waiters())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
Emu.GetEventManager().UnregisterKey(queue->key);
|
||||
idm::remove<lv2_event_queue_t>(equeue_id);
|
||||
|
||||
// signal all threads to return CELL_ECANCELED
|
||||
for (auto& thread : queue->sq)
|
||||
for (auto& thread : queue->thread_queue(lv2_lock))
|
||||
{
|
||||
if (queue->type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU)
|
||||
if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
|
||||
{
|
||||
static_cast<PPUThread&>(*thread).GPR[3] = 1;
|
||||
}
|
||||
else if (queue->type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU)
|
||||
else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
|
||||
{
|
||||
static_cast<SPUThread&>(*thread).ch_in_mbox.set_values(1, CELL_ECANCELED);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", queue->type, thread->get_type());
|
||||
throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, queue->type, thread->type);
|
||||
}
|
||||
|
||||
thread->signal();
|
||||
thread->state += cpu_state::signal;
|
||||
thread->cv.notify_one();
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -174,7 +196,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
throw EXCEPTION("Negative size");
|
||||
throw fmt::exception("Negative size (%d)" HERE, size);
|
||||
}
|
||||
|
||||
if (queue->type != SYS_PPU_QUEUE)
|
||||
@ -184,13 +206,11 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
|
||||
|
||||
s32 count = 0;
|
||||
|
||||
while (queue->sq.empty() && count < size && queue->events.size())
|
||||
while (queue->waiters() == 0 && count < size && queue->events())
|
||||
{
|
||||
auto& dest = event_array[count++];
|
||||
|
||||
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front();
|
||||
|
||||
queue->events.pop_front();
|
||||
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->pop(lv2_lock);
|
||||
}
|
||||
|
||||
*number = count;
|
||||
@ -218,13 +238,10 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (queue->events.size())
|
||||
if (queue->events())
|
||||
{
|
||||
// event data is returned in registers (dummy_event is not used)
|
||||
std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->events.front();
|
||||
|
||||
queue->events.pop_front();
|
||||
|
||||
std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->pop(lv2_lock);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -232,9 +249,9 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
|
||||
ppu.GPR[3] = 0;
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, queue->sq);
|
||||
sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -257,11 +274,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
|
||||
|
||||
if (ppu.GPR[3])
|
||||
{
|
||||
if (idm::check<lv2_event_queue_t>(equeue_id))
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
}
|
||||
|
||||
Ensures(!idm::check<lv2_event_queue_t>(equeue_id));
|
||||
return CELL_ECANCELED;
|
||||
}
|
||||
|
||||
@ -282,7 +295,7 @@ s32 sys_event_queue_drain(u32 equeue_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
queue->events.clear();
|
||||
queue->clear(lv2_lock);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -401,7 +414,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
||||
return CELL_ENOTCONN;
|
||||
}
|
||||
|
||||
if (queue->events.size() >= queue->size)
|
||||
if (queue->events() >= queue->size)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
// Event Queue Type
|
||||
enum : u32
|
||||
@ -65,23 +63,58 @@ struct sys_event_t
|
||||
be_t<u64> data3;
|
||||
};
|
||||
|
||||
struct lv2_event_queue_t
|
||||
class lv2_event_queue_t final
|
||||
{
|
||||
const u32 id;
|
||||
// Tuple elements: source, data1, data2, data3
|
||||
using event_type = std::tuple<u64, u64, u64, u64>;
|
||||
|
||||
std::deque<event_type> m_events;
|
||||
|
||||
sleep_queue<cpu_thread> m_sq;
|
||||
|
||||
public:
|
||||
// Try to make an event queue with specified global key
|
||||
static std::shared_ptr<lv2_event_queue_t> make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size);
|
||||
|
||||
// Get event queue by its global key
|
||||
static std::shared_ptr<lv2_event_queue_t> find(u64 ipc_key);
|
||||
|
||||
const u32 protocol;
|
||||
const s32 type;
|
||||
const u64 name;
|
||||
const u64 key;
|
||||
const u64 ipc_key;
|
||||
const s32 size;
|
||||
const u32 id{};
|
||||
|
||||
// tuple elements: source, data1, data2, data3
|
||||
std::deque<std::tuple<u64, u64, u64, u64>> events;
|
||||
lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
|
||||
: protocol(protocol)
|
||||
, type(type)
|
||||
, name(name)
|
||||
, ipc_key(ipc_key)
|
||||
, size(size)
|
||||
{
|
||||
}
|
||||
|
||||
sleep_queue_t sq;
|
||||
// Send an event
|
||||
void push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3);
|
||||
|
||||
lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size);
|
||||
// Receive an event (queue shouldn't be empty)
|
||||
event_type pop(lv2_lock_t);
|
||||
|
||||
void push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3);
|
||||
// Remove all events
|
||||
void clear(lv2_lock_t)
|
||||
{
|
||||
m_events.clear();
|
||||
}
|
||||
|
||||
// Get event count
|
||||
std::size_t events() const { return m_events.size(); }
|
||||
|
||||
// Get waiter count
|
||||
std::size_t waiters() const { return m_sq.size(); }
|
||||
|
||||
// Get threads (TODO)
|
||||
auto& thread_queue(lv2_lock_t) { return m_sq; }
|
||||
};
|
||||
|
||||
struct lv2_event_port_t
|
@ -1,22 +1,20 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_event_flag.h"
|
||||
|
||||
SysCallBase sys_event_flag("sys_event_flag");
|
||||
LOG_CHANNEL(sys_event_flag);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock)
|
||||
void lv2_event_flag_t::notify_all(lv2_lock_t)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
auto pred = [this](sleep_queue_t::value_type& thread) -> bool
|
||||
auto pred = [this](cpu_thread* thread) -> bool
|
||||
{
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
|
||||
@ -30,10 +28,8 @@ void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock)
|
||||
// save pattern
|
||||
ppu.GPR[4] = clear_pattern(bitptn, mode);
|
||||
|
||||
if (!ppu.signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -147,9 +143,9 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u6
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, eflag->sq);
|
||||
sleep_entry<cpu_thread> waiter(eflag->sq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -295,10 +291,8 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
|
||||
// clear "mode" as a sign of cancellation
|
||||
ppu.GPR[5] = 0;
|
||||
|
||||
if (!thread->signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
}
|
||||
|
||||
eflag->sq.clear();
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@ -37,9 +35,9 @@ struct lv2_event_flag_t
|
||||
const s32 type;
|
||||
const u64 name;
|
||||
|
||||
std::atomic<u64> pattern;
|
||||
atomic_t<u64> pattern;
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name)
|
||||
: pattern(pattern)
|
||||
@ -105,7 +103,7 @@ struct lv2_event_flag_t
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all(lv2_lock_t& lv2_lock);
|
||||
void notify_all(lv2_lock_t);
|
||||
};
|
||||
|
||||
// Aux
|
@ -1,17 +1,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/FS/VFS.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
#include "Emu/FS/vfsLocalFile.h"
|
||||
#include "Emu/FS/vfsDir.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_fs.h"
|
||||
|
||||
SysCallBase sys_fs("sys_fs");
|
||||
LOG_CHANNEL(sys_fs);
|
||||
|
||||
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
|
||||
{
|
||||
@ -31,11 +27,8 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
return CELL_FS_EINVAL;
|
||||
}
|
||||
|
||||
std::string local_path;
|
||||
|
||||
const auto device = Emu.GetVFS().GetDevice(path.get_ptr(), local_path);
|
||||
|
||||
if (!device)
|
||||
const std::string& local_path = vfs::get(path.get_ptr());
|
||||
if (local_path.empty())
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr());
|
||||
return CELL_FS_ENOTMOUNTED;
|
||||
@ -49,50 +42,50 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
return CELL_FS_EISDIR;
|
||||
}
|
||||
|
||||
u32 open_mode = 0;
|
||||
mset<fs::open_mode> open_mode{};
|
||||
|
||||
switch (flags & CELL_FS_O_ACCMODE)
|
||||
{
|
||||
case CELL_FS_O_RDONLY: open_mode |= fom::read; break;
|
||||
case CELL_FS_O_WRONLY: open_mode |= fom::write; break;
|
||||
case CELL_FS_O_RDWR: open_mode |= fom::read | fom::write; break;
|
||||
case CELL_FS_O_RDONLY: open_mode += fs::read; break;
|
||||
case CELL_FS_O_WRONLY: open_mode += fs::write; break;
|
||||
case CELL_FS_O_RDWR: open_mode += fs::read + fs::write; break;
|
||||
}
|
||||
|
||||
if (flags & CELL_FS_O_CREAT)
|
||||
{
|
||||
open_mode |= fom::create;
|
||||
open_mode += fs::create;
|
||||
}
|
||||
|
||||
if (flags & CELL_FS_O_TRUNC)
|
||||
{
|
||||
open_mode |= fom::trunc;
|
||||
open_mode += fs::trunc;
|
||||
}
|
||||
|
||||
if (flags & CELL_FS_O_APPEND)
|
||||
{
|
||||
open_mode |= fom::append;
|
||||
open_mode += fs::append;
|
||||
}
|
||||
|
||||
if (flags & CELL_FS_O_EXCL)
|
||||
{
|
||||
if (flags & CELL_FS_O_CREAT)
|
||||
{
|
||||
open_mode |= fom::excl;
|
||||
open_mode += fs::excl;
|
||||
}
|
||||
else
|
||||
{
|
||||
open_mode = 0; // error
|
||||
open_mode = {}; // error
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ~(CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL))
|
||||
{
|
||||
open_mode = 0; // error
|
||||
open_mode = {}; // error
|
||||
}
|
||||
|
||||
if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE)
|
||||
{
|
||||
open_mode = 0; // error
|
||||
open_mode = {}; // error
|
||||
}
|
||||
|
||||
if (!open_mode)
|
||||
@ -100,13 +93,13 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
throw EXCEPTION("Invalid or unimplemented flags (%#o): '%s'", flags, path.get_ptr());
|
||||
}
|
||||
|
||||
std::shared_ptr<vfsStream> file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode));
|
||||
fs::file file(local_path, open_mode);
|
||||
|
||||
if (!file || !file->IsOpened())
|
||||
if (!file)
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s'): failed to open file (flags=%#o, mode=%#o)", path.get_ptr(), flags, mode);
|
||||
|
||||
if (open_mode & fom::excl)
|
||||
if (open_mode & fs::excl)
|
||||
{
|
||||
return CELL_FS_EEXIST; // approximation
|
||||
}
|
||||
@ -122,7 +115,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
return CELL_FS_EMFILE;
|
||||
}
|
||||
|
||||
*fd = idm::get_last_id();
|
||||
*fd = _file->id;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -140,7 +133,7 @@ s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
*nread = file->file->Read(buf.get_ptr(), nbytes);
|
||||
*nread = file->file.read(buf.get_ptr(), nbytes);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -160,7 +153,7 @@ s32 sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
*nwrite = file->file->Write(buf.get_ptr(), nbytes);
|
||||
*nwrite = file->file.write(buf.get_ptr(), nbytes);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -188,9 +181,9 @@ s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::shared_ptr<vfsDirBase> dir(Emu.GetVFS().OpenDir(path.get_ptr()));
|
||||
fs::dir dir(vfs::get(path.get_ptr()));
|
||||
|
||||
if (!dir || !dir->IsOpened())
|
||||
if (!dir)
|
||||
{
|
||||
sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr());
|
||||
return CELL_FS_ENOENT;
|
||||
@ -204,7 +197,7 @@ s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
return CELL_FS_EMFILE;
|
||||
}
|
||||
|
||||
*fd = idm::get_last_id();
|
||||
*fd = _dir->id;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -220,13 +213,13 @@ s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||
return CELL_FS_EBADF;
|
||||
}
|
||||
|
||||
const DirEntryInfo* info = directory->dir->Read();
|
||||
fs::dir_entry info;
|
||||
|
||||
if (info)
|
||||
if (directory->dir.read(info))
|
||||
{
|
||||
dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY;
|
||||
dir->d_namlen = u8(std::min<size_t>(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
|
||||
strcpy_trunc(dir->d_name, info->name);
|
||||
dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
|
||||
dir->d_namlen = u8(std::min<size_t>(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
|
||||
strcpy_trunc(dir->d_name, info.name);
|
||||
*nread = sizeof(CellFsDirent);
|
||||
}
|
||||
else
|
||||
@ -258,9 +251,9 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::string local_path;
|
||||
const std::string& local_path = vfs::get(path.get_ptr());
|
||||
|
||||
if (!Emu.GetVFS().GetDevice(path.get_ptr(), local_path))
|
||||
if (local_path.empty())
|
||||
{
|
||||
sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr());
|
||||
return CELL_FS_ENOTMOUNTED;
|
||||
@ -299,20 +292,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
const auto local_file = dynamic_cast<vfsLocalFile*>(file->file.get());
|
||||
|
||||
if (!local_file)
|
||||
{
|
||||
sys_fs.error("sys_fs_fstat(fd=0x%x): not a local file");
|
||||
return CELL_FS_ENOTSUP;
|
||||
}
|
||||
|
||||
fs::stat_t info;
|
||||
|
||||
if (!local_file->GetFile().stat(info))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
const fs::stat_t& info = file->file.stat();
|
||||
|
||||
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
|
||||
sb->uid = 1; // ???
|
||||
@ -331,14 +311,14 @@ s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode)
|
||||
sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::string ps3_path = path.get_ptr();
|
||||
const std::string& local_path = vfs::get(path.get_ptr());
|
||||
|
||||
if (Emu.GetVFS().ExistsDir(ps3_path))
|
||||
if (fs::is_dir(local_path))
|
||||
{
|
||||
return CELL_FS_EEXIST;
|
||||
}
|
||||
|
||||
if (!Emu.GetVFS().CreatePath(ps3_path))
|
||||
if (!fs::create_path(local_path))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
@ -353,7 +333,7 @@ s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
|
||||
sys_fs.warning("*** from = '%s'", from.get_ptr());
|
||||
sys_fs.warning("*** to = '%s'", to.get_ptr());
|
||||
|
||||
if (!Emu.GetVFS().Rename(from.get_ptr(), to.get_ptr()))
|
||||
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
|
||||
{
|
||||
return CELL_FS_ENOENT; // ???
|
||||
}
|
||||
@ -367,15 +347,14 @@ s32 sys_fs_rmdir(vm::cptr<char> path)
|
||||
sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::string ps3_path = path.get_ptr();
|
||||
|
||||
if (!Emu.GetVFS().ExistsDir(ps3_path))
|
||||
if (!fs::remove_dir(vfs::get(path.get_ptr())))
|
||||
{
|
||||
return CELL_FS_ENOENT;
|
||||
}
|
||||
switch (auto error = errno)
|
||||
{
|
||||
case ENOENT: return CELL_FS_ENOENT;
|
||||
default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error);
|
||||
}
|
||||
|
||||
if (!Emu.GetVFS().RemoveDir(ps3_path))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
|
||||
@ -388,15 +367,14 @@ s32 sys_fs_unlink(vm::cptr<char> path)
|
||||
sys_fs.warning("sys_fs_unlink(path=*0x%x)", path);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::string ps3_path = path.get_ptr();
|
||||
|
||||
if (!Emu.GetVFS().ExistsFile(ps3_path))
|
||||
if (!fs::remove_file(vfs::get(path.get_ptr())))
|
||||
{
|
||||
return CELL_FS_ENOENT;
|
||||
}
|
||||
switch (auto error = errno)
|
||||
{
|
||||
case ENOENT: return CELL_FS_ENOENT;
|
||||
default: sys_fs.error("sys_fs_unlink(): unknown error %d", error);
|
||||
}
|
||||
|
||||
if (!Emu.GetVFS().RemoveFile(ps3_path))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
|
||||
@ -417,7 +395,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
|
||||
if (whence >= 3)
|
||||
{
|
||||
sys_fs.error("sys_fs_lseek(): unknown seek whence (%d)", whence);
|
||||
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
|
||||
return CELL_FS_EINVAL;
|
||||
}
|
||||
|
||||
@ -430,7 +408,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
*pos = file->file->Seek(offset, (fs::seek_mode)whence);
|
||||
*pos = file->file.seek(offset, static_cast<fs::seek_mode>(whence));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -468,15 +446,14 @@ s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
|
||||
sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
std::string ps3_path = path.get_ptr();
|
||||
|
||||
if (!Emu.GetVFS().ExistsFile(ps3_path))
|
||||
if (!fs::truncate_file(vfs::get(path.get_ptr()), size))
|
||||
{
|
||||
return CELL_FS_ENOENT;
|
||||
}
|
||||
switch (auto error = errno)
|
||||
{
|
||||
case ENOENT: return CELL_FS_ENOENT;
|
||||
default: sys_fs.error("sys_fs_truncate(): unknown error %d", error);
|
||||
}
|
||||
|
||||
if (!Emu.GetVFS().TruncateFile(ps3_path, size))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
|
||||
@ -496,16 +473,14 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
const auto local_file = dynamic_cast<vfsLocalFile*>(file->file.get());
|
||||
|
||||
if (!local_file)
|
||||
if (!file->file.trunc(size))
|
||||
{
|
||||
sys_fs.error("sys_fs_ftruncate(fd=0x%x): not a local file");
|
||||
return CELL_FS_ENOTSUP;
|
||||
}
|
||||
switch (auto error = errno)
|
||||
{
|
||||
case 0:
|
||||
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);
|
||||
}
|
||||
|
||||
if (!local_file->GetFile().trunc(size))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
}
|
||||
|
@ -148,8 +148,6 @@ struct CellFsUtimbuf
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct vfsStream;
|
||||
|
||||
// Stream Support Status (st_status)
|
||||
enum : u32
|
||||
{
|
||||
@ -161,16 +159,26 @@ enum : u32
|
||||
|
||||
using fs_st_cb_t = vm::ptr<void(u32 xfd, u64 xsize)>;
|
||||
|
||||
struct fs_st_cb_rec_t
|
||||
struct alignas(16) fs_st_cb_rec_t
|
||||
{
|
||||
u64 size;
|
||||
fs_st_cb_t func;
|
||||
u32 pad;
|
||||
};
|
||||
|
||||
struct lv2_file_t
|
||||
struct lv2_fs_object_t
|
||||
{
|
||||
const std::shared_ptr<vfsStream> file;
|
||||
using id_base = lv2_fs_object_t;
|
||||
|
||||
static constexpr u32 id_min = 3;
|
||||
static constexpr u32 id_max = 255;
|
||||
|
||||
const u32 id{};
|
||||
};
|
||||
|
||||
struct lv2_file_t : lv2_fs_object_t
|
||||
{
|
||||
const fs::file file;
|
||||
const s32 mode;
|
||||
const s32 flags;
|
||||
|
||||
@ -188,12 +196,12 @@ struct lv2_file_t
|
||||
|
||||
u32 st_buffer;
|
||||
u64 st_read_size;
|
||||
std::atomic<u64> st_total_read;
|
||||
std::atomic<u64> st_copied;
|
||||
atomic_t<u64> st_total_read;
|
||||
atomic_t<u64> st_copied;
|
||||
|
||||
atomic_t<fs_st_cb_rec_t> st_callback;
|
||||
|
||||
lv2_file_t(std::shared_ptr<vfsStream> file, s32 mode, s32 flags)
|
||||
lv2_file_t(fs::file file, s32 mode, s32 flags)
|
||||
: file(std::move(file))
|
||||
, mode(mode)
|
||||
, flags(flags)
|
||||
@ -203,42 +211,16 @@ struct lv2_file_t
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct id_traits<lv2_file_t>
|
||||
struct lv2_dir_t : lv2_fs_object_t
|
||||
{
|
||||
static const u32 base = 0xfddd0000, max = 255;
|
||||
const fs::dir dir;
|
||||
|
||||
static u32 next_id(u32 raw_id)
|
||||
{
|
||||
return
|
||||
raw_id < 0x80000000 ? base + 3 :
|
||||
raw_id - base < max ? raw_id + 1 : 0;
|
||||
}
|
||||
|
||||
static u32 in_id(u32 id)
|
||||
{
|
||||
return id + base;
|
||||
}
|
||||
|
||||
static u32 out_id(u32 raw_id)
|
||||
{
|
||||
return raw_id - base;
|
||||
}
|
||||
};
|
||||
|
||||
class vfsDirBase;
|
||||
|
||||
struct lv2_dir_t
|
||||
{
|
||||
const std::shared_ptr<vfsDirBase> dir;
|
||||
|
||||
lv2_dir_t(std::shared_ptr<vfsDirBase> dir)
|
||||
lv2_dir_t(fs::dir dir)
|
||||
: dir(std::move(dir))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct id_traits<lv2_dir_t> : public id_traits<lv2_file_t> {};
|
||||
|
||||
// SysCalls
|
||||
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6);
|
||||
s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size);
|
@ -1,36 +1,24 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_interrupt.h"
|
||||
|
||||
SysCallBase sys_interrupt("sys_interrupt");
|
||||
LOG_CHANNEL(sys_interrupt);
|
||||
|
||||
lv2_int_tag_t::lv2_int_tag_t()
|
||||
: id(idm::get_last_id())
|
||||
void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock)
|
||||
{
|
||||
}
|
||||
|
||||
lv2_int_serv_t::lv2_int_serv_t(const std::shared_ptr<PPUThread>& thread)
|
||||
: thread(thread)
|
||||
, id(idm::get_last_id())
|
||||
{
|
||||
}
|
||||
|
||||
void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
// Use is_joining to stop interrupt thread and signal
|
||||
thread->is_joining = true;
|
||||
|
||||
thread->cv.notify_one();
|
||||
|
||||
// Start joining
|
||||
while (thread->is_alive())
|
||||
while (!(thread->state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -39,7 +27,7 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock)
|
||||
|
||||
// Cleanup
|
||||
idm::remove<lv2_int_serv_t>(id);
|
||||
idm::remove<PPUThread>(thread->get_id());
|
||||
idm::remove<PPUThread>(thread->id);
|
||||
}
|
||||
|
||||
s32 sys_interrupt_tag_destroy(u32 intrtag)
|
||||
@ -88,7 +76,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
|
||||
}
|
||||
|
||||
// If interrupt thread is running, it's already established on another interrupt tag
|
||||
if (!it->is_stopped())
|
||||
if (!(it->state & cpu_state::stop))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
@ -137,10 +125,11 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
|
||||
ppu.cv.wait(lv2_lock);
|
||||
}
|
||||
|
||||
ppu.exit();
|
||||
ppu.state += cpu_state::exit;
|
||||
};
|
||||
|
||||
it->exec();
|
||||
it->state -= cpu_state::stop;
|
||||
it->safe_notify();
|
||||
|
||||
*ih = handler->id;
|
||||
|
||||
@ -177,5 +166,5 @@ void sys_interrupt_thread_eoi(PPUThread& ppu)
|
||||
|
||||
ppu.GPR[1] = align(ppu.stack_addr + ppu.stack_size, 0x200) - 0x200; // supercrutch to bypass stack check
|
||||
|
||||
ppu.fast_stop();
|
||||
ppu.state += cpu_state::ret;
|
||||
}
|
@ -1,28 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
class PPUThread;
|
||||
|
||||
struct lv2_int_tag_t
|
||||
{
|
||||
const u32 id;
|
||||
const u32 id{};
|
||||
|
||||
std::shared_ptr<struct lv2_int_serv_t> handler;
|
||||
|
||||
lv2_int_tag_t();
|
||||
};
|
||||
|
||||
struct lv2_int_serv_t
|
||||
{
|
||||
const std::shared_ptr<PPUThread> thread;
|
||||
const u32 id;
|
||||
const u32 id{};
|
||||
|
||||
std::atomic<u32> signal{ 0 }; // signal count
|
||||
atomic_t<u32> signal{ 0 }; // signal count
|
||||
|
||||
lv2_int_serv_t(const std::shared_ptr<PPUThread>& thread);
|
||||
lv2_int_serv_t(const std::shared_ptr<PPUThread>& thread)
|
||||
: thread(thread)
|
||||
{
|
||||
}
|
||||
|
||||
void join(PPUThread& ppu, lv2_lock_t& lv2_lock);
|
||||
void join(PPUThread& ppu, lv2_lock_t);
|
||||
};
|
||||
|
||||
// SysCalls
|
@ -1,21 +1,20 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_lwmutex.h"
|
||||
#include "sys_lwcond.h"
|
||||
|
||||
SysCallBase sys_lwcond("sys_lwcond");
|
||||
LOG_CHANNEL(sys_lwcond);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr<lv2_lwmutex_t>& mutex, bool mode2)
|
||||
void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<lv2_lwmutex_t>& mutex, bool mode2)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
|
||||
ppu.GPR[3] = mode2; // set to return CELL_EBUSY
|
||||
@ -30,10 +29,8 @@ void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thre
|
||||
mutex->signaled--;
|
||||
}
|
||||
|
||||
if (!ppu.signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
}
|
||||
|
||||
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5)
|
||||
@ -92,9 +89,9 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod
|
||||
// mode 3: lightweight mutex was forcefully owned by the calling thread
|
||||
|
||||
// pick waiter; protocol is ignored in current implementation
|
||||
const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread)
|
||||
const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread)
|
||||
{
|
||||
return thread->get_id() == ppu_thread_id;
|
||||
return thread->id == ppu_thread_id;
|
||||
});
|
||||
|
||||
if (found == cond->sq.end())
|
||||
@ -177,12 +174,12 @@ s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 ti
|
||||
mutex->unlock(lv2_lock);
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, cond->sq);
|
||||
sleep_entry<cpu_thread> waiter(cond->sq, ppu);
|
||||
|
||||
// potential mutex waiter (not added immediately)
|
||||
sleep_queue_entry_t mutex_waiter(ppu, cond->sq, defer_sleep);
|
||||
sleep_entry<cpu_thread> mutex_waiter(cond->sq, ppu, defer_sleep);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
@ -21,14 +21,14 @@ struct lv2_lwcond_t
|
||||
{
|
||||
const u64 name;
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_lwcond_t(u64 name)
|
||||
: name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr<lv2_lwmutex_t>& mutex, bool mode2);
|
||||
void notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<lv2_lwmutex_t>& mutex, bool mode2);
|
||||
};
|
||||
|
||||
// Aux
|
@ -1,21 +1,19 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_lwmutex.h"
|
||||
|
||||
SysCallBase sys_lwmutex("sys_lwmutex");
|
||||
LOG_CHANNEL(sys_lwmutex);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock)
|
||||
void lv2_lwmutex_t::unlock(lv2_lock_t)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
if (signaled)
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
@ -23,10 +21,9 @@ void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock)
|
||||
|
||||
if (sq.size())
|
||||
{
|
||||
if (!sq.front()->signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
auto& thread = sq.front();
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
|
||||
sq.pop_front();
|
||||
}
|
||||
@ -102,9 +99,9 @@ s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout)
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, mutex->sq);
|
||||
sleep_entry<cpu_thread> waiter(mutex->sq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
struct sys_lwmutex_attribute_t
|
||||
{
|
||||
@ -20,7 +18,7 @@ enum : u32
|
||||
|
||||
struct sys_lwmutex_t
|
||||
{
|
||||
struct sync_var_t
|
||||
struct alignas(8) sync_var_t
|
||||
{
|
||||
be_t<u32> owner;
|
||||
be_t<u32> waiter;
|
||||
@ -52,9 +50,9 @@ struct lv2_lwmutex_t
|
||||
const u64 name;
|
||||
|
||||
// this object is not truly a mutex and its syscall names may be wrong, it's probably a sleep queue or something
|
||||
std::atomic<u32> signaled{ 0 };
|
||||
atomic_t<u32> signaled{ 0 };
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_lwmutex_t(u32 protocol, u64 name)
|
||||
: protocol(protocol)
|
||||
@ -62,7 +60,7 @@ struct lv2_lwmutex_t
|
||||
{
|
||||
}
|
||||
|
||||
void unlock(lv2_lock_t& lv2_lock);
|
||||
void unlock(lv2_lock_t);
|
||||
};
|
||||
|
||||
// Aux
|
@ -1,18 +1,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_memory.h"
|
||||
|
||||
SysCallBase sys_memory("sys_memory");
|
||||
|
||||
lv2_memory_container_t::lv2_memory_container_t(u32 size)
|
||||
: size(size)
|
||||
, id(idm::get_last_id())
|
||||
{
|
||||
}
|
||||
LOG_CHANNEL(sys_memory);
|
||||
|
||||
s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
enum : u32
|
||||
{
|
||||
@ -42,18 +42,23 @@ struct sys_page_attr_t
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
#include <map>
|
||||
|
||||
struct lv2_memory_container_t
|
||||
{
|
||||
const u32 size; // amount of "physical" memory in this container
|
||||
const u32 id;
|
||||
const u32 id{};
|
||||
|
||||
// amount of memory allocated
|
||||
std::atomic<u32> used{ 0 };
|
||||
atomic_t<u32> used{ 0 };
|
||||
|
||||
// allocations (addr -> size)
|
||||
std::map<u32, u32> allocs;
|
||||
|
||||
lv2_memory_container_t(u32 size);
|
||||
lv2_memory_container_t(u32 size)
|
||||
: size(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// SysCalls
|
@ -1,21 +1,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_mmapper.h"
|
||||
|
||||
SysCallBase sys_mmapper("sys_mmapper");
|
||||
|
||||
lv2_memory_t::lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct)
|
||||
: size(size)
|
||||
, align(align)
|
||||
, id(idm::get_last_id())
|
||||
, flags(flags)
|
||||
, ct(ct)
|
||||
{
|
||||
}
|
||||
LOG_CHANNEL(sys_mmapper);
|
||||
|
||||
s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
|
||||
{
|
@ -2,19 +2,23 @@
|
||||
|
||||
#include "sys_memory.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
struct lv2_memory_t
|
||||
{
|
||||
const u32 size; // memory size
|
||||
const u32 align; // required alignment
|
||||
const u32 id;
|
||||
const u64 flags;
|
||||
const std::shared_ptr<lv2_memory_container_t> ct; // memory container the physical memory is taken from
|
||||
const u32 id{};
|
||||
|
||||
std::atomic<u32> addr{ 0 }; // actual mapping address
|
||||
atomic_t<u32> addr{ 0 }; // actual mapping address
|
||||
|
||||
lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct);
|
||||
lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct)
|
||||
: size(size)
|
||||
, align(align)
|
||||
, flags(flags)
|
||||
, ct(ct)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// SysCalls
|
@ -1,32 +1,28 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_mutex.h"
|
||||
|
||||
SysCallBase sys_mutex("sys_mutex");
|
||||
LOG_CHANNEL(sys_mutex);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_mutex_t::unlock(lv2_lock_t& lv2_lock)
|
||||
void lv2_mutex_t::unlock(lv2_lock_t)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
owner.reset();
|
||||
|
||||
if (sq.size())
|
||||
{
|
||||
// pick new owner; protocol is ignored in current implementation
|
||||
owner = sq.front();
|
||||
owner = std::static_pointer_cast<cpu_thread>(sq.front()->shared_from_this());
|
||||
|
||||
if (!owner->signal())
|
||||
{
|
||||
throw EXCEPTION("Mutex owner already signaled");
|
||||
}
|
||||
ASSERT(!owner->state.test_and_set(cpu_state::signal));
|
||||
owner->cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,15 +128,15 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout)
|
||||
// lock immediately if not locked
|
||||
if (!mutex->owner)
|
||||
{
|
||||
mutex->owner = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());
|
||||
mutex->owner = std::static_pointer_cast<cpu_thread>(ppu.shared_from_this());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, mutex->sq);
|
||||
sleep_entry<cpu_thread> waiter(mutex->sq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -207,7 +203,7 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id)
|
||||
}
|
||||
|
||||
// own the mutex if free
|
||||
mutex->owner = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());
|
||||
mutex->owner = std::static_pointer_cast<cpu_thread>(ppu.shared_from_this());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
struct sys_mutex_attribute_t
|
||||
{
|
||||
@ -27,11 +25,11 @@ struct lv2_mutex_t
|
||||
const u32 protocol;
|
||||
const u64 name;
|
||||
|
||||
std::atomic<u32> cond_count{ 0 }; // count of condition variables associated
|
||||
std::atomic<u32> recursive_count{ 0 }; // count of recursive locks
|
||||
std::shared_ptr<CPUThread> owner; // current mutex owner
|
||||
atomic_t<u32> cond_count{ 0 }; // count of condition variables associated
|
||||
atomic_t<u32> recursive_count{ 0 }; // count of recursive locks
|
||||
std::shared_ptr<cpu_thread> owner; // current mutex owner
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_mutex_t(bool recursive, u32 protocol, u64 name)
|
||||
: recursive(recursive)
|
||||
@ -40,7 +38,7 @@ struct lv2_mutex_t
|
||||
{
|
||||
}
|
||||
|
||||
void unlock(lv2_lock_t& lv2_lock);
|
||||
void unlock(lv2_lock_t);
|
||||
};
|
||||
|
||||
class PPUThread;
|
@ -1,14 +1,15 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_mutex.h"
|
||||
#include "sys_ppu_thread.h"
|
||||
|
||||
SysCallBase sys_ppu_thread("sys_ppu_thread");
|
||||
LOG_CHANNEL(sys_ppu_thread);
|
||||
|
||||
void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode)
|
||||
{
|
||||
@ -28,17 +29,17 @@ void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode)
|
||||
|
||||
if (!ppu.is_joinable)
|
||||
{
|
||||
idm::remove<PPUThread>(ppu.get_id());
|
||||
idm::remove<PPUThread>(ppu.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.exit();
|
||||
ppu.state += cpu_state::exit;
|
||||
}
|
||||
|
||||
// Throw if this syscall was not called directly by the SC instruction
|
||||
if (~ppu.hle_code != 41)
|
||||
// Throw if this syscall was not called directly by the SC instruction (hack)
|
||||
if (ppu.GPR[11] != 41 || ppu.custom_task)
|
||||
{
|
||||
throw CPUThreadExit{};
|
||||
throw cpu_state::exit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +77,7 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
thread->is_joining = true;
|
||||
|
||||
// join thread
|
||||
while (thread->is_alive())
|
||||
while (!(thread->state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -84,10 +85,10 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
}
|
||||
|
||||
// get exit status from the register
|
||||
*vptr = thread->GPR[3];
|
||||
if (vptr) *vptr = thread->GPR[3];
|
||||
|
||||
// cleanup
|
||||
idm::remove<PPUThread>(thread->get_id());
|
||||
idm::remove<PPUThread>(thread->id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -225,7 +226,7 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st
|
||||
ppu->prio = prio;
|
||||
ppu->stack_size = stacksize;
|
||||
ppu->custom_task = std::move(task);
|
||||
ppu->run();
|
||||
ppu->cpu_init();
|
||||
|
||||
if (entry)
|
||||
{
|
||||
@ -234,9 +235,10 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st
|
||||
}
|
||||
|
||||
ppu->GPR[3] = arg;
|
||||
ppu->exec();
|
||||
ppu->state -= cpu_state::stop;
|
||||
ppu->safe_notify();
|
||||
|
||||
return ppu->get_id();
|
||||
return ppu->id;
|
||||
}
|
||||
|
||||
s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
|
||||
@ -263,21 +265,17 @@ s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> p
|
||||
|
||||
ppu->prio = prio;
|
||||
ppu->stack_size = std::max<u32>(stacksize, 0x4000);
|
||||
ppu->run();
|
||||
ppu->cpu_init();
|
||||
|
||||
ppu->PC = vm::read32(param->entry);
|
||||
ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc
|
||||
ppu->GPR[3] = arg;
|
||||
ppu->GPR[4] = unk; // actually unknown
|
||||
ppu->GPR[13] = param->tls;
|
||||
|
||||
ppu->is_joinable = is_joinable;
|
||||
|
||||
if (u32 tls = param->tls) // hack
|
||||
{
|
||||
ppu->GPR[13] = tls;
|
||||
}
|
||||
|
||||
*thread_id = ppu->get_id();
|
||||
*thread_id = ppu->id;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -295,7 +293,8 @@ s32 sys_ppu_thread_start(u32 thread_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
thread->exec();
|
||||
thread->state -= cpu_state::stop;
|
||||
thread->safe_notify();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/FS/VFS.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
#include "Loader/PSF.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_lwmutex.h"
|
||||
#include "sys_lwcond.h"
|
||||
#include "sys_mutex.h"
|
||||
@ -24,7 +22,7 @@
|
||||
#include "sys_fs.h"
|
||||
#include "sys_process.h"
|
||||
|
||||
SysCallBase sys_process("sys_process");
|
||||
LOG_CHANNEL(sys_process);
|
||||
|
||||
s32 process_getpid()
|
||||
{
|
@ -1,142 +1,32 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/CB_FUNC.h"
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
#include "Emu/SysCalls/ModuleManager.h"
|
||||
#include "Emu/Cell/PPUInstrTable.h"
|
||||
|
||||
#include "Emu/FS/VFS.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Loader/ELF64.h"
|
||||
#include "Loader/ELF.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_prx.h"
|
||||
|
||||
SysCallBase sys_prx("sys_prx");
|
||||
|
||||
lv2_prx_t::lv2_prx_t()
|
||||
: id(idm::get_last_id())
|
||||
{
|
||||
}
|
||||
LOG_CHANNEL(sys_prx);
|
||||
|
||||
s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
||||
{
|
||||
sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt);
|
||||
|
||||
loader::handlers::elf64 loader;
|
||||
const ppu_prx_loader loader = fs::file(vfs::get(path));
|
||||
|
||||
vfsFile f(path);
|
||||
if (!f.IsOpened())
|
||||
{
|
||||
return CELL_PRX_ERROR_UNKNOWN_MODULE;
|
||||
}
|
||||
|
||||
if (loader.init(f) != loader::handler::error_code::ok || !loader.is_sprx())
|
||||
if (loader != elf_error::ok)
|
||||
{
|
||||
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
||||
}
|
||||
|
||||
loader::handlers::elf64::sprx_info info;
|
||||
loader.load_sprx(info);
|
||||
const auto prx = loader.load();
|
||||
|
||||
auto prx = idm::make_ptr<lv2_prx_t>();
|
||||
|
||||
auto meta = info.modules[""];
|
||||
prx->start.set(meta.exports[0xBC9A0086]);
|
||||
prx->stop.set(meta.exports[0xAB779874]);
|
||||
prx->exit.set(meta.exports[0x3AB9A95E]);
|
||||
|
||||
for (auto &module_ : info.modules)
|
||||
if (!prx)
|
||||
{
|
||||
if (module_.first == "")
|
||||
continue;
|
||||
|
||||
Module<>* module = Emu.GetModuleManager().GetModuleByName(module_.first.c_str());
|
||||
|
||||
if (!module)
|
||||
{
|
||||
sys_prx.error("Unknown module '%s'", module_.first.c_str());
|
||||
}
|
||||
|
||||
for (auto& f : module_.second.exports)
|
||||
{
|
||||
const u32 nid = f.first;
|
||||
const u32 addr = f.second;
|
||||
|
||||
u32 index;
|
||||
|
||||
auto func = get_ppu_func_by_nid(nid, &index);
|
||||
|
||||
if (!func)
|
||||
{
|
||||
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr<void()>::make(addr)));
|
||||
}
|
||||
else
|
||||
{
|
||||
func->lle_func.set(addr);
|
||||
|
||||
if (func->flags & MFF_FORCED_HLE)
|
||||
{
|
||||
u32 i_addr = 0;
|
||||
|
||||
if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4))
|
||||
{
|
||||
sys_prx.error("Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::write32(i_addr, PPU_instr::HACK(index | EIF_PERFORM_BLR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &import : module_.second.imports)
|
||||
{
|
||||
u32 nid = import.first;
|
||||
u32 addr = import.second;
|
||||
|
||||
u32 index;
|
||||
|
||||
auto func = get_ppu_func_by_nid(nid, &index);
|
||||
|
||||
if (!func)
|
||||
{
|
||||
sys_prx.error("Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_.first);
|
||||
|
||||
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE);
|
||||
|
||||
sys_prx.error("Imported %sfunction '%s' in '%s' module (0x%x)", (is_lle ? "LLE " : ""), get_ps3_function_name(nid), module_.first, addr);
|
||||
}
|
||||
|
||||
if (!patch_ppu_import(addr, index))
|
||||
{
|
||||
sys_prx.error("Failed to inject code at address 0x%x", addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto decoder_cache = fxm::get<ppu_decoder_cache_t>();
|
||||
|
||||
for (auto& seg : info.segments)
|
||||
{
|
||||
const u32 addr = seg.begin.addr();
|
||||
const u32 size = align(seg.size, 4096);
|
||||
|
||||
if (vm::check_addr(addr, size))
|
||||
{
|
||||
decoder_cache->initialize(addr, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_prx.error("Failed to process executable area (addr=0x%x, size=0x%x)", addr, size);
|
||||
}
|
||||
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
||||
}
|
||||
|
||||
return prx->id;
|
@ -30,114 +30,21 @@ enum
|
||||
CELL_PRX_ERROR_ELF_IS_REGISTERED = 0x80011910, // Fixed ELF is already registered
|
||||
};
|
||||
|
||||
struct sys_stub
|
||||
{
|
||||
u8 s_size; // = 0x2c
|
||||
u8 s_unk0;
|
||||
be_t<u16> s_version; // = 0x1
|
||||
be_t<u16> s_unk1; // = 0x9 // flags?
|
||||
be_t<u16> s_imports;
|
||||
be_t<u32> s_unk2; // = 0x0
|
||||
be_t<u32> s_unk3; // = 0x0
|
||||
vm::bcptr<char> s_modulename;
|
||||
vm::bptr<u32> s_nid;
|
||||
vm::bptr<u32> s_text;
|
||||
be_t<u32> s_unk4; // = 0x0
|
||||
be_t<u32> s_unk5; // = 0x0
|
||||
be_t<u32> s_unk6; // = 0x0
|
||||
be_t<u32> s_unk7; // = 0x0
|
||||
};
|
||||
|
||||
struct sys_proc_prx_param
|
||||
{
|
||||
be_t<u32> size;
|
||||
be_t<u32> magic;
|
||||
be_t<u32> version;
|
||||
be_t<u32> pad0;
|
||||
be_t<u32> libentstart;
|
||||
be_t<u32> libentend;
|
||||
vm::bptr<sys_stub> libstubstart;
|
||||
vm::bptr<sys_stub> libstubend;
|
||||
be_t<u16> ver;
|
||||
be_t<u16> pad1;
|
||||
be_t<u32> pad2;
|
||||
};
|
||||
|
||||
// Information about imported or exported libraries in PRX modules
|
||||
struct sys_prx_library_info_t
|
||||
{
|
||||
u8 size;
|
||||
u8 unk0;
|
||||
be_t<u16> version;
|
||||
be_t<u16> attributes;
|
||||
be_t<u16> num_func;
|
||||
be_t<u16> num_var;
|
||||
be_t<u16> num_tlsvar;
|
||||
u8 info_hash;
|
||||
u8 info_tlshash;
|
||||
u8 unk1[2];
|
||||
be_t<u32> name_addr;
|
||||
be_t<u32> fnid_addr;
|
||||
be_t<u32> fstub_addr;
|
||||
be_t<u32> unk4;
|
||||
be_t<u32> unk5;
|
||||
be_t<u32> unk6;
|
||||
be_t<u32> unk7;
|
||||
};
|
||||
|
||||
// ELF file headers
|
||||
struct sys_prx_param_t
|
||||
{
|
||||
be_t<u32> size;
|
||||
be_t<u32> magic;
|
||||
be_t<u32> version;
|
||||
be_t<u32> unk0;
|
||||
be_t<u32> libentstart;
|
||||
be_t<u32> libentend;
|
||||
vm::bptr<sys_prx_library_info_t> libstubstart;
|
||||
vm::bptr<sys_prx_library_info_t> libstubend;
|
||||
be_t<u16> ver;
|
||||
be_t<u16> unk1;
|
||||
be_t<u32> unk2;
|
||||
};
|
||||
|
||||
struct sys_prx_get_module_id_by_name_option_t
|
||||
{
|
||||
be_t<u64> size;
|
||||
vm::ptr<void> base;
|
||||
};
|
||||
|
||||
// PRX file headers
|
||||
struct sys_prx_module_info_t
|
||||
{
|
||||
be_t<u16> attributes;
|
||||
be_t<u16> version;
|
||||
char name[28];
|
||||
be_t<u32> toc;
|
||||
vm::bptr<sys_prx_library_info_t> exports_start;
|
||||
vm::bptr<sys_prx_library_info_t> exports_end;
|
||||
be_t<u32> imports_start;
|
||||
be_t<u32> imports_end;
|
||||
};
|
||||
|
||||
// Relocation information of the SCE_PPURELA segment
|
||||
struct sys_prx_relocation_info_t
|
||||
{
|
||||
be_t<u64> offset;
|
||||
be_t<u16> unk0;
|
||||
u8 index_value;
|
||||
u8 index_addr;
|
||||
be_t<u32> type;
|
||||
vm::bptr<void, u64> ptr;
|
||||
};
|
||||
|
||||
// Data types
|
||||
struct sys_prx_load_module_option_t
|
||||
{
|
||||
be_t<u64> size;
|
||||
vm::bptr<void> base_addr;
|
||||
};
|
||||
|
||||
struct sys_prx_segment_info_t;// TODO
|
||||
struct sys_prx_module_info_t;// TODO
|
||||
|
||||
struct sys_prx_start_module_option_t
|
||||
{
|
||||
be_t<u64> size;
|
||||
@ -165,18 +72,17 @@ struct sys_prx_get_module_list_t
|
||||
vm::bptr<s32> idlist;
|
||||
};
|
||||
|
||||
// Auxiliary data types
|
||||
struct lv2_prx_t
|
||||
{
|
||||
const u32 id;
|
||||
const u32 id{};
|
||||
|
||||
bool is_started = false;
|
||||
|
||||
std::unordered_map<u32, u32> specials;
|
||||
|
||||
vm::ptr<s32(int argc, vm::ptr<void> argv)> start = vm::null;
|
||||
vm::ptr<s32(int argc, vm::ptr<void> argv)> stop = vm::null;
|
||||
vm::ptr<s32()> exit = vm::null;
|
||||
|
||||
lv2_prx_t();
|
||||
};
|
||||
|
||||
// SysCalls
|
@ -1,11 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_rsx.h"
|
||||
|
||||
SysCallBase sys_rsx("sys_rsx");
|
||||
LOG_CHANNEL(sys_rsx);
|
||||
|
||||
s32 sys_rsx_device_open()
|
||||
{
|
@ -1,30 +1,26 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_rwlock.h"
|
||||
|
||||
SysCallBase sys_rwlock("sys_rwlock");
|
||||
LOG_CHANNEL(sys_rwlock);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock)
|
||||
void lv2_rwlock_t::notify_all(lv2_lock_t)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
// pick a new writer if possible; protocol is ignored in current implementation
|
||||
if (!readers && !writer && wsq.size())
|
||||
{
|
||||
writer = wsq.front();
|
||||
writer = std::static_pointer_cast<cpu_thread>(wsq.front()->shared_from_this());
|
||||
|
||||
if (!writer->signal())
|
||||
{
|
||||
throw EXCEPTION("Writer already signaled");
|
||||
}
|
||||
ASSERT(!writer->state.test_and_set(cpu_state::signal));
|
||||
writer->cv.notify_one();
|
||||
|
||||
return wsq.pop_front();
|
||||
}
|
||||
@ -36,10 +32,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock)
|
||||
|
||||
for (auto& thread : rsq)
|
||||
{
|
||||
if (!thread->signal())
|
||||
{
|
||||
throw EXCEPTION("Reader already signaled");
|
||||
}
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
}
|
||||
|
||||
return rsq.clear();
|
||||
@ -123,9 +117,9 @@ s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, rwlock->rsq);
|
||||
sleep_entry<cpu_thread> waiter(rwlock->rsq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -228,15 +222,15 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
|
||||
if (!rwlock->readers && !rwlock->writer)
|
||||
{
|
||||
rwlock->writer = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());
|
||||
rwlock->writer = std::static_pointer_cast<cpu_thread>(ppu.shared_from_this());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, rwlock->wsq);
|
||||
sleep_entry<cpu_thread> waiter(rwlock->wsq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -249,7 +243,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
// if the last waiter quit the writer sleep queue, readers must acquire the lock
|
||||
if (!rwlock->writer && rwlock->wsq.size() == 1)
|
||||
{
|
||||
if (rwlock->wsq.front().get() != &ppu)
|
||||
if (rwlock->wsq.front() != &ppu)
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
}
|
||||
@ -300,7 +294,7 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
rwlock->writer = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());
|
||||
rwlock->writer = std::static_pointer_cast<cpu_thread>(ppu.shared_from_this());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
struct sys_rwlock_attribute_t
|
||||
{
|
||||
@ -24,11 +22,11 @@ struct lv2_rwlock_t
|
||||
const u64 name;
|
||||
const u32 protocol;
|
||||
|
||||
std::atomic<u32> readers{ 0 }; // reader lock count
|
||||
std::shared_ptr<CPUThread> writer; // writer lock owner
|
||||
atomic_t<u32> readers{ 0 }; // reader lock count
|
||||
std::shared_ptr<cpu_thread> writer; // writer lock owner
|
||||
|
||||
sleep_queue_t rsq; // threads trying to acquire readed lock
|
||||
sleep_queue_t wsq; // threads trying to acquire writer lock
|
||||
sleep_queue<cpu_thread> rsq; // threads trying to acquire readed lock
|
||||
sleep_queue<cpu_thread> wsq; // threads trying to acquire writer lock
|
||||
|
||||
lv2_rwlock_t(u32 protocol, u64 name)
|
||||
: protocol(protocol)
|
||||
@ -36,7 +34,7 @@ struct lv2_rwlock_t
|
||||
{
|
||||
}
|
||||
|
||||
void notify_all(lv2_lock_t& lv2_lock);
|
||||
void notify_all(lv2_lock_t);
|
||||
};
|
||||
|
||||
// Aux
|
@ -1,14 +1,14 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "sys_sync.h"
|
||||
#include "sys_semaphore.h"
|
||||
|
||||
SysCallBase sys_semaphore("sys_semaphore");
|
||||
LOG_CHANNEL(sys_semaphore);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
@ -92,9 +92,9 @@ s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout)
|
||||
}
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_queue_entry_t waiter(ppu, sem->sq);
|
||||
sleep_entry<cpu_thread> waiter(sem->sq, ppu);
|
||||
|
||||
while (!ppu.unsignal())
|
||||
while (!ppu.state.test_and_reset(cpu_state::signal))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -173,10 +173,9 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
|
||||
{
|
||||
count--;
|
||||
|
||||
if (!sem->sq.front()->signal())
|
||||
{
|
||||
throw EXCEPTION("Thread already signaled");
|
||||
}
|
||||
auto& thread = sem->sq.front();
|
||||
ASSERT(!thread->state.test_and_set(cpu_state::signal));
|
||||
thread->cv.notify_one();
|
||||
|
||||
sem->sq.pop_front();
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
struct sys_semaphore_attribute_t
|
||||
{
|
||||
@ -25,9 +23,9 @@ struct lv2_sema_t
|
||||
const s32 max;
|
||||
const u64 name;
|
||||
|
||||
std::atomic<s32> value;
|
||||
atomic_t<s32> value;
|
||||
|
||||
sleep_queue_t sq;
|
||||
sleep_queue<cpu_thread> sq;
|
||||
|
||||
lv2_sema_t(u32 protocol, s32 max, u64 name, s32 value)
|
||||
: protocol(protocol)
|
@ -1,30 +1,40 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/CPU/CPUThreadManager.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include "Emu/FS/vfsStreamMemory.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
#include "Loader/ELF32.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Loader/ELF.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include "sys_interrupt.h"
|
||||
#include "sys_event.h"
|
||||
#include "sys_spu.h"
|
||||
|
||||
SysCallBase sys_spu("sys_spu");
|
||||
LOG_CHANNEL(sys_spu);
|
||||
|
||||
void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr)
|
||||
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
|
||||
{
|
||||
loader::handlers::elf32 h;
|
||||
h.init(stream);
|
||||
h.load_data(addr);
|
||||
spu_ep = h.m_ehdr.data_be.e_entry;
|
||||
const spu_exec_loader loader = stream;
|
||||
|
||||
if (loader != elf_error::ok)
|
||||
{
|
||||
throw fmt::exception("Failed to load SPU image: %s" HERE, bijective_find<elf_error>(loader, "???"));
|
||||
}
|
||||
|
||||
for (const auto& prog : loader.progs)
|
||||
{
|
||||
if (prog.p_type == 0x1 /* LOAD */)
|
||||
{
|
||||
std::memcpy(vm::base(addr + prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
spu_ep = loader.header.e_entry;
|
||||
}
|
||||
|
||||
u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
|
||||
u32 LoadSpuImage(const fs::file& stream, u32& spu_ep)
|
||||
{
|
||||
const u32 alloc_size = 256 * 1024;
|
||||
u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main);
|
||||
@ -33,20 +43,6 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
|
||||
return spu_offset;
|
||||
}
|
||||
|
||||
s32 spu_image_import(sys_spu_image& img, u32 src, u32 type)
|
||||
{
|
||||
vfsStreamMemory f(src);
|
||||
u32 entry;
|
||||
u32 offset = LoadSpuImage(f, entry);
|
||||
|
||||
img.type = SYS_SPU_IMAGE_TYPE_USER;
|
||||
img.entry_point = entry;
|
||||
img.addr = offset; // TODO: writing actual segment info
|
||||
img.nsegs = 1; // wrong value
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
||||
{
|
||||
sys_spu.warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
|
||||
@ -59,14 +55,14 @@ s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
|
||||
s32 sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path)
|
||||
{
|
||||
sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path);
|
||||
|
||||
vfsFile f(path.get_ptr());
|
||||
if(!f.IsOpened())
|
||||
const fs::file f(vfs::get(path.get_ptr()));
|
||||
if (!f)
|
||||
{
|
||||
sys_spu.error("sys_spu_image_open error: '%s' not found!", path.get_ptr());
|
||||
sys_spu.error("sys_spu_image_open() error: '%s' not found!", path.get_ptr());
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
@ -75,25 +71,23 @@ s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
|
||||
|
||||
if (hdr.CheckMagic())
|
||||
{
|
||||
sys_spu.error("sys_spu_image_open error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr());
|
||||
Emu.Pause();
|
||||
return CELL_ENOENT;
|
||||
throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr());
|
||||
}
|
||||
|
||||
f.Seek(0);
|
||||
f.seek(0);
|
||||
|
||||
u32 entry;
|
||||
u32 offset = LoadSpuImage(f, entry);
|
||||
|
||||
img->type = SYS_SPU_IMAGE_TYPE_USER;
|
||||
img->entry_point = entry;
|
||||
img->addr = offset; // TODO: writing actual segment info
|
||||
img->segs.set(offset); // TODO: writing actual segment info
|
||||
img->nsegs = 1; // wrong value
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function<void(SPUThread&)> task = nullptr)
|
||||
u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr<sys_spu_image_t> img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function<void(SPUThread&)> task = nullptr)
|
||||
{
|
||||
if (option)
|
||||
{
|
||||
@ -131,10 +125,10 @@ u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img,
|
||||
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
|
||||
}
|
||||
|
||||
return spu->get_id();
|
||||
return spu->id;
|
||||
}
|
||||
|
||||
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
|
||||
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image_t> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
|
||||
{
|
||||
sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg);
|
||||
|
||||
@ -263,7 +257,7 @@ s32 sys_spu_thread_group_destroy(u32 id)
|
||||
{
|
||||
if (t)
|
||||
{
|
||||
idm::remove<SPUThread>(t->get_id());
|
||||
idm::remove<SPUThread>(t->id);
|
||||
|
||||
t.reset();
|
||||
}
|
||||
@ -312,10 +306,10 @@ s32 sys_spu_thread_group_start(u32 id)
|
||||
|
||||
// Copy SPU image:
|
||||
// TODO: use segment info
|
||||
std::memcpy(vm::base(t->offset), vm::base(image->addr), 256 * 1024);
|
||||
std::memcpy(vm::base(t->offset), image->segs.get_ptr(), 256 * 1024);
|
||||
|
||||
t->pc = image->entry_point;
|
||||
t->run();
|
||||
t->cpu_init();
|
||||
t->gpr[3] = v128::from64(0, args.arg1);
|
||||
t->gpr[4] = v128::from64(0, args.arg2);
|
||||
t->gpr[5] = v128::from64(0, args.arg3);
|
||||
@ -329,9 +323,13 @@ s32 sys_spu_thread_group_start(u32 id)
|
||||
|
||||
group->send_run_event(lv2_lock, id, 0, 0); // TODO: check data2 and data3
|
||||
|
||||
for (auto& t : group->threads)
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (t) t->exec();
|
||||
if (thread)
|
||||
{
|
||||
thread->state -= cpu_state::stop;
|
||||
thread->safe_notify();
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -379,9 +377,12 @@ s32 sys_spu_thread_group_suspend(u32 id)
|
||||
return CELL_ESTAT;
|
||||
}
|
||||
|
||||
for (auto& t : group->threads)
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (t) t->sleep(); // trigger status check
|
||||
if (thread)
|
||||
{
|
||||
thread->state += cpu_state::suspend;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -420,9 +421,13 @@ s32 sys_spu_thread_group_resume(u32 id)
|
||||
return CELL_ESTAT;
|
||||
}
|
||||
|
||||
for (auto& t : group->threads)
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (t) t->awake(); // untrigger status check
|
||||
if (thread)
|
||||
{
|
||||
thread->state -= cpu_state::suspend;
|
||||
thread->safe_notify();
|
||||
}
|
||||
}
|
||||
|
||||
group->cv.notify_all();
|
||||
@ -499,9 +504,13 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
|
||||
return CELL_ESTAT;
|
||||
}
|
||||
|
||||
for (auto& t : group->threads)
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (t) t->stop();
|
||||
if (thread)
|
||||
{
|
||||
thread->state += cpu_state::stop;
|
||||
thread->safe_notify();
|
||||
}
|
||||
}
|
||||
|
||||
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
|
||||
@ -1143,14 +1152,14 @@ s32 sys_raw_spu_create(vm::ptr<u32> id, vm::ptr<void> attr)
|
||||
|
||||
// TODO: check number set by sys_spu_initialize()
|
||||
|
||||
const auto thread = Emu.GetCPU().NewRawSPUThread();
|
||||
const auto thread = idm::make_ptr<RawSPUThread>("");
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
thread->run();
|
||||
thread->cpu_init();
|
||||
|
||||
*id = thread->index;
|
||||
|
||||
@ -1163,7 +1172,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1173,7 +1182,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
|
||||
// TODO: CELL_EBUSY is not returned
|
||||
|
||||
// Stop thread
|
||||
thread->stop();
|
||||
thread->state += cpu_state::stop;
|
||||
|
||||
// Clear interrupt handlers
|
||||
for (auto& intr : thread->int_ctrl)
|
||||
@ -1189,7 +1198,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
|
||||
}
|
||||
}
|
||||
|
||||
idm::remove<RawSPUThread>(thread->get_id());
|
||||
idm::remove<RawSPUThread>(thread->id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -1200,7 +1209,7 @@ s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1235,7 +1244,7 @@ s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1256,7 +1265,7 @@ s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr<u64> mask)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1277,7 +1286,7 @@ s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1298,7 +1307,7 @@ s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, vm::ptr<u64> stat)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1314,7 +1323,7 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr<u32> value)
|
||||
{
|
||||
sys_spu.trace("sys_raw_spu_read_puint_mb(id=%d, value=*0x%x)", id, value);
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1343,7 +1352,7 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value)
|
||||
throw EXCEPTION("Unexpected value (0x%x)", value);
|
||||
}
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -1359,7 +1368,7 @@ s32 sys_raw_spu_get_spu_cfg(u32 id, vm::ptr<u32> value)
|
||||
{
|
||||
sys_spu.trace("sys_raw_spu_get_spu_afg(id=%d, value=*0x%x)", id, value);
|
||||
|
||||
const auto thread = Emu.GetCPU().GetRawSPUThread(id);
|
||||
const auto thread = idm::get<RawSPUThread>(id);
|
||||
|
||||
if (!thread)
|
||||
{
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
#include "sys_event.h"
|
||||
|
||||
enum : s32
|
||||
@ -107,15 +105,11 @@ enum : u32
|
||||
SYS_SPU_IMAGE_TYPE_KERNEL = 1,
|
||||
};
|
||||
|
||||
struct sys_spu_image
|
||||
struct sys_spu_image_t
|
||||
{
|
||||
be_t<u32> type; // user, kernel
|
||||
be_t<u32> entry_point;
|
||||
union
|
||||
{
|
||||
be_t<u32> addr; // temporarily used as offset of the whole LS image (should be removed)
|
||||
vm::bptr<sys_spu_segment> segs;
|
||||
};
|
||||
vm::bptr<sys_spu_segment> segs;
|
||||
be_t<s32> nsegs;
|
||||
};
|
||||
|
||||
@ -151,14 +145,14 @@ struct lv2_spu_group_t
|
||||
const u32 ct; // Memory Container Id
|
||||
|
||||
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads
|
||||
std::array<vm::ptr<sys_spu_image>, 256> images; // SPU Images
|
||||
std::array<vm::ptr<sys_spu_image_t>, 256> images; // SPU Images
|
||||
std::array<spu_arg_t, 256> args; // SPU Thread Arguments
|
||||
|
||||
s32 prio; // SPU Thread Group Priority
|
||||
volatile u32 state; // SPU Thread Group State
|
||||
s32 exit_status; // SPU Thread Group Exit Status
|
||||
|
||||
std::atomic<u32> join_state; // flags used to detect exit cause
|
||||
atomic_t<u32> join_state; // flags used to detect exit cause
|
||||
std::condition_variable cv; // used to signal waiting PPU thread
|
||||
|
||||
std::weak_ptr<lv2_event_queue_t> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
|
||||
@ -177,30 +171,24 @@ struct lv2_spu_group_t
|
||||
{
|
||||
}
|
||||
|
||||
void send_run_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
void send_run_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
if (const auto queue = ep_run.lock())
|
||||
{
|
||||
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_RUN_KEY, data1, data2, data3);
|
||||
}
|
||||
}
|
||||
|
||||
void send_exception_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
void send_exception_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
if (const auto queue = ep_exception.lock())
|
||||
{
|
||||
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION_KEY, data1, data2, data3);
|
||||
}
|
||||
}
|
||||
|
||||
void send_sysmodule_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
void send_sysmodule_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
CHECK_LV2_LOCK(lv2_lock);
|
||||
|
||||
if (const auto queue = ep_sysmodule.lock())
|
||||
{
|
||||
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3);
|
||||
@ -208,20 +196,17 @@ struct lv2_spu_group_t
|
||||
}
|
||||
};
|
||||
|
||||
struct vfsStream;
|
||||
class PPUThread;
|
||||
|
||||
void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr);
|
||||
u32 LoadSpuImage(vfsStream& stream, u32& spu_ep);
|
||||
|
||||
// Aux
|
||||
s32 spu_image_import(sys_spu_image& img, u32 src, u32 type);
|
||||
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr);
|
||||
u32 LoadSpuImage(const fs::file& stream, u32& spu_ep);
|
||||
|
||||
// SysCalls
|
||||
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
||||
s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path);
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img);
|
||||
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg);
|
||||
s32 sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path);
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img);
|
||||
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image_t> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg);
|
||||
s32 sys_spu_thread_set_argument(u32 id, vm::ptr<sys_spu_thread_argument> arg);
|
||||
s32 sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr);
|
||||
s32 sys_spu_thread_group_destroy(u32 id);
|
113
rpcs3/Emu/Cell/lv2/sys_sync.h
Normal file
113
rpcs3/Emu/Cell/lv2/sys_sync.h
Normal file
@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SharedMutex.h"
|
||||
#include "Utilities/SleepQueue.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
// attr_protocol (waiting scheduling policy)
|
||||
enum
|
||||
{
|
||||
// First In, First Out
|
||||
SYS_SYNC_FIFO = 1,
|
||||
// Priority Order
|
||||
SYS_SYNC_PRIORITY = 2,
|
||||
// Basic Priority Inheritance Protocol (probably not implemented)
|
||||
SYS_SYNC_PRIORITY_INHERIT = 3,
|
||||
// Not selected while unlocking
|
||||
SYS_SYNC_RETRY = 4,
|
||||
//
|
||||
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
|
||||
};
|
||||
|
||||
// attr_recursive (recursive locks policy)
|
||||
enum
|
||||
{
|
||||
// Recursive locks are allowed
|
||||
SYS_SYNC_RECURSIVE = 0x10,
|
||||
// Recursive locks are NOT allowed
|
||||
SYS_SYNC_NOT_RECURSIVE = 0x20,
|
||||
//
|
||||
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
|
||||
};
|
||||
|
||||
// attr_pshared
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
|
||||
};
|
||||
|
||||
// attr_adaptive
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_ADAPTIVE = 0x1000,
|
||||
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
|
||||
};
|
||||
|
||||
// IPC manager collection for lv2 objects of type T
|
||||
template<typename T>
|
||||
class ipc_manager final
|
||||
{
|
||||
mutable shared_mutex m_mutex;
|
||||
std::unordered_map<u64, std::weak_ptr<T>> m_map;
|
||||
|
||||
public:
|
||||
// Add new object if specified ipc_key is not used
|
||||
template<typename F>
|
||||
auto add(u64 ipc_key, F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider()))
|
||||
{
|
||||
std::lock_guard<shared_mutex> lock(m_mutex);
|
||||
|
||||
// Get object location
|
||||
std::weak_ptr<T>& wptr = m_map[ipc_key];
|
||||
|
||||
if (wptr.expired())
|
||||
{
|
||||
// Call a function which must return the object
|
||||
std::shared_ptr<T>&& result = provider();
|
||||
wptr = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
|
||||
// Get existing object with specified ipc_key
|
||||
std::shared_ptr<T> get(u64 ipc_key) const
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
const auto found = m_map.find(ipc_key);
|
||||
|
||||
if (found != m_map.end())
|
||||
{
|
||||
return found->second.lock();
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
// Simple class for global mutex to pass unique_lock and check it
|
||||
struct lv2_lock_t
|
||||
{
|
||||
using type = std::unique_lock<std::mutex>;
|
||||
|
||||
type& ref;
|
||||
|
||||
lv2_lock_t(type& lv2_lock)
|
||||
: ref(lv2_lock)
|
||||
{
|
||||
Expects(ref.owns_lock());
|
||||
Expects(ref.mutex() == &mutex);
|
||||
}
|
||||
|
||||
operator type&() const
|
||||
{
|
||||
return ref;
|
||||
}
|
||||
|
||||
static type::mutex_type mutex;
|
||||
};
|
||||
|
||||
#define LV2_LOCK lv2_lock_t::type lv2_lock(lv2_lock_t::mutex)
|
@ -1,8 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_time.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -44,7 +45,7 @@ const g_time_aux_info = []() -> time_aux_info_t // initialize time-related value
|
||||
|
||||
#endif
|
||||
|
||||
SysCallBase sys_time("sys_time");
|
||||
LOG_CHANNEL(sys_time);
|
||||
|
||||
static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz
|
||||
|
@ -1,15 +1,15 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Utilities/Thread.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_event.h"
|
||||
#include "sys_process.h"
|
||||
#include "sys_timer.h"
|
||||
|
||||
SysCallBase sys_timer("sys_timer");
|
||||
LOG_CHANNEL(sys_timer);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
@ -59,11 +59,6 @@ void lv2_timer_t::on_task()
|
||||
}
|
||||
}
|
||||
|
||||
lv2_timer_t::lv2_timer_t()
|
||||
: id(idm::get_last_id())
|
||||
{
|
||||
}
|
||||
|
||||
s32 sys_timer_create(vm::ptr<u32> timer_id)
|
||||
{
|
||||
sys_timer.warning("sys_timer_create(timer_id=*0x%x)", timer_id);
|
||||
@ -199,8 +194,8 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto timer(idm::get<lv2_timer_t>(timer_id));
|
||||
const auto queue(idm::get<lv2_event_queue_t>(queue_id));
|
||||
const auto timer = idm::get<lv2_timer_t>(timer_id);
|
||||
const auto queue = idm::get<lv2_event_queue_t>(queue_id);
|
||||
|
||||
if (!timer || !queue)
|
||||
{
|
||||
@ -269,7 +264,7 @@ s32 sys_timer_sleep(u32 sleep_time)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_usleep(u64 sleep_time)
|
||||
s32 sys_timer_usleep(const u64 sleep_time)
|
||||
{
|
||||
sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time);
|
||||
|
@ -19,35 +19,36 @@ struct sys_timer_information_t
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
class lv2_timer_t final : public named_thread_t
|
||||
class lv2_timer_t final : public named_thread
|
||||
{
|
||||
void on_task() override;
|
||||
|
||||
void on_id_aux_finalize() override
|
||||
public:
|
||||
std::string get_name() const override
|
||||
{
|
||||
return fmt::format("Timer Thread[0x%x]", id);
|
||||
}
|
||||
|
||||
void on_stop() override
|
||||
{
|
||||
// Signal thread using invalid state and join
|
||||
{ std::lock_guard<std::mutex>{mutex}, state = -1; }
|
||||
std::lock_guard<std::mutex>{ mutex }, state = -1;
|
||||
|
||||
cv.notify_one();
|
||||
join();
|
||||
}
|
||||
|
||||
public:
|
||||
lv2_timer_t();
|
||||
const u32 id{}; // Timer id
|
||||
|
||||
std::string get_name() const override { return fmt::format("Timer Thread[0x%x]", id); }
|
||||
atomic_t<u32> state{ SYS_TIMER_STATE_RUN }; // Timer state
|
||||
|
||||
const u32 id;
|
||||
|
||||
std::weak_ptr<lv2_event_queue_t> port; // event queue
|
||||
u64 source; // event source
|
||||
u64 data1; // event arg 1
|
||||
u64 data2; // event arg 2
|
||||
std::weak_ptr<lv2_event_queue_t> port; // Event queue
|
||||
u64 source; // Event source
|
||||
u64 data1; // Event arg 1
|
||||
u64 data2; // Event arg 2
|
||||
|
||||
u64 expire = 0; // next expiration time
|
||||
u64 period = 0; // period (oneshot if 0)
|
||||
|
||||
std::atomic<u32> state{ SYS_TIMER_STATE_RUN }; // timer state
|
||||
u64 expire = 0; // Next expiration time
|
||||
u64 period = 0; // Period (oneshot if 0)
|
||||
};
|
||||
|
||||
s32 sys_timer_create(vm::ptr<u32> timer_id);
|
@ -1,11 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_trace.h"
|
||||
|
||||
SysCallBase sys_trace("sys_trace");
|
||||
LOG_CHANNEL(sys_trace);
|
||||
|
||||
s32 sys_trace_create()
|
||||
{
|
@ -1,11 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_tty.h"
|
||||
|
||||
SysCallBase sys_tty("sys_tty");
|
||||
LOG_CHANNEL(sys_tty);
|
||||
|
||||
s32 sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen)
|
||||
{
|
@ -1,13 +1,14 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_memory.h"
|
||||
#include "sys_vm.h"
|
||||
|
||||
SysCallBase sys_vm("sys_vm");
|
||||
LOG_CHANNEL(sys_vm);
|
||||
|
||||
s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "sys_sync.h"
|
||||
|
||||
enum : u64
|
||||
{
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ErrorCodes.h"
|
||||
|
||||
struct SysCallBase : public _log::channel
|
||||
{
|
||||
SysCallBase(const std::string& name)
|
||||
: _log::channel(name, _log::level::notice)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void execute_syscall_by_index(class PPUThread& ppu, u64 code);
|
||||
std::string get_ps3_function_name(u64 fid);
|
@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
// attr_protocol (waiting scheduling policy)
|
||||
enum
|
||||
{
|
||||
// First In, First Out
|
||||
SYS_SYNC_FIFO = 1,
|
||||
// Priority Order
|
||||
SYS_SYNC_PRIORITY = 2,
|
||||
// Basic Priority Inheritance Protocol (probably not implemented)
|
||||
SYS_SYNC_PRIORITY_INHERIT = 3,
|
||||
// Not selected while unlocking
|
||||
SYS_SYNC_RETRY = 4,
|
||||
//
|
||||
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
|
||||
};
|
||||
|
||||
// attr_recursive (recursive locks policy)
|
||||
enum
|
||||
{
|
||||
// Recursive locks are allowed
|
||||
SYS_SYNC_RECURSIVE = 0x10,
|
||||
// Recursive locks are NOT allowed
|
||||
SYS_SYNC_NOT_RECURSIVE = 0x20,
|
||||
//
|
||||
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
|
||||
};
|
||||
|
||||
// attr_pshared
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
|
||||
};
|
||||
|
||||
// attr_adaptive
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_ADAPTIVE = 0x1000,
|
||||
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
|
||||
};
|
Loading…
Reference in New Issue
Block a user