mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 04:32:35 +01:00
sys_prx: Improve sys_prx_start/stop_module
* Add missing error codes, "internal" errors are ones which are not reachable from liblv2.sprx functions * Implement SYS_PRX_NO_RESIDENT (unloading module) for _sys_prx_start_module.
This commit is contained in:
parent
717dd1625c
commit
e1f2f3f081
@ -297,8 +297,55 @@ error_code _sys_prx_start_module(u32 id, u64 flags, vm::ptr<sys_prx_start_stop_m
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (prx->is_started.exchange(true))
|
||||
return not_an_error(CELL_PRX_ERROR_ALREADY_STARTED);
|
||||
switch (pOpt->cmd & 0xf)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (!prx->state.compare_and_swap_test(PRX_STATE_INITIALIZED, PRX_STATE_STARTING))
|
||||
{
|
||||
// The only error code here
|
||||
return CELL_PRX_ERROR_ERROR;
|
||||
}
|
||||
|
||||
pOpt->entry.set(prx->start ? prx->start.addr() : ~0ull);
|
||||
pOpt->entry2.set(prx->prologue ? prx->prologue.addr() : ~0ull);
|
||||
return CELL_OK;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
switch (const u64 res = pOpt->res)
|
||||
{
|
||||
case SYS_PRX_RESIDENT:
|
||||
{
|
||||
// No error code on invalid state, so throw on unexpected state
|
||||
verify(HERE), prx->state.compare_and_swap_test(PRX_STATE_STARTING, PRX_STATE_STARTED);
|
||||
return CELL_OK;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (res & 0xffff'ffffu)
|
||||
{
|
||||
// Unload the module (SYS_PRX_NO_RESIDENT expected)
|
||||
sys_prx.warning("_sys_prx_start_module(): Start entry function returned SYS_PRX_NO_RESIDENT (res=0x%llx)", res);
|
||||
|
||||
// Thread-safe if called from liblv2.sprx, due to internal lwmutex lock before it
|
||||
prx->state = PRX_STATE_STOPPED;
|
||||
_sys_prx_unload_module(id, 0, vm::null);
|
||||
|
||||
// Return the exact value returned by the start function (as an error)
|
||||
return static_cast<s32>(res);
|
||||
}
|
||||
|
||||
// Return type of start entry function is s32
|
||||
// And according to RE this path results in weird behavior
|
||||
sys_prx.error("_sys_prx_start_module(): Start entry function returned weird value (res=0x%llx)", res);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return CELL_PRX_ERROR_ERROR;
|
||||
}
|
||||
|
||||
pOpt->entry.set(prx->start ? prx->start.addr() : ~0ull);
|
||||
pOpt->entry2.set(prx->prologue ? prx->prologue.addr() : ~0ull);
|
||||
@ -316,11 +363,80 @@ error_code _sys_prx_stop_module(u32 id, u64 flags, vm::ptr<sys_prx_start_stop_mo
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!prx->is_started.exchange(false))
|
||||
return not_an_error(CELL_PRX_ERROR_ALREADY_STOPPED);
|
||||
if (!pOpt)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
|
||||
pOpt->entry2.set(prx->epilogue ? prx->epilogue.addr() : ~0ull);
|
||||
switch (pOpt->cmd & 0xf)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (const auto old = prx->state.compare_and_swap(PRX_STATE_STARTED, PRX_STATE_STOPPING))
|
||||
{
|
||||
case PRX_STATE_INITIALIZED: return CELL_PRX_ERROR_NOT_STARTED;
|
||||
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
||||
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
||||
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
||||
case PRX_STATE_STARTED: break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid prx state (%d)" HERE, old);
|
||||
}
|
||||
|
||||
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
|
||||
pOpt->entry2.set(prx->epilogue ? prx->epilogue.addr() : ~0ull);
|
||||
return CELL_OK;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
switch (pOpt->res)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// No error code on invalid state, so throw on unexpected state
|
||||
verify(HERE), prx->state.compare_and_swap_test(PRX_STATE_STOPPING, PRX_STATE_STOPPED);
|
||||
return CELL_OK;
|
||||
}
|
||||
case 1:
|
||||
return CELL_PRX_ERROR_CAN_NOT_STOP; // Internal error
|
||||
default:
|
||||
// Nothing happens (probably unexpected value)
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// These commands are not used by liblv2.sprx
|
||||
case 4: // Get start entry and stop functions
|
||||
case 8: // Disable stop function execution
|
||||
{
|
||||
switch (const auto old = +prx->state)
|
||||
{
|
||||
case PRX_STATE_INITIALIZED: return CELL_PRX_ERROR_NOT_STARTED;
|
||||
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
||||
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
||||
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
||||
case PRX_STATE_STARTED: break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid prx state (%d)" HERE, old);
|
||||
}
|
||||
|
||||
if (pOpt->cmd == 4u)
|
||||
{
|
||||
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
|
||||
pOpt->entry2.set(prx->epilogue ? prx->epilogue.addr() : ~0ull);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disables stop function execution (but the real value can be read through _sys_prx_get_module_info)
|
||||
sys_prx.todo("_sys_prx_stop_module(): cmd is 8 (stop function = *0x%x)", prx->stop);
|
||||
//prx->stop = vm::null;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
default:
|
||||
return CELL_PRX_ERROR_ERROR;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -117,11 +117,27 @@ struct sys_prx_get_module_list_option_t
|
||||
be_t<u32> unk; // 0
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
SYS_PRX_RESIDENT = 0,
|
||||
SYS_PRX_NO_RESIDENT = 1,
|
||||
};
|
||||
|
||||
// Unofficial names for PRX state
|
||||
enum : u32
|
||||
{
|
||||
PRX_STATE_INITIALIZED,
|
||||
PRX_STATE_STARTING, // In-between state between initialized and started (internal)
|
||||
PRX_STATE_STARTED,
|
||||
PRX_STATE_STOPPING, // In-between state between started and stopped (internal)
|
||||
PRX_STATE_STOPPED, // Last state, the module cannot be restarted
|
||||
};
|
||||
|
||||
struct lv2_prx final : lv2_obj, ppu_module
|
||||
{
|
||||
static const u32 id_base = 0x23000000;
|
||||
|
||||
atomic_t<bool> is_started = false;
|
||||
atomic_t<u32> state = PRX_STATE_INITIALIZED;
|
||||
|
||||
std::unordered_map<u32, u32> specials;
|
||||
std::unordered_map<u32, void*> imports;
|
||||
|
Loading…
Reference in New Issue
Block a user