mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-28 17:28:26 +00:00
libraries/fiber: implement context switching (#1950)
This commit is contained in:
parent
e8b0fdd6cc
commit
851995d444
|
@ -41,6 +41,39 @@ void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI _sceFiberAttachContext(OrbisFiber* fiber, void* addr_context, u64 size_context) {
|
||||
if (size_context && size_context < ORBIS_FIBER_CONTEXT_MINIMUM_SIZE) {
|
||||
return ORBIS_FIBER_ERROR_RANGE;
|
||||
}
|
||||
if (size_context & 15) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (!addr_context || !size_context) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (fiber->addr_context) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
fiber->addr_context = addr_context;
|
||||
fiber->size_context = size_context;
|
||||
fiber->context_start = addr_context;
|
||||
fiber->context_end = reinterpret_cast<u8*>(addr_context) + size_context;
|
||||
|
||||
/* Apply signature to start of stack */
|
||||
*(u64*)addr_context = kFiberStackSignature;
|
||||
|
||||
if (fiber->flags & FiberFlags::ContextSizeCheck) {
|
||||
u64* stack_start = reinterpret_cast<u64*>(fiber->context_start);
|
||||
u64* stack_end = reinterpret_cast<u64*>(fiber->context_end);
|
||||
|
||||
u64* stack_ptr = stack_start + 1;
|
||||
while (stack_ptr < stack_end) {
|
||||
*stack_ptr++ = kFiberStackSizeCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
|
||||
OrbisFiberContext* ctx) {
|
||||
OrbisFiberContext* fiber_ctx = fiber->context;
|
||||
|
@ -62,8 +95,7 @@ void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
|
|||
data.entry = fiber->entry;
|
||||
data.arg_on_initialize = fiber->arg_on_initialize;
|
||||
data.arg_on_run_to = arg_on_run_to;
|
||||
data.stack_addr =
|
||||
reinterpret_cast<void*>(reinterpret_cast<u64>(fiber->addr_context) + fiber->size_context);
|
||||
data.stack_addr = reinterpret_cast<u8*>(fiber->addr_context) + fiber->size_context;
|
||||
if (fiber->flags & FiberFlags::SetFpuRegs) {
|
||||
data.fpucw = 0x037f;
|
||||
data.mxcsr = 0x9fc0;
|
||||
|
@ -169,8 +201,7 @@ s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFi
|
|||
|
||||
if (addr_context != nullptr) {
|
||||
fiber->context_start = addr_context;
|
||||
fiber->context_end =
|
||||
reinterpret_cast<void*>(reinterpret_cast<u64>(addr_context) + size_context);
|
||||
fiber->context_end = reinterpret_cast<u8*>(addr_context) + size_context;
|
||||
|
||||
/* Apply signature to start of stack */
|
||||
*(u64*)addr_context = kFiberStackSignature;
|
||||
|
@ -221,11 +252,12 @@ s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
|
||||
s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size_context,
|
||||
u64 arg_on_run_to, u64* arg_on_return) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber & 7) {
|
||||
if ((u64)fiber & 7 || (u64)addr_context & 15) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
|
@ -237,6 +269,14 @@ s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_r
|
|||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
/* Caller wants to attach context and run. */
|
||||
if (addr_context != nullptr || size_context != 0) {
|
||||
s32 res = _sceFiberAttachContext(fiber, addr_context, size_context);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
FiberState expected = FiberState::Idle;
|
||||
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
|
@ -288,11 +328,12 @@ s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_r
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
|
||||
s32 PS4_SYSV_ABI sceFiberSwitchImpl(OrbisFiber* fiber, void* addr_context, u64 size_context,
|
||||
u64 arg_on_run_to, u64* arg_on_run) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber & 7) {
|
||||
if ((u64)fiber & 7 || (u64)addr_context & 15) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
|
@ -304,6 +345,14 @@ s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_o
|
|||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
/* Caller wants to attach context and switch. */
|
||||
if (addr_context != nullptr || size_context != 0) {
|
||||
s32 res = _sceFiberAttachContext(fiber, addr_context, size_context);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
FiberState expected = FiberState::Idle;
|
||||
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
|
@ -462,9 +511,32 @@ s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer) {
|
||||
if (!addr_frame_pointer) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
|
||||
OrbisFiberContext* g_ctx = GetFiberContext();
|
||||
if (!g_ctx) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
*addr_frame_pointer = g_ctx->rbp;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
|
||||
return sceFiberRunImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_return);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
|
||||
return sceFiberSwitchImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_run);
|
||||
}
|
||||
|
||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberInitialize); // _sceFiberInitializeWithInternalOptionImpl
|
||||
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||
|
||||
|
@ -473,12 +545,20 @@ void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
||||
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
||||
|
||||
LIB_FUNCTION("avfGJ94g36Q", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberRunImpl); // _sceFiberAttachContextAndRun
|
||||
LIB_FUNCTION("ZqhZFuzKT6U", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberSwitchImpl); // _sceFiberAttachContextAndSwitch
|
||||
|
||||
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
|
||||
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberStartContextSizeCheck);
|
||||
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberStopContextSizeCheck);
|
||||
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
|
||||
|
||||
LIB_FUNCTION("0dy4JtMUcMQ", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||
sceFiberGetThreadFramePointerAddress);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Fiber
|
||||
|
|
|
@ -114,5 +114,7 @@ s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
|
|||
|
||||
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer);
|
||||
|
||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Fiber
|
Loading…
Reference in a new issue