1
0
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:
Nekotekina 2016-04-14 01:23:53 +03:00
parent 5637c22363
commit 42e1d4d752
50 changed files with 677 additions and 874 deletions

View File

@ -1,42 +1,39 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/AutoPause.h" #include "Utilities/AutoPause.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h"
#include "Modules.h"
#include "lv2/sys_lwmutex.h" #include "Emu/Cell/PPUFunction.h"
#include "lv2/sys_lwcond.h" #include "Emu/Cell/ErrorCodes.h"
#include "lv2/sys_mutex.h" #include "sys_sync.h"
#include "lv2/sys_cond.h" #include "sys_lwmutex.h"
#include "lv2/sys_event.h" #include "sys_lwcond.h"
#include "lv2/sys_event_flag.h" #include "sys_mutex.h"
#include "lv2/sys_interrupt.h" #include "sys_cond.h"
#include "lv2/sys_memory.h" #include "sys_event.h"
#include "lv2/sys_mmapper.h" #include "sys_event_flag.h"
#include "lv2/sys_ppu_thread.h" #include "sys_interrupt.h"
#include "lv2/sys_process.h" #include "sys_memory.h"
#include "lv2/sys_prx.h" #include "sys_mmapper.h"
#include "lv2/sys_rsx.h" #include "sys_ppu_thread.h"
#include "lv2/sys_rwlock.h" #include "sys_process.h"
#include "lv2/sys_semaphore.h" #include "sys_prx.h"
#include "lv2/sys_spu.h" #include "sys_rsx.h"
#include "lv2/sys_time.h" #include "sys_rwlock.h"
#include "lv2/sys_timer.h" #include "sys_semaphore.h"
#include "lv2/sys_trace.h" #include "sys_spu.h"
#include "lv2/sys_tty.h" #include "sys_time.h"
#include "lv2/sys_vm.h" #include "sys_timer.h"
#include "lv2/sys_fs.h" #include "sys_trace.h"
#include "lv2/sys_dbg.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" static void null_func(PPUThread& ppu)
void null_func(PPUThread& ppu)
{ {
const u64 code = ppu.GPR[11]; LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(ppu.GPR[11]));
LOG_TODO(HLE, "Unimplemented syscall %lld: %s -> CELL_OK", code, get_ps3_function_name(~code));
ppu.GPR[3] = 0; ppu.GPR[3] = 0;
} }
@ -45,7 +42,7 @@ void null_func(PPUThread& ppu)
// DBG = Debug // DBG = Debug
// PM = Product Mode // PM = Product Mode
// AuthID = Authentication ID // AuthID = Authentication ID
const ppu_func_caller g_sc_table[1024] = std::array<ppu_function_t, 1024> g_ppu_syscall_table
{ {
null_func, null_func,
BIND_FUNC(sys_process_getpid), //1 (0x001) 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, //1009 UNS
null_func, null_func, null_func, null_func, null_func, //1014 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, 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; try
ppu.hle_code = ~code; {
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)); LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]);
ppu.last_function = previous_function;
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;
} }
lv2_lock_t::type::mutex_type lv2_lock_t::mutex;

View File

@ -1,22 +1,20 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_mutex.h" #include "sys_mutex.h"
#include "sys_cond.h" #include "sys_cond.h"
SysCallBase sys_cond("sys_cond"); LOG_CHANNEL(sys_cond);
extern u64 get_system_time(); 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) if (mutex->owner)
{ {
// add thread to the mutex sleep queue if cannot lock immediately // 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 else
{ {
mutex->owner = thread; mutex->owner = std::static_pointer_cast<cpu_thread>(thread->shared_from_this());
if (!thread->signal()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Thread already signaled");
}
} }
} }
@ -150,9 +146,9 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
return CELL_ESRCH; 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 // 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); cond->mutex->unlock(lv2_lock);
// add waiter; protocol is ignored in current implementation // 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) // 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; 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 // try to reown mutex and exit if timed out
if (!cond->mutex->owner) 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; break;
} }

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
struct lv2_mutex_t; struct lv2_mutex_t;
@ -24,7 +22,7 @@ struct lv2_cond_t
const u64 name; const u64 name;
const std::shared_ptr<lv2_mutex_t> mutex; // associated mutex 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) lv2_cond_t(const std::shared_ptr<lv2_mutex_t>& mutex, u64 name)
: mutex(mutex) : 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; class PPUThread;

View File

@ -1,9 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_dbg.h" #include "sys_dbg.h"
SysCallBase sys_dbg("sys_dbg"); LOG_CHANNEL(sys_dbg);

View File

@ -1,49 +1,65 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/Event.h"
#include "sys_sync.h"
#include "sys_process.h" #include "sys_process.h"
#include "sys_event.h" #include "sys_event.h"
SysCallBase sys_event("sys_event"); LOG_CHANNEL(sys_event);
extern u64 get_system_time(); extern u64 get_system_time();
lv2_event_queue_t::lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size) static ipc_manager<lv2_event_queue_t>& get_ipc_manager()
: id(idm::get_last_id())
, protocol(protocol)
, type(type)
, name(name)
, key(key)
, size(size)
{ {
// 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 (ipc_key == SYS_EVENT_QUEUE_LOCAL)
if (sq.empty())
{ {
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 // 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 // store event data in registers
auto& ppu = static_cast<PPUThread&>(*thread); 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[6] = data2;
ppu.GPR[7] = data3; 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 // store event data in In_MBox
auto& spu = static_cast<SPUThread&>(*thread); 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 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()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Thread already signaled");
}
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) 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; 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) if (!queue)
{ {
@ -128,32 +150,32 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
return CELL_EINVAL; return CELL_EINVAL;
} }
if (!mode && queue->sq.size()) if (!mode && queue->waiters())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
// cleanup // cleanup
Emu.GetEventManager().UnregisterKey(queue->key);
idm::remove<lv2_event_queue_t>(equeue_id); idm::remove<lv2_event_queue_t>(equeue_id);
// signal all threads to return CELL_ECANCELED // 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; 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); static_cast<SPUThread&>(*thread).ch_in_mbox.set_values(1, CELL_ECANCELED);
} }
else 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; 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) if (size < 0)
{ {
throw EXCEPTION("Negative size"); throw fmt::exception("Negative size (%d)" HERE, size);
} }
if (queue->type != SYS_PPU_QUEUE) 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; 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++]; auto& dest = event_array[count++];
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->pop(lv2_lock);
queue->events.pop_front();
} }
*number = count; *number = count;
@ -218,13 +238,10 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
return CELL_EINVAL; return CELL_EINVAL;
} }
if (queue->events.size()) if (queue->events())
{ {
// event data is returned in registers (dummy_event is not used) // 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(); std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->pop(lv2_lock);
queue->events.pop_front();
return CELL_OK; 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; ppu.GPR[3] = 0;
// add waiter; protocol is ignored in current implementation // 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; 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 (ppu.GPR[3])
{ {
if (idm::check<lv2_event_queue_t>(equeue_id)) Ensures(!idm::check<lv2_event_queue_t>(equeue_id));
{
throw EXCEPTION("Unexpected");
}
return CELL_ECANCELED; return CELL_ECANCELED;
} }
@ -282,7 +295,7 @@ s32 sys_event_queue_drain(u32 equeue_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
queue->events.clear(); queue->clear(lv2_lock);
return CELL_OK; return CELL_OK;
} }
@ -401,7 +414,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
return CELL_ENOTCONN; return CELL_ENOTCONN;
} }
if (queue->events.size() >= queue->size) if (queue->events() >= queue->size)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
// Event Queue Type // Event Queue Type
enum : u32 enum : u32
@ -65,23 +63,58 @@ struct sys_event_t
be_t<u64> data3; 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 u32 protocol;
const s32 type; const s32 type;
const u64 name; const u64 name;
const u64 key; const u64 ipc_key;
const s32 size; const s32 size;
const u32 id{};
// tuple elements: source, data1, data2, data3 lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
std::deque<std::tuple<u64, u64, u64, u64>> events; : 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 struct lv2_event_port_t

View File

@ -1,22 +1,20 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_event_flag.h" #include "sys_event_flag.h"
SysCallBase sys_event_flag("sys_event_flag"); LOG_CHANNEL(sys_event_flag);
extern u64 get_system_time(); 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](cpu_thread* thread) -> bool
auto pred = [this](sleep_queue_t::value_type& thread) -> bool
{ {
auto& ppu = static_cast<PPUThread&>(*thread); auto& ppu = static_cast<PPUThread&>(*thread);
@ -30,10 +28,8 @@ void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock)
// save pattern // save pattern
ppu.GPR[4] = clear_pattern(bitptn, mode); ppu.GPR[4] = clear_pattern(bitptn, mode);
if (!ppu.signal()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Thread already signaled");
}
return true; 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 // 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; 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 // clear "mode" as a sign of cancellation
ppu.GPR[5] = 0; ppu.GPR[5] = 0;
if (!thread->signal()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Thread already signaled");
}
} }
eflag->sq.clear(); eflag->sq.clear();

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
enum enum
{ {
@ -37,9 +35,9 @@ struct lv2_event_flag_t
const s32 type; const s32 type;
const u64 name; 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) lv2_event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name)
: pattern(pattern) : 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 // Aux

View File

@ -1,17 +1,13 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.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" #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) 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; return CELL_FS_EINVAL;
} }
std::string local_path; const std::string& local_path = vfs::get(path.get_ptr());
if (local_path.empty())
const auto device = Emu.GetVFS().GetDevice(path.get_ptr(), local_path);
if (!device)
{ {
sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr()); sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr());
return CELL_FS_ENOTMOUNTED; 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; return CELL_FS_EISDIR;
} }
u32 open_mode = 0; mset<fs::open_mode> open_mode{};
switch (flags & CELL_FS_O_ACCMODE) switch (flags & CELL_FS_O_ACCMODE)
{ {
case CELL_FS_O_RDONLY: open_mode |= fom::read; break; case CELL_FS_O_RDONLY: open_mode += fs::read; break;
case CELL_FS_O_WRONLY: open_mode |= fom::write; break; case CELL_FS_O_WRONLY: open_mode += fs::write; break;
case CELL_FS_O_RDWR: open_mode |= fom::read | fom::write; break; case CELL_FS_O_RDWR: open_mode += fs::read + fs::write; break;
} }
if (flags & CELL_FS_O_CREAT) if (flags & CELL_FS_O_CREAT)
{ {
open_mode |= fom::create; open_mode += fs::create;
} }
if (flags & CELL_FS_O_TRUNC) if (flags & CELL_FS_O_TRUNC)
{ {
open_mode |= fom::trunc; open_mode += fs::trunc;
} }
if (flags & CELL_FS_O_APPEND) 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_EXCL)
{ {
if (flags & CELL_FS_O_CREAT) if (flags & CELL_FS_O_CREAT)
{ {
open_mode |= fom::excl; open_mode += fs::excl;
} }
else 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)) 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) if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE)
{ {
open_mode = 0; // error open_mode = {}; // error
} }
if (!open_mode) 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()); 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); 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 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; return CELL_FS_EMFILE;
} }
*fd = idm::get_last_id(); *fd = _file->id;
return CELL_OK; 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); 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; 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); 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; 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("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd);
sys_fs.warning("*** path = '%s'", path.get_ptr()); 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()); sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr());
return CELL_FS_ENOENT; return CELL_FS_ENOENT;
@ -204,7 +197,7 @@ s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
return CELL_FS_EMFILE; return CELL_FS_EMFILE;
} }
*fd = idm::get_last_id(); *fd = _dir->id;
return CELL_OK; 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; 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_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
dir->d_namlen = u8(std::min<size_t>(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); 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); strcpy_trunc(dir->d_name, info.name);
*nread = sizeof(CellFsDirent); *nread = sizeof(CellFsDirent);
} }
else 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("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb);
sys_fs.warning("*** path = '%s'", path.get_ptr()); 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()); sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr());
return CELL_FS_ENOTMOUNTED; 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); std::lock_guard<std::mutex> lock(file->mutex);
const auto local_file = dynamic_cast<vfsLocalFile*>(file->file.get()); const fs::stat_t& info = file->file.stat();
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; // ???
}
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
sb->uid = 1; // ??? 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("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode);
sys_fs.warning("*** path = '%s'", path.get_ptr()); 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; return CELL_FS_EEXIST;
} }
if (!Emu.GetVFS().CreatePath(ps3_path)) if (!fs::create_path(local_path))
{ {
return CELL_FS_EIO; // ??? 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("*** from = '%s'", from.get_ptr());
sys_fs.warning("*** to = '%s'", to.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; // ??? 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("sys_fs_rmdir(path=*0x%x)", path);
sys_fs.warning("*** path = '%s'", path.get_ptr()); sys_fs.warning("*** path = '%s'", path.get_ptr());
std::string ps3_path = path.get_ptr(); if (!fs::remove_dir(vfs::get(path.get_ptr())))
if (!Emu.GetVFS().ExistsDir(ps3_path))
{ {
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; // ??? 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("sys_fs_unlink(path=*0x%x)", path);
sys_fs.warning("*** path = '%s'", path.get_ptr()); sys_fs.warning("*** path = '%s'", path.get_ptr());
std::string ps3_path = path.get_ptr(); if (!fs::remove_file(vfs::get(path.get_ptr())))
if (!Emu.GetVFS().ExistsFile(ps3_path))
{ {
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; // ??? 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) 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; 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); 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; 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("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size);
sys_fs.warning("*** path = '%s'", path.get_ptr()); sys_fs.warning("*** path = '%s'", path.get_ptr());
std::string ps3_path = path.get_ptr(); if (!fs::truncate_file(vfs::get(path.get_ptr()), size))
if (!Emu.GetVFS().ExistsFile(ps3_path))
{ {
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; // ??? return CELL_FS_EIO; // ???
} }
@ -496,16 +473,14 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
std::lock_guard<std::mutex> lock(file->mutex); std::lock_guard<std::mutex> lock(file->mutex);
const auto local_file = dynamic_cast<vfsLocalFile*>(file->file.get()); if (!file->file.trunc(size))
if (!local_file)
{ {
sys_fs.error("sys_fs_ftruncate(fd=0x%x): not a local file"); switch (auto error = errno)
return CELL_FS_ENOTSUP; {
} case 0:
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);
}
if (!local_file->GetFile().trunc(size))
{
return CELL_FS_EIO; // ??? return CELL_FS_EIO; // ???
} }

View File

@ -148,8 +148,6 @@ struct CellFsUtimbuf
#pragma pack(pop) #pragma pack(pop)
struct vfsStream;
// Stream Support Status (st_status) // Stream Support Status (st_status)
enum : u32 enum : u32
{ {
@ -161,16 +159,26 @@ enum : u32
using fs_st_cb_t = vm::ptr<void(u32 xfd, u64 xsize)>; 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; u64 size;
fs_st_cb_t func; fs_st_cb_t func;
u32 pad; 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 mode;
const s32 flags; const s32 flags;
@ -188,12 +196,12 @@ struct lv2_file_t
u32 st_buffer; u32 st_buffer;
u64 st_read_size; u64 st_read_size;
std::atomic<u64> st_total_read; atomic_t<u64> st_total_read;
std::atomic<u64> st_copied; atomic_t<u64> st_copied;
atomic_t<fs_st_cb_rec_t> st_callback; 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)) : file(std::move(file))
, mode(mode) , mode(mode)
, flags(flags) , 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) lv2_dir_t(fs::dir dir)
{
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)
: dir(std::move(dir)) : dir(std::move(dir))
{ {
} }
}; };
template<> struct id_traits<lv2_dir_t> : public id_traits<lv2_file_t> {};
// SysCalls // SysCalls
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6); 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); s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size);

View File

@ -1,36 +1,24 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_interrupt.h" #include "sys_interrupt.h"
SysCallBase sys_interrupt("sys_interrupt"); LOG_CHANNEL(sys_interrupt);
lv2_int_tag_t::lv2_int_tag_t() void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock)
: id(idm::get_last_id())
{ {
}
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 // Use is_joining to stop interrupt thread and signal
thread->is_joining = true; thread->is_joining = true;
thread->cv.notify_one(); thread->cv.notify_one();
// Start joining // Start joining
while (thread->is_alive()) while (!(thread->state & cpu_state::exit))
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
@ -39,7 +27,7 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock)
// Cleanup // Cleanup
idm::remove<lv2_int_serv_t>(id); 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) 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 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; 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.cv.wait(lv2_lock);
} }
ppu.exit(); ppu.state += cpu_state::exit;
}; };
it->exec(); it->state -= cpu_state::stop;
it->safe_notify();
*ih = handler->id; *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.GPR[1] = align(ppu.stack_addr + ppu.stack_size, 0x200) - 0x200; // supercrutch to bypass stack check
ppu.fast_stop(); ppu.state += cpu_state::ret;
} }

View File

@ -1,28 +1,29 @@
#pragma once #pragma once
namespace vm { using namespace ps3; } #include "sys_sync.h"
class PPUThread; class PPUThread;
struct lv2_int_tag_t struct lv2_int_tag_t
{ {
const u32 id; const u32 id{};
std::shared_ptr<struct lv2_int_serv_t> handler; std::shared_ptr<struct lv2_int_serv_t> handler;
lv2_int_tag_t();
}; };
struct lv2_int_serv_t struct lv2_int_serv_t
{ {
const std::shared_ptr<PPUThread> thread; 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 // SysCalls

View File

@ -1,21 +1,20 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sys_lwmutex.h"
#include "sys_lwcond.h" #include "sys_lwcond.h"
SysCallBase sys_lwcond("sys_lwcond"); LOG_CHANNEL(sys_lwcond);
extern u64 get_system_time(); 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); auto& ppu = static_cast<PPUThread&>(*thread);
ppu.GPR[3] = mode2; // set to return CELL_EBUSY 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--; mutex->signaled--;
} }
if (!ppu.signal()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Thread already signaled");
}
} }
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5) 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 // mode 3: lightweight mutex was forcefully owned by the calling thread
// pick waiter; protocol is ignored in current implementation // 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()) 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); mutex->unlock(lv2_lock);
// add waiter; protocol is ignored in current implementation // 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) // 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; CHECK_EMU_STATUS;

View File

@ -21,14 +21,14 @@ struct lv2_lwcond_t
{ {
const u64 name; const u64 name;
sleep_queue_t sq; sleep_queue<cpu_thread> sq;
lv2_lwcond_t(u64 name) lv2_lwcond_t(u64 name)
: name(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 // Aux

View File

@ -1,21 +1,19 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_lwmutex.h" #include "sys_lwmutex.h"
SysCallBase sys_lwmutex("sys_lwmutex"); LOG_CHANNEL(sys_lwmutex);
extern u64 get_system_time(); 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) if (signaled)
{ {
throw EXCEPTION("Unexpected"); throw EXCEPTION("Unexpected");
@ -23,10 +21,9 @@ void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock)
if (sq.size()) if (sq.size())
{ {
if (!sq.front()->signal()) auto& thread = sq.front();
{ ASSERT(!thread->state.test_and_set(cpu_state::signal));
throw EXCEPTION("Thread already signaled"); thread->cv.notify_one();
}
sq.pop_front(); 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 // 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; CHECK_EMU_STATUS;

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
struct sys_lwmutex_attribute_t struct sys_lwmutex_attribute_t
{ {
@ -20,7 +18,7 @@ enum : u32
struct sys_lwmutex_t struct sys_lwmutex_t
{ {
struct sync_var_t struct alignas(8) sync_var_t
{ {
be_t<u32> owner; be_t<u32> owner;
be_t<u32> waiter; be_t<u32> waiter;
@ -52,9 +50,9 @@ struct lv2_lwmutex_t
const u64 name; 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 // 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) lv2_lwmutex_t(u32 protocol, u64 name)
: protocol(protocol) : protocol(protocol)
@ -62,7 +60,7 @@ struct lv2_lwmutex_t
{ {
} }
void unlock(lv2_lock_t& lv2_lock); void unlock(lv2_lock_t);
}; };
// Aux // Aux

View File

@ -1,18 +1,13 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_memory.h" #include "sys_memory.h"
SysCallBase sys_memory("sys_memory"); LOG_CHANNEL(sys_memory);
lv2_memory_container_t::lv2_memory_container_t(u32 size)
: size(size)
, id(idm::get_last_id())
{
}
s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr) s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
{ {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
namespace vm { using namespace ps3; } #include "sys_sync.h"
enum : u32 enum : u32
{ {
@ -42,18 +42,23 @@ struct sys_page_attr_t
be_t<u32> pad; be_t<u32> pad;
}; };
#include <map>
struct lv2_memory_container_t struct lv2_memory_container_t
{ {
const u32 size; // amount of "physical" memory in this container const u32 size; // amount of "physical" memory in this container
const u32 id; const u32 id{};
// amount of memory allocated // amount of memory allocated
std::atomic<u32> used{ 0 }; atomic_t<u32> used{ 0 };
// allocations (addr -> size) // allocations (addr -> size)
std::map<u32, u32> allocs; std::map<u32, u32> allocs;
lv2_memory_container_t(u32 size); lv2_memory_container_t(u32 size)
: size(size)
{
}
}; };
// SysCalls // SysCalls

View File

@ -1,21 +1,13 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_mmapper.h" #include "sys_mmapper.h"
SysCallBase sys_mmapper("sys_mmapper"); LOG_CHANNEL(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)
{
}
s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr) s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
{ {

View File

@ -2,19 +2,23 @@
#include "sys_memory.h" #include "sys_memory.h"
namespace vm { using namespace ps3; }
struct lv2_memory_t struct lv2_memory_t
{ {
const u32 size; // memory size const u32 size; // memory size
const u32 align; // required alignment const u32 align; // required alignment
const u32 id;
const u64 flags; const u64 flags;
const std::shared_ptr<lv2_memory_container_t> ct; // memory container the physical memory is taken from 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 // SysCalls

View File

@ -1,32 +1,28 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_mutex.h" #include "sys_mutex.h"
SysCallBase sys_mutex("sys_mutex"); LOG_CHANNEL(sys_mutex);
extern u64 get_system_time(); 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(); owner.reset();
if (sq.size()) if (sq.size())
{ {
// pick new owner; protocol is ignored in current implementation // 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()) ASSERT(!owner->state.test_and_set(cpu_state::signal));
{ owner->cv.notify_one();
throw EXCEPTION("Mutex owner already signaled");
}
} }
} }
@ -132,15 +128,15 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout)
// lock immediately if not locked // lock immediately if not locked
if (!mutex->owner) 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; return CELL_OK;
} }
// add waiter; protocol is ignored in current implementation // 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; CHECK_EMU_STATUS;
@ -207,7 +203,7 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id)
} }
// own the mutex if free // 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; return CELL_OK;
} }

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
struct sys_mutex_attribute_t struct sys_mutex_attribute_t
{ {
@ -27,11 +25,11 @@ struct lv2_mutex_t
const u32 protocol; const u32 protocol;
const u64 name; const u64 name;
std::atomic<u32> cond_count{ 0 }; // count of condition variables associated atomic_t<u32> cond_count{ 0 }; // count of condition variables associated
std::atomic<u32> recursive_count{ 0 }; // count of recursive locks atomic_t<u32> recursive_count{ 0 }; // count of recursive locks
std::shared_ptr<CPUThread> owner; // current mutex owner 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) lv2_mutex_t(bool recursive, u32 protocol, u64 name)
: recursive(recursive) : recursive(recursive)
@ -40,7 +38,7 @@ struct lv2_mutex_t
{ {
} }
void unlock(lv2_lock_t& lv2_lock); void unlock(lv2_lock_t);
}; };
class PPUThread; class PPUThread;

View File

@ -1,14 +1,15 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_mutex.h" #include "sys_mutex.h"
#include "sys_ppu_thread.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) 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) if (!ppu.is_joinable)
{ {
idm::remove<PPUThread>(ppu.get_id()); idm::remove<PPUThread>(ppu.id);
} }
else else
{ {
ppu.exit(); ppu.state += cpu_state::exit;
} }
// Throw if this syscall was not called directly by the SC instruction // Throw if this syscall was not called directly by the SC instruction (hack)
if (~ppu.hle_code != 41) 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; thread->is_joining = true;
// join thread // join thread
while (thread->is_alive()) while (!(thread->state & cpu_state::exit))
{ {
CHECK_EMU_STATUS; 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 // get exit status from the register
*vptr = thread->GPR[3]; if (vptr) *vptr = thread->GPR[3];
// cleanup // cleanup
idm::remove<PPUThread>(thread->get_id()); idm::remove<PPUThread>(thread->id);
return CELL_OK; 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->prio = prio;
ppu->stack_size = stacksize; ppu->stack_size = stacksize;
ppu->custom_task = std::move(task); ppu->custom_task = std::move(task);
ppu->run(); ppu->cpu_init();
if (entry) 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->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) 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->prio = prio;
ppu->stack_size = std::max<u32>(stacksize, 0x4000); ppu->stack_size = std::max<u32>(stacksize, 0x4000);
ppu->run(); ppu->cpu_init();
ppu->PC = vm::read32(param->entry); ppu->PC = vm::read32(param->entry);
ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc
ppu->GPR[3] = arg; ppu->GPR[3] = arg;
ppu->GPR[4] = unk; // actually unknown ppu->GPR[4] = unk; // actually unknown
ppu->GPR[13] = param->tls;
ppu->is_joinable = is_joinable; ppu->is_joinable = is_joinable;
if (u32 tls = param->tls) // hack *thread_id = ppu->id;
{
ppu->GPR[13] = tls;
}
*thread_id = ppu->get_id();
return CELL_OK; return CELL_OK;
} }
@ -295,7 +293,8 @@ s32 sys_ppu_thread_start(u32 thread_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
thread->exec(); thread->state -= cpu_state::stop;
thread->safe_notify();
return CELL_OK; return CELL_OK;
} }

View File

@ -1,12 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/FS/VFS.h" #include "Emu/Cell/ErrorCodes.h"
#include "Emu/FS/vfsFile.h"
#include "Loader/PSF.h"
#include "sys_lwmutex.h" #include "sys_lwmutex.h"
#include "sys_lwcond.h" #include "sys_lwcond.h"
#include "sys_mutex.h" #include "sys_mutex.h"
@ -24,7 +22,7 @@
#include "sys_fs.h" #include "sys_fs.h"
#include "sys_process.h" #include "sys_process.h"
SysCallBase sys_process("sys_process"); LOG_CHANNEL(sys_process);
s32 process_getpid() s32 process_getpid()
{ {

View File

@ -1,142 +1,32 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.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 "Crypto/unself.h"
#include "Loader/ELF64.h" #include "Loader/ELF.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_prx.h" #include "sys_prx.h"
SysCallBase sys_prx("sys_prx"); LOG_CHANNEL(sys_prx);
lv2_prx_t::lv2_prx_t()
: id(idm::get_last_id())
{
}
s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt) 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); 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 (loader != elf_error::ok)
if (!f.IsOpened())
{
return CELL_PRX_ERROR_UNKNOWN_MODULE;
}
if (loader.init(f) != loader::handler::error_code::ok || !loader.is_sprx())
{ {
return CELL_PRX_ERROR_ILLEGAL_LIBRARY; return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
} }
loader::handlers::elf64::sprx_info info; const auto prx = loader.load();
loader.load_sprx(info);
auto prx = idm::make_ptr<lv2_prx_t>(); if (!prx)
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 (module_.first == "") return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
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 prx->id; return prx->id;

View File

@ -30,114 +30,21 @@ enum
CELL_PRX_ERROR_ELF_IS_REGISTERED = 0x80011910, // Fixed ELF is already registered 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 struct sys_prx_get_module_id_by_name_option_t
{ {
be_t<u64> size; be_t<u64> size;
vm::ptr<void> base; 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 struct sys_prx_load_module_option_t
{ {
be_t<u64> size; be_t<u64> size;
vm::bptr<void> base_addr; 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 struct sys_prx_start_module_option_t
{ {
be_t<u64> size; be_t<u64> size;
@ -165,18 +72,17 @@ struct sys_prx_get_module_list_t
vm::bptr<s32> idlist; vm::bptr<s32> idlist;
}; };
// Auxiliary data types
struct lv2_prx_t struct lv2_prx_t
{ {
const u32 id; const u32 id{};
bool is_started = false; 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)> start = vm::null;
vm::ptr<s32(int argc, vm::ptr<void> argv)> stop = vm::null; vm::ptr<s32(int argc, vm::ptr<void> argv)> stop = vm::null;
vm::ptr<s32()> exit = vm::null; vm::ptr<s32()> exit = vm::null;
lv2_prx_t();
}; };
// SysCalls // SysCalls

View File

@ -1,11 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_rsx.h" #include "sys_rsx.h"
SysCallBase sys_rsx("sys_rsx"); LOG_CHANNEL(sys_rsx);
s32 sys_rsx_device_open() s32 sys_rsx_device_open()
{ {

View File

@ -1,30 +1,26 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_rwlock.h" #include "sys_rwlock.h"
SysCallBase sys_rwlock("sys_rwlock"); LOG_CHANNEL(sys_rwlock);
extern u64 get_system_time(); 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 // pick a new writer if possible; protocol is ignored in current implementation
if (!readers && !writer && wsq.size()) if (!readers && !writer && wsq.size())
{ {
writer = wsq.front(); writer = std::static_pointer_cast<cpu_thread>(wsq.front()->shared_from_this());
if (!writer->signal()) ASSERT(!writer->state.test_and_set(cpu_state::signal));
{ writer->cv.notify_one();
throw EXCEPTION("Writer already signaled");
}
return wsq.pop_front(); return wsq.pop_front();
} }
@ -36,10 +32,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock)
for (auto& thread : rsq) for (auto& thread : rsq)
{ {
if (!thread->signal()) ASSERT(!thread->state.test_and_set(cpu_state::signal));
{ thread->cv.notify_one();
throw EXCEPTION("Reader already signaled");
}
} }
return rsq.clear(); 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 // 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; CHECK_EMU_STATUS;
@ -228,15 +222,15 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
if (!rwlock->readers && !rwlock->writer) 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; return CELL_OK;
} }
// add waiter; protocol is ignored in current implementation // 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; 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 the last waiter quit the writer sleep queue, readers must acquire the lock
if (!rwlock->writer && rwlock->wsq.size() == 1) if (!rwlock->writer && rwlock->wsq.size() == 1)
{ {
if (rwlock->wsq.front().get() != &ppu) if (rwlock->wsq.front() != &ppu)
{ {
throw EXCEPTION("Unexpected"); throw EXCEPTION("Unexpected");
} }
@ -300,7 +294,7 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id)
return CELL_EBUSY; 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; return CELL_OK;
} }

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
struct sys_rwlock_attribute_t struct sys_rwlock_attribute_t
{ {
@ -24,11 +22,11 @@ struct lv2_rwlock_t
const u64 name; const u64 name;
const u32 protocol; const u32 protocol;
std::atomic<u32> readers{ 0 }; // reader lock count atomic_t<u32> readers{ 0 }; // reader lock count
std::shared_ptr<CPUThread> writer; // writer lock owner std::shared_ptr<cpu_thread> writer; // writer lock owner
sleep_queue_t rsq; // threads trying to acquire readed lock sleep_queue<cpu_thread> rsq; // threads trying to acquire readed lock
sleep_queue_t wsq; // threads trying to acquire writer lock sleep_queue<cpu_thread> wsq; // threads trying to acquire writer lock
lv2_rwlock_t(u32 protocol, u64 name) lv2_rwlock_t(u32 protocol, u64 name)
: protocol(protocol) : 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 // Aux

View File

@ -1,14 +1,14 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_sync.h"
#include "sys_semaphore.h" #include "sys_semaphore.h"
SysCallBase sys_semaphore("sys_semaphore"); LOG_CHANNEL(sys_semaphore);
extern u64 get_system_time(); 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 // 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; CHECK_EMU_STATUS;
@ -173,10 +173,9 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
{ {
count--; count--;
if (!sem->sq.front()->signal()) auto& thread = sem->sq.front();
{ ASSERT(!thread->state.test_and_set(cpu_state::signal));
throw EXCEPTION("Thread already signaled"); thread->cv.notify_one();
}
sem->sq.pop_front(); sem->sq.pop_front();
} }

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "Utilities/SleepQueue.h" #include "sys_sync.h"
namespace vm { using namespace ps3; }
struct sys_semaphore_attribute_t struct sys_semaphore_attribute_t
{ {
@ -25,9 +23,9 @@ struct lv2_sema_t
const s32 max; const s32 max;
const u64 name; 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) lv2_sema_t(u32 protocol, s32 max, u64 name, s32 value)
: protocol(protocol) : protocol(protocol)

View File

@ -1,30 +1,40 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.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 "Crypto/unself.h"
#include "Loader/ELF.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/RawSPUThread.h"
#include "sys_interrupt.h" #include "sys_interrupt.h"
#include "sys_event.h" #include "sys_event.h"
#include "sys_spu.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; const spu_exec_loader loader = stream;
h.init(stream);
h.load_data(addr); if (loader != elf_error::ok)
spu_ep = h.m_ehdr.data_be.e_entry; {
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; const u32 alloc_size = 256 * 1024;
u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main); u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main);
@ -33,20 +43,6 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
return spu_offset; 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) 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); 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; 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); sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path);
vfsFile f(path.get_ptr()); const fs::file f(vfs::get(path.get_ptr()));
if(!f.IsOpened()) 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; 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()) if (hdr.CheckMagic())
{ {
sys_spu.error("sys_spu_image_open error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr());
Emu.Pause();
return CELL_ENOENT;
} }
f.Seek(0); f.seek(0);
u32 entry; u32 entry;
u32 offset = LoadSpuImage(f, entry); u32 offset = LoadSpuImage(f, entry);
img->type = SYS_SPU_IMAGE_TYPE_USER; img->type = SYS_SPU_IMAGE_TYPE_USER;
img->entry_point = entry; 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 img->nsegs = 1; // wrong value
return CELL_OK; 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) 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; 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); 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) if (t)
{ {
idm::remove<SPUThread>(t->get_id()); idm::remove<SPUThread>(t->id);
t.reset(); t.reset();
} }
@ -312,10 +306,10 @@ s32 sys_spu_thread_group_start(u32 id)
// Copy SPU image: // Copy SPU image:
// TODO: use segment info // 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->pc = image->entry_point;
t->run(); t->cpu_init();
t->gpr[3] = v128::from64(0, args.arg1); t->gpr[3] = v128::from64(0, args.arg1);
t->gpr[4] = v128::from64(0, args.arg2); t->gpr[4] = v128::from64(0, args.arg2);
t->gpr[5] = v128::from64(0, args.arg3); 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 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; return CELL_OK;
@ -379,9 +377,12 @@ s32 sys_spu_thread_group_suspend(u32 id)
return CELL_ESTAT; 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; return CELL_OK;
@ -420,9 +421,13 @@ s32 sys_spu_thread_group_resume(u32 id)
return CELL_ESTAT; 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(); group->cv.notify_all();
@ -499,9 +504,13 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
return CELL_ESTAT; 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; 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() // TODO: check number set by sys_spu_initialize()
const auto thread = Emu.GetCPU().NewRawSPUThread(); const auto thread = idm::make_ptr<RawSPUThread>("");
if (!thread) if (!thread)
{ {
return CELL_EAGAIN; return CELL_EAGAIN;
} }
thread->run(); thread->cpu_init();
*id = thread->index; *id = thread->index;
@ -1163,7 +1172,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
LV2_LOCK; LV2_LOCK;
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) if (!thread)
{ {
@ -1173,7 +1182,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
// TODO: CELL_EBUSY is not returned // TODO: CELL_EBUSY is not returned
// Stop thread // Stop thread
thread->stop(); thread->state += cpu_state::stop;
// Clear interrupt handlers // Clear interrupt handlers
for (auto& intr : thread->int_ctrl) 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; 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; LV2_LOCK;
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) if (!thread)
{ {
@ -1235,7 +1244,7 @@ s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask)
return CELL_EINVAL; return CELL_EINVAL;
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) 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; return CELL_EINVAL;
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) if (!thread)
{ {
@ -1277,7 +1286,7 @@ s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat)
return CELL_EINVAL; return CELL_EINVAL;
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) 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; return CELL_EINVAL;
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) 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); 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) if (!thread)
{ {
@ -1343,7 +1352,7 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value)
throw EXCEPTION("Unexpected value (0x%x)", value); throw EXCEPTION("Unexpected value (0x%x)", value);
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = idm::get<RawSPUThread>(id);
if (!thread) 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); 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) if (!thread)
{ {

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
namespace vm { using namespace ps3; }
#include "sys_event.h" #include "sys_event.h"
enum : s32 enum : s32
@ -107,15 +105,11 @@ enum : u32
SYS_SPU_IMAGE_TYPE_KERNEL = 1, SYS_SPU_IMAGE_TYPE_KERNEL = 1,
}; };
struct sys_spu_image struct sys_spu_image_t
{ {
be_t<u32> type; // user, kernel be_t<u32> type; // user, kernel
be_t<u32> entry_point; be_t<u32> entry_point;
union vm::bptr<sys_spu_segment> segs;
{
be_t<u32> addr; // temporarily used as offset of the whole LS image (should be removed)
vm::bptr<sys_spu_segment> segs;
};
be_t<s32> nsegs; be_t<s32> nsegs;
}; };
@ -151,14 +145,14 @@ struct lv2_spu_group_t
const u32 ct; // Memory Container Id const u32 ct; // Memory Container Id
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads 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 std::array<spu_arg_t, 256> args; // SPU Thread Arguments
s32 prio; // SPU Thread Group Priority s32 prio; // SPU Thread Group Priority
volatile u32 state; // SPU Thread Group State volatile u32 state; // SPU Thread Group State
s32 exit_status; // SPU Thread Group Exit Status 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::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 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()) if (const auto queue = ep_run.lock())
{ {
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_RUN_KEY, data1, data2, data3); 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()) if (const auto queue = ep_exception.lock())
{ {
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION_KEY, data1, data2, data3); 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()) if (const auto queue = ep_sysmodule.lock())
{ {
queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3); 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; class PPUThread;
void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr);
u32 LoadSpuImage(vfsStream& stream, u32& spu_ep);
// Aux // 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 // SysCalls
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); 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_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path);
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img); 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> 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, 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_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_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); s32 sys_spu_thread_group_destroy(u32 id);

View 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)

View File

@ -1,8 +1,9 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_time.h" #include "sys_time.h"
#ifdef _WIN32 #ifdef _WIN32
@ -44,7 +45,7 @@ const g_time_aux_info = []() -> time_aux_info_t // initialize time-related value
#endif #endif
SysCallBase sys_time("sys_time"); LOG_CHANNEL(sys_time);
static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz

View File

@ -1,15 +1,15 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.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_event.h"
#include "sys_process.h" #include "sys_process.h"
#include "sys_timer.h" #include "sys_timer.h"
SysCallBase sys_timer("sys_timer"); LOG_CHANNEL(sys_timer);
extern u64 get_system_time(); 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) s32 sys_timer_create(vm::ptr<u32> timer_id)
{ {
sys_timer.warning("sys_timer_create(timer_id=*0x%x)", 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; LV2_LOCK;
const auto timer(idm::get<lv2_timer_t>(timer_id)); const auto timer = idm::get<lv2_timer_t>(timer_id);
const auto queue(idm::get<lv2_event_queue_t>(queue_id)); const auto queue = idm::get<lv2_event_queue_t>(queue_id);
if (!timer || !queue) if (!timer || !queue)
{ {
@ -269,7 +264,7 @@ s32 sys_timer_sleep(u32 sleep_time)
return CELL_OK; 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); sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time);

View File

@ -19,35 +19,36 @@ struct sys_timer_information_t
be_t<u32> pad; 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_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 // 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(); cv.notify_one();
join(); join();
} }
public: const u32 id{}; // Timer id
lv2_timer_t();
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
std::weak_ptr<lv2_event_queue_t> port; // event queue u64 data1; // Event arg 1
u64 source; // event source u64 data2; // Event arg 2
u64 data1; // event arg 1
u64 data2; // event arg 2
u64 expire = 0; // next expiration time u64 expire = 0; // Next expiration time
u64 period = 0; // period (oneshot if 0) u64 period = 0; // Period (oneshot if 0)
std::atomic<u32> state{ SYS_TIMER_STATE_RUN }; // timer state
}; };
s32 sys_timer_create(vm::ptr<u32> timer_id); s32 sys_timer_create(vm::ptr<u32> timer_id);

View File

@ -1,11 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_trace.h" #include "sys_trace.h"
SysCallBase sys_trace("sys_trace"); LOG_CHANNEL(sys_trace);
s32 sys_trace_create() s32 sys_trace_create()
{ {

View File

@ -1,11 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_tty.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) s32 sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen)
{ {

View File

@ -1,13 +1,14 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_memory.h" #include "sys_memory.h"
#include "sys_vm.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) s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
{ {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
namespace vm { using namespace ps3; } #include "sys_sync.h"
enum : u64 enum : u64
{ {

View File

@ -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);

View File

@ -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,
};