mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-11-26 20:50:40 +00:00
core/libraries: Initial fiber implementation (#1255)
This commit is contained in:
parent
100036aecf
commit
0a12ba4120
@ -324,6 +324,10 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
|
||||
src/core/libraries/usbd/usbd.h
|
||||
)
|
||||
|
||||
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp
|
||||
src/core/libraries/fiber/fiber.h
|
||||
)
|
||||
|
||||
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
||||
src/core/libraries/np_manager/np_manager.h
|
||||
src/core/libraries/np_score/np_score.cpp
|
||||
@ -464,6 +468,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||
${USBD_LIB}
|
||||
${MISC_LIBS}
|
||||
${DIALOGS_LIB}
|
||||
${FIBER_LIB}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
|
@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Lib, AvPlayer) \
|
||||
SUB(Lib, Ngs2) \
|
||||
SUB(Lib, Audio3d) \
|
||||
SUB(Lib, Fiber) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
@ -81,6 +81,7 @@ enum class Class : u8 {
|
||||
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
||||
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
||||
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
||||
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
@ -498,4 +498,12 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF;
|
||||
// AppContent library
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
||||
|
||||
// Fiber library
|
||||
constexpr int ORBIS_FIBER_ERROR_NULL = 0x80590001;
|
||||
constexpr int ORBIS_FIBER_ERROR_ALIGNMENT = 0x80590002;
|
||||
constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003;
|
||||
constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004;
|
||||
constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005;
|
||||
constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006;
|
284
src/core/libraries/fiber/fiber.cpp
Normal file
284
src/core/libraries/fiber/fiber.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "fiber.h"
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/linker.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace Libraries::Fiber {
|
||||
|
||||
constexpr static u64 kFiberSignature = 0x054ad954;
|
||||
|
||||
thread_local SceFiber* gCurrentFiber = nullptr;
|
||||
thread_local void* gFiberThread = nullptr;
|
||||
|
||||
void FiberEntry(void* param) {
|
||||
SceFiber* fiber = static_cast<SceFiber*>(param);
|
||||
u64 argRun = 0;
|
||||
u64 argRet = 0;
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
|
||||
if (fiber->pArgRun != nullptr) {
|
||||
argRun = *fiber->pArgRun;
|
||||
}
|
||||
|
||||
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||
linker->ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||
const SceFiberOptParam* optParam) {
|
||||
LOG_INFO(Lib_Fiber, "called: name = {}", name);
|
||||
|
||||
if (!fiber || !name || !entry) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
|
||||
fiber->signature = kFiberSignature;
|
||||
|
||||
fiber->entry = entry;
|
||||
fiber->argOnInitialize = argOnInitialize;
|
||||
|
||||
fiber->argRun = 0;
|
||||
fiber->pArgRun = &fiber->argRun;
|
||||
fiber->argReturn = 0;
|
||||
fiber->pArgReturn = &fiber->argReturn;
|
||||
|
||||
fiber->sizeContext = sizeContext;
|
||||
|
||||
fiber->state = FiberState::Init;
|
||||
#ifdef _WIN64
|
||||
fiber->handle = CreateFiber(sizeContext, FiberEntry, fiber);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) {
|
||||
LOG_ERROR(Lib_Fiber, "called");
|
||||
|
||||
if (!optParam) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (fiber->state != FiberState::Run) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
}
|
||||
|
||||
fiber->signature = 0;
|
||||
fiber->state = FiberState::None;
|
||||
|
||||
#ifdef _WIN64
|
||||
DeleteFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (fiber->state == FiberState::Run) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
}
|
||||
|
||||
if (gFiberThread == nullptr) {
|
||||
#ifdef _WIN64
|
||||
gFiberThread = ConvertThreadToFiber(nullptr);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
}
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
|
||||
if (fiber->pArgRun != nullptr) {
|
||||
*fiber->pArgRun = argOnRunTo;
|
||||
}
|
||||
|
||||
fiber->pArgReturn = argOnReturn;
|
||||
fiber->state = FiberState::Run;
|
||||
#ifdef _WIN64
|
||||
SwitchToFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (gCurrentFiber == nullptr) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
if (fiber->state == FiberState::Run) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
}
|
||||
|
||||
gCurrentFiber->state = FiberState::Suspend;
|
||||
|
||||
// TODO: argOnRun
|
||||
|
||||
*fiber->pArgRun = argOnRunTo;
|
||||
fiber->state = FiberState::Run;
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
#ifdef _WIN64
|
||||
SwitchToFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
if (!fiber || !gCurrentFiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if (gCurrentFiber->signature != kFiberSignature) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
*fiber = gCurrentFiber;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
if (gCurrentFiber->signature != kFiberSignature) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
if (gCurrentFiber->pArgReturn != nullptr) {
|
||||
*gCurrentFiber->pArgReturn = argOnReturn;
|
||||
}
|
||||
|
||||
// TODO: argOnRun
|
||||
gCurrentFiber->state = FiberState::Suspend;
|
||||
gCurrentFiber = nullptr;
|
||||
#ifdef _WIN64
|
||||
SwitchToFiber(gFiberThread);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo) {
|
||||
LOG_INFO(Lib_Fiber, "called");
|
||||
|
||||
if (!fiber || !fiberInfo) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
|
||||
fiberInfo->entry = fiber->entry;
|
||||
fiberInfo->argOnInitialize = fiber->argOnInitialize;
|
||||
fiberInfo->addrContext = nullptr;
|
||||
fiberInfo->sizeContext = fiber->sizeContext;
|
||||
fiberInfo->sizeContextMargin = 0;
|
||||
|
||||
strncpy(fiberInfo->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) {
|
||||
LOG_ERROR(Lib_Fiber, "called");
|
||||
|
||||
if (flags != 0) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
|
||||
LOG_ERROR(Lib_Fiber, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
|
||||
LOG_INFO(Lib_Fiber, "called, name = {}", name);
|
||||
|
||||
if (!fiber || !name) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
|
||||
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||
|
||||
LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun);
|
||||
LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch);
|
||||
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
||||
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Fiber
|
83
src/core/libraries/fiber/fiber.h
Normal file
83
src/core/libraries/fiber/fiber.h
Normal file
@ -0,0 +1,83 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
namespace Libraries::Fiber {
|
||||
|
||||
#define ORBIS_FIBER_MAX_NAME_LENGTH (31)
|
||||
|
||||
typedef void PS4_SYSV_ABI (*SceFiberEntry)(u64 argOnInitialize, u64 argOnRun);
|
||||
|
||||
enum FiberState : u32 {
|
||||
None = 0u,
|
||||
Init = 1u,
|
||||
Run = 2u,
|
||||
Suspend = 3u,
|
||||
};
|
||||
|
||||
struct SceFiber {
|
||||
u64 signature;
|
||||
FiberState state;
|
||||
SceFiberEntry entry;
|
||||
|
||||
u64 argOnInitialize;
|
||||
|
||||
u64 argRun;
|
||||
u64* pArgRun;
|
||||
|
||||
u64 argReturn;
|
||||
u64* pArgReturn;
|
||||
|
||||
u64 sizeContext;
|
||||
|
||||
char name[ORBIS_FIBER_MAX_NAME_LENGTH];
|
||||
void* handle;
|
||||
};
|
||||
static_assert(sizeof(SceFiber) <= 256);
|
||||
|
||||
struct SceFiberInfo {
|
||||
u64 size;
|
||||
SceFiberEntry entry;
|
||||
u64 argOnInitialize;
|
||||
void* addrContext;
|
||||
u64 sizeContext;
|
||||
char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1];
|
||||
u64 sizeContextMargin;
|
||||
};
|
||||
static_assert(sizeof(SceFiberInfo) <= 128);
|
||||
|
||||
typedef void* SceFiberOptParam;
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||
const SceFiberOptParam* optParam);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name);
|
||||
|
||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Fiber
|
@ -11,6 +11,7 @@
|
||||
#include "core/libraries/dialogs/error_dialog.h"
|
||||
#include "core/libraries/dialogs/ime_dialog.h"
|
||||
#include "core/libraries/disc_map/disc_map.h"
|
||||
#include "core/libraries/fiber/fiber.h"
|
||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/libc_internal/libc_internal.h"
|
||||
@ -77,6 +78,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
Libraries::ImeDialog::RegisterlibSceImeDialog(sym);
|
||||
Libraries::AvPlayer::RegisterlibSceAvPlayer(sym);
|
||||
Libraries::Audio3d::RegisterlibSceAudio3d(sym);
|
||||
Libraries::Fiber::RegisterlibSceFiber(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "core/file_format/trp.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/disc_map/disc_map.h"
|
||||
#include "core/libraries/fiber/fiber.h"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
#include "core/libraries/libc_internal/libc_internal.h"
|
||||
#include "core/libraries/libs.h"
|
||||
@ -258,7 +259,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
||||
void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
||||
constexpr std::array<SysModules, 13> ModulesToLoad{
|
||||
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
||||
{"libSceFiber.sprx", nullptr},
|
||||
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
||||
{"libSceUlt.sprx", nullptr},
|
||||
{"libSceJson.sprx", nullptr},
|
||||
{"libSceJson2.sprx", nullptr},
|
||||
|
Loading…
Reference in New Issue
Block a user