From 8a0187685d25ee753856811ec91d77bdac90d80d Mon Sep 17 00:00:00 2001 From: w1naenator Date: Mon, 26 Jan 2026 03:40:09 +0200 Subject: [PATCH] Add Ulobjmgr integration and enhance fiber management - Added Ulobjmgr support in logging and fiber management, including new functions for registration and unregistration. - Updated fiber context structure to include ASan (AddressSanitizer) support and improved stack handling. - Enhanced fiber switching logic to accommodate ASan and Razor CPU features. - Introduced logging for Ulobjmgr function calls to aid in debugging. - Modified memory and pthread headers to include necessary function declarations for ASan and thread management. - Improved error handling and logging throughout the fiber management code. --- src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + src/core/libraries/fiber/fiber.cpp | 360 +++++++++++++++++--- src/core/libraries/fiber/fiber.h | 49 ++- src/core/libraries/fiber/fiber_context.s | 107 +++--- src/core/libraries/kernel/memory.h | 2 + src/core/libraries/kernel/threads/pthread.h | 2 + src/core/libraries/razor_cpu/razor_cpu.h | 5 +- src/core/libraries/ulobjmgr/ulobjmgr.cpp | 5 + src/core/libraries/ulobjmgr/ulobjmgr.h | 11 +- src/core/tls.h | 7 +- 11 files changed, 428 insertions(+), 122 deletions(-) diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 9c8b80255..422d69db1 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -139,6 +139,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Vdec2) \ SUB(Lib, Videodec) \ SUB(Lib, RazorCpu) \ + SUB(Lib, Ulobjmgr) \ SUB(Lib, Mouse) \ SUB(Lib, WebBrowserDialog) \ SUB(Lib, NpParty) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index dc7c561a4..f554e4e48 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -107,6 +107,7 @@ enum class Class : u8 { Lib_Videodec, ///< The LibSceVideodec implementation. Lib_Voice, ///< The LibSceVoice implementation. Lib_RazorCpu, ///< The LibRazorCpu implementation. + Lib_Ulobjmgr, ///< The ulobjmgr implementation. Lib_Mouse, ///< The LibSceMouse implementation Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation Lib_NpParty, ///< The LibSceNpParty implementation diff --git a/src/core/libraries/fiber/fiber.cpp b/src/core/libraries/fiber/fiber.cpp index 12b173d79..5d4e033ad 100644 --- a/src/core/libraries/fiber/fiber.cpp +++ b/src/core/libraries/fiber/fiber.cpp @@ -6,10 +6,20 @@ #include "common/elf_info.h" #include "common/logging/log.h" #include "core/libraries/fiber/fiber_error.h" +#include "core/libraries/kernel/memory.h" +#include "core/libraries/kernel/threads/pthread.h" #include "core/libraries/libs.h" +#include "core/libraries/razor_cpu/razor_cpu.h" +#include "core/libraries/system/sysmodule.h" +#include "core/libraries/ulobjmgr/ulobjmgr.h" #include "core/tls.h" +#include +#include #include +#if defined(_MSC_VER) +#include +#endif namespace Libraries::Fiber { @@ -33,6 +43,106 @@ static constexpr u8 kFiberNameXorTable[ORBIS_FIBER_MAX_NAME_LENGTH + 1] = { static std::atomic context_size_check = false; static std::atomic name_seed = kFiberNameSeedInit; +static std::atomic fiber_globals_init = false; +static std::atomic razor_enabled = false; +static std::atomic asan_enabled = false; +static std::atomic switch_cookie_counter = 0; + +static u64 PthreadSelf() { + auto* thread = ::Libraries::Kernel::posix_pthread_self(); + return reinterpret_cast(thread); +} + +static void GetThreadStack(void** stack_addr, size_t* stack_size) { + if (!stack_addr || !stack_size) { + return; + } + + auto* thread = ::Libraries::Kernel::g_curthread; + if (!thread) { + *stack_addr = nullptr; + *stack_size = 0; + return; + } + + *stack_addr = thread->attr.stackaddr_attr; + *stack_size = thread->attr.stacksize_attr; +} + +static void RazorCpuFiberSwitch(u32 from_id, u32 to_id, u32 reason) { + (void)from_id; + (void)to_id; + (void)reason; + ::Libraries::RazorCpu::sceRazorCpuFiberSwitch(); +} + +static void RazorCpuFiberLogNameChange(OrbisFiber* fiber, const char* name) { + (void)fiber; + (void)name; + ::Libraries::RazorCpu::sceRazorCpuFiberLogNameChange(); +} + +static s32 UlobjmgrRegister(u64 arg0, s32 arg1, u32* arg2) { + return ::Libraries::Ulobjmgr::Func_046DBA8411A2365C(arg0, arg1, arg2); +} + +static s32 UlobjmgrUnregister(u32 arg0) { + return ::Libraries::Ulobjmgr::Func_4A67FE7D435B94F7(arg0); +} + +extern "C" { +void PS4_SYSV_ABI __sanitizer_start_switch_fiber(void** fake_stack_save, + const void* stack_addr, + size_t stack_size); +void PS4_SYSV_ABI __sanitizer_finish_switch_fiber(void* fake_stack_save, + const void** old_stack_addr, + size_t* old_stack_size); +void PS4_SYSV_ABI __asan_destroy_fake_stack(); +} // extern "C" + +extern "C" void PS4_SYSV_ABI __sanitizer_start_switch_fiber(void** fake_stack_save, + const void* stack_addr, + size_t stack_size) { + (void)fake_stack_save; + (void)stack_addr; + (void)stack_size; +} + +extern "C" void PS4_SYSV_ABI __sanitizer_finish_switch_fiber(void* fake_stack_save, + const void** old_stack_addr, + size_t* old_stack_size) { + (void)fake_stack_save; + (void)old_stack_addr; + (void)old_stack_size; +} + +extern "C" void PS4_SYSV_ABI __asan_destroy_fake_stack() {} + +static void EnsureFiberGlobalsInitialized() { + u32 expected = 0; + if (fiber_globals_init.compare_exchange_strong(expected, 1u, std::memory_order_relaxed)) { + const auto razor_loaded = ::Libraries::SysModule::sceSysmoduleIsLoadedInternal( + ::Libraries::SysModule::OrbisSysModuleInternal::ORBIS_SYSMODULE_INTERNAL_RAZOR_CPU); + razor_enabled.store(razor_loaded == 0 ? 1u : 0u, std::memory_order_relaxed); + asan_enabled.store(::Libraries::Kernel::sceKernelIsAddressSanitizerEnabled() != 0 ? 1u : 0u, + std::memory_order_relaxed); + } +} + +static bool RazorEnabled() { + EnsureFiberGlobalsInitialized(); + return razor_enabled.load(std::memory_order_relaxed) != 0; +} + +static bool AsanEnabled() { + EnsureFiberGlobalsInitialized(); + return asan_enabled.load(std::memory_order_relaxed) != 0; +} + +static void UpdateSwitchCookie(OrbisFiber* fiber) { + const u64 value = switch_cookie_counter.fetch_add(1, std::memory_order_relaxed) + 1; + fiber->switch_cookie = value ^ kFiberSwitchCookieInit; +} static u64 ComputeContextSizeMargin(const OrbisFiber* fiber) { if (!fiber || !fiber->context_start || !fiber->context_end) { @@ -162,13 +272,26 @@ extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) { } void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) { - u64* stack_base = reinterpret_cast(ctx->current_fiber->addr_context); - u64 stack_size = ctx->current_fiber->size_context; + OrbisFiber* fiber = ctx->current_fiber; + u64* stack_base = reinterpret_cast(fiber->addr_context); + u64 stack_size = fiber->size_context; if (stack_base && *stack_base != kFiberStackSignature) { - if (*stack_base == 0) { - *stack_base = kFiberStackSignature; - return; - } + char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1]{}; + DecodeFiberName(fiber, name, sizeof(name)); + + const uintptr_t stack_base_addr = reinterpret_cast(stack_base); + const uintptr_t stack_top_addr = stack_base_addr + static_cast(stack_size); + LOG_CRITICAL( + Lib_Fiber, + "Fiber stack overflow: name='{}' fiber={:#x} ctx={:#x} stack_base={:#x} " + "stack_top={:#x} size=0x{:x} sig={:#x} expected={:#x} context_start={:#x} " + "context_end={:#x} flags=0x{:x} state=0x{:x} switch_cookie={:#x} magic_start=0x{:x} " + "magic_end=0x{:x}", + name, reinterpret_cast(fiber), reinterpret_cast(ctx), + stack_base_addr, stack_top_addr, stack_size, *stack_base, + kFiberStackSignature, reinterpret_cast(fiber->context_start), + reinterpret_cast(fiber->context_end), fiber->flags, fiber->state, + fiber->switch_cookie, fiber->magic_start, fiber->magic_end); UNREACHABLE_MSG("Stack overflow detected in fiber with size = 0x{:x}", stack_size); } } @@ -194,6 +317,11 @@ s32 PS4_SYSV_ABI _sceFiberAttachContext(OrbisFiber* fiber, void* addr_context, u /* Apply signature to start of stack */ *(u64*)addr_context = kFiberStackSignature; + LOG_INFO( + Lib_Fiber, + "Fiber attach context: fiber={:#x} addr_context={:#x} size=0x{:x} sig={:#x} flags=0x{:x}", + reinterpret_cast(fiber), reinterpret_cast(addr_context), size_context, + *(u64*)addr_context, fiber->flags); if (fiber->flags & FiberFlags::ContextSizeCheck) { u64* stack_start = reinterpret_cast(fiber->context_start); @@ -209,7 +337,7 @@ s32 PS4_SYSV_ABI _sceFiberAttachContext(OrbisFiber* fiber, void* addr_context, u } void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to, - OrbisFiberContext* ctx) { + OrbisFiberContext* ctx, u64 asan_cookie) { OrbisFiberContext* fiber_ctx = fiber->context; if (fiber_ctx) { ctx->arg_on_run_to = arg_on_run_to; @@ -230,22 +358,23 @@ void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to, data.arg_on_initialize = DecodeArgOnInitialize(fiber); data.arg_on_run_to = arg_on_run_to; data.stack_addr = reinterpret_cast(fiber->addr_context) + fiber->size_context; - if (fiber->flags & FiberFlags::SetFpuRegs) { - data.fpucw = 0x037f; - data.mxcsr = 0x9fc0; - _sceFiberSwitchEntry(&data, true); - } else { - _sceFiberSwitchEntry(&data, false); - } + data.asan_fake_stack = reinterpret_cast(asan_cookie); + _sceFiberSwitchEntry(&data, (fiber->flags & FiberFlags::SetFpuRegs) != 0); __builtin_trap(); } void PS4_SYSV_ABI _sceFiberSwitch(OrbisFiber* cur_fiber, OrbisFiber* fiber, u64 arg_on_run_to, - OrbisFiberContext* ctx) { + OrbisFiberContext* ctx, u64 asan_cookie) { + UpdateSwitchCookie(cur_fiber); ctx->prev_fiber = cur_fiber; ctx->current_fiber = fiber; + if (RazorEnabled()) { + RazorCpuFiberSwitch(static_cast(reinterpret_cast(cur_fiber)), + static_cast(reinterpret_cast(fiber)), 1); + } + if (fiber->addr_context == nullptr) { ctx->prev_fiber = nullptr; @@ -253,25 +382,25 @@ void PS4_SYSV_ABI _sceFiberSwitch(OrbisFiber* cur_fiber, OrbisFiber* fiber, u64 data.entry = DecodeEntry(fiber); data.arg_on_initialize = DecodeArgOnInitialize(fiber); data.arg_on_run_to = arg_on_run_to; - data.stack_addr = reinterpret_cast(ctx->rsp & ~15); + data.stack_addr = reinterpret_cast(ctx->jmp.rsp & ~15); data.state = reinterpret_cast(&cur_fiber->state); - - if (fiber->flags & FiberFlags::SetFpuRegs) { - data.fpucw = 0x037f; - data.mxcsr = 0x9fc0; - _sceFiberSwitchEntry(&data, true); + if (asan_cookie != 0) { + data.asan_fake_stack = + reinterpret_cast(reinterpret_cast(fiber->asan_fake_stack) + 1); } else { - _sceFiberSwitchEntry(&data, false); + data.asan_fake_stack = nullptr; } + _sceFiberSwitchEntry(&data, (fiber->flags & FiberFlags::SetFpuRegs) != 0); __builtin_trap(); } - _sceFiberSwitchToFiber(fiber, arg_on_run_to, ctx); + _sceFiberSwitchToFiber(fiber, arg_on_run_to, ctx, asan_cookie); __builtin_trap(); } void PS4_SYSV_ABI _sceFiberTerminate(OrbisFiber* fiber, u64 arg_on_return, OrbisFiberContext* ctx) { + UpdateSwitchCookie(fiber); ctx->arg_on_return = arg_on_return; _sceFiberLongJmp(ctx); __builtin_trap(); @@ -281,6 +410,7 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb u64 arg_on_initialize, void* addr_context, u64 size_context, const OrbisFiberOptParam* opt_param, u32 flags, u32 build_ver) { + EnsureFiberGlobalsInitialized(); if (!fiber || !name || !entry) { return ORBIS_FIBER_ERROR_NULL; } @@ -302,6 +432,9 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb if (addr_context && !size_context) { return ORBIS_FIBER_ERROR_INVALID; } + if (size_context && size_context <= 4096) { + LOG_WARNING(Lib_Fiber, "Fiber initialized with small stack area."); + } if (opt_param && opt_param->magic != kFiberOptSignature) { return ORBIS_FIBER_ERROR_INVALID; } @@ -310,7 +443,7 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb if (build_ver >= Common::ElfInfo::FW_35) { user_flags |= FiberFlags::SetFpuRegs; } - if (context_size_check) { + if (context_size_check.load(std::memory_order_relaxed) != 0) { user_flags |= FiberFlags::ContextSizeCheck; } @@ -323,7 +456,7 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb fiber->context = nullptr; fiber->owner_thread = 0; fiber->flags = user_flags; - fiber->razor_id_xor = kFiberRazorIdXor; + fiber->razor_id_xor = 0; fiber->switch_cookie = kFiberSwitchCookieInit; fiber->asan_fake_stack = nullptr; fiber->context_start = nullptr; @@ -339,6 +472,12 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb /* Apply signature to start of stack */ *(u64*)addr_context = kFiberStackSignature; + LOG_INFO(Lib_Fiber, + "Fiber init context: fiber={:#x} name='{}' addr_context={:#x} size=0x{:x} " + "sig={:#x} flags=0x{:x}", + reinterpret_cast(fiber), name, + reinterpret_cast(addr_context), size_context, *(u64*)addr_context, + fiber->flags); if (fiber->flags & FiberFlags::ContextSizeCheck) { u64* stack_start = reinterpret_cast(fiber->context_start); @@ -352,6 +491,16 @@ s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, Orb } StoreFiberState(fiber, FiberState::Idle); + if ((fiber->flags & FiberFlags::NoUlobjmgr) == 0) { + LOG_DEBUG(Lib_Fiber, "Ulobjmgr register: fiber={:#x} flags=0x{:x}", + reinterpret_cast(fiber), fiber->flags); + u32 razor_id = 0; + UlobjmgrRegister(reinterpret_cast(fiber), 1, &razor_id); + fiber->razor_id_xor = razor_id ^ kFiberRazorIdXor; + } else { + LOG_DEBUG(Lib_Fiber, "Ulobjmgr register skipped (NoUlobjmgr): fiber={:#x} flags=0x{:x}", + reinterpret_cast(fiber), fiber->flags); + } return ORBIS_OK; } @@ -369,6 +518,7 @@ s32 PS4_SYSV_ABI sceFiberOptParamInitialize(OrbisFiberOptParam* opt_param) { } s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) { + EnsureFiberGlobalsInitialized(); if (!fiber) { return ORBIS_FIBER_ERROR_NULL; } @@ -383,11 +533,29 @@ s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) { return ORBIS_FIBER_ERROR_STATE; } + if (RazorEnabled()) { + char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1]{}; + DecodeFiberName(fiber, name, sizeof(name)); + RazorCpuFiberLogNameChange(fiber, name); + } + if ((fiber->flags & FiberFlags::NoUlobjmgr) == 0) { + LOG_DEBUG(Lib_Fiber, "Ulobjmgr unregister: fiber={:#x} flags=0x{:x}", + reinterpret_cast(fiber), fiber->flags); + UlobjmgrUnregister(fiber->razor_id_xor ^ kFiberRazorIdXor); + } else { + LOG_DEBUG(Lib_Fiber, "Ulobjmgr unregister skipped (NoUlobjmgr): fiber={:#x} flags=0x{:x}", + reinterpret_cast(fiber), fiber->flags); + } + if (AsanEnabled() && fiber->asan_fake_stack != nullptr && fiber->addr_context != nullptr) { + __asan_destroy_fake_stack(); + fiber->asan_fake_stack = nullptr; + } return ORBIS_OK; } s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size_context, u64 arg_on_run_to, u64* arg_on_return) { + EnsureFiberGlobalsInitialized(); if (!fiber) { return ORBIS_FIBER_ERROR_NULL; } @@ -403,11 +571,16 @@ s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size 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; + const bool attach_context = (addr_context != nullptr || size_context != 0); + if (attach_context) { + if (size_context != 0 && size_context < ORBIS_FIBER_CONTEXT_MINIMUM_SIZE) { + return ORBIS_FIBER_ERROR_RANGE; + } + if (!addr_context || size_context == 0 || (size_context & 15)) { + return ORBIS_FIBER_ERROR_INVALID; + } + if (fiber->addr_context != nullptr) { + return ORBIS_FIBER_ERROR_INVALID; } } @@ -415,17 +588,46 @@ s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size return ORBIS_FIBER_ERROR_STATE; } + /* Caller wants to attach context and run. */ + if (attach_context) { + s32 res = _sceFiberAttachContext(fiber, addr_context, size_context); + if (res < 0) { + return res; + } + } + + fiber->owner_thread = PthreadSelf(); + OrbisFiberContext ctx{}; ctx.current_fiber = fiber; ctx.prev_fiber = nullptr; + ctx.arg_on_run_to = 0; + ctx.arg_on_return = 0; ctx.return_val = 0; + ctx.owner_thread = fiber->owner_thread; + ctx.asan_fake_stack = nullptr; + ctx.reserved0 = 0; + ctx.reserved1 = 0; + ctx.reserved2 = 0xffffffffu; + ctx.reserved3 = 0xffffffffu; tcb->tcb_fiber = &ctx; + if (RazorEnabled()) { + RazorCpuFiberSwitch(0, static_cast(reinterpret_cast(fiber)), 2); + } + + bool asan_switch = false; + if (AsanEnabled() && fiber->addr_context != nullptr) { + __sanitizer_start_switch_fiber(&ctx.asan_fake_stack, fiber->addr_context, + fiber->size_context); + asan_switch = true; + } + s32 jmp = _sceFiberSetJmp(&ctx); if (!jmp) { if (fiber->addr_context) { - _sceFiberSwitchToFiber(fiber, arg_on_run_to, &ctx); + _sceFiberSwitchToFiber(fiber, arg_on_run_to, &ctx, asan_switch ? 1 : 0); __builtin_trap(); } @@ -433,19 +635,22 @@ s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size data.entry = DecodeEntry(fiber); data.arg_on_initialize = DecodeArgOnInitialize(fiber); data.arg_on_run_to = arg_on_run_to; - data.stack_addr = reinterpret_cast(ctx.rsp & ~15); + data.stack_addr = reinterpret_cast(ctx.jmp.rsp & ~15); data.state = nullptr; - if (fiber->flags & FiberFlags::SetFpuRegs) { - data.fpucw = 0x037f; - data.mxcsr = 0x9fc0; - _sceFiberSwitchEntry(&data, true); - } else { - _sceFiberSwitchEntry(&data, false); - } + data.asan_fake_stack = nullptr; + _sceFiberSwitchEntry(&data, (fiber->flags & FiberFlags::SetFpuRegs) != 0); + } + + if (asan_switch) { + __sanitizer_finish_switch_fiber(ctx.asan_fake_stack, nullptr, nullptr); } OrbisFiber* cur_fiber = ctx.current_fiber; ctx.current_fiber = nullptr; + + if (RazorEnabled()) { + RazorCpuFiberSwitch(static_cast(reinterpret_cast(cur_fiber)), 0, 3); + } StoreFiberState(cur_fiber, FiberState::Idle); if (ctx.return_val != 0) { @@ -463,6 +668,7 @@ s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size s32 PS4_SYSV_ABI sceFiberSwitchImpl(OrbisFiber* fiber, void* addr_context, u64 size_context, u64 arg_on_run_to, u64* arg_on_run) { + EnsureFiberGlobalsInitialized(); if (!fiber) { return ORBIS_FIBER_ERROR_NULL; } @@ -478,11 +684,16 @@ s32 PS4_SYSV_ABI sceFiberSwitchImpl(OrbisFiber* fiber, void* addr_context, u64 s 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; + const bool attach_context = (addr_context != nullptr || size_context != 0); + if (attach_context) { + if (size_context != 0 && size_context < ORBIS_FIBER_CONTEXT_MINIMUM_SIZE) { + return ORBIS_FIBER_ERROR_RANGE; + } + if (!addr_context || size_context == 0 || (size_context & 15)) { + return ORBIS_FIBER_ERROR_INVALID; + } + if (fiber->addr_context != nullptr) { + return ORBIS_FIBER_ERROR_INVALID; } } @@ -490,25 +701,54 @@ s32 PS4_SYSV_ABI sceFiberSwitchImpl(OrbisFiber* fiber, void* addr_context, u64 s return ORBIS_FIBER_ERROR_STATE; } + /* Caller wants to attach context and switch. */ + if (attach_context) { + s32 res = _sceFiberAttachContext(fiber, addr_context, size_context); + if (res < 0) { + return res; + } + } + + fiber->owner_thread = g_ctx->owner_thread; + OrbisFiber* cur_fiber = g_ctx->current_fiber; if (cur_fiber->addr_context == nullptr) { - _sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx); + u64 asan_cookie = 0; + if (AsanEnabled() && fiber->addr_context != nullptr) { + __sanitizer_start_switch_fiber(&cur_fiber->asan_fake_stack, fiber->addr_context, + fiber->size_context); + asan_cookie = 1; + } + _sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx, asan_cookie); __builtin_trap(); } + if (AsanEnabled()) { + void* stack_addr = nullptr; + size_t stack_size = 0; + if (fiber->addr_context == nullptr) { + GetThreadStack(&stack_addr, &stack_size); + } else { + stack_addr = fiber->addr_context; + stack_size = fiber->size_context; + } + __sanitizer_start_switch_fiber(&cur_fiber->asan_fake_stack, stack_addr, stack_size); + } + OrbisFiberContext ctx{}; s32 jmp = _sceFiberSetJmp(&ctx); if (!jmp) { cur_fiber->context = &ctx; _sceFiberCheckStackOverflow(g_ctx); - _sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx); + _sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx, AsanEnabled() ? 1 : 0); __builtin_trap(); } - g_ctx = GetFiberContext(); - if (g_ctx->current_fiber) { - g_ctx->current_fiber->context = nullptr; + if (AsanEnabled()) { + __sanitizer_finish_switch_fiber(cur_fiber->asan_fake_stack, nullptr, nullptr); } + + g_ctx = GetFiberContext(); if (g_ctx->prev_fiber) { StoreFiberState(g_ctx->prev_fiber, FiberState::Idle); g_ctx->prev_fiber = nullptr; @@ -543,13 +783,20 @@ s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 arg_on_return, u64* arg_on_run) { OrbisFiber* cur_fiber = g_ctx->current_fiber; if (cur_fiber->addr_context) { + if (AsanEnabled()) { + void* stack_addr = nullptr; + size_t stack_size = 0; + GetThreadStack(&stack_addr, &stack_size); + __sanitizer_start_switch_fiber(&cur_fiber->asan_fake_stack, stack_addr, stack_size); + } + OrbisFiberContext ctx{}; s32 jmp = _sceFiberSetJmp(&ctx); if (jmp) { - g_ctx = GetFiberContext(); - if (g_ctx->current_fiber) { - g_ctx->current_fiber->context = nullptr; + if (AsanEnabled()) { + __sanitizer_finish_switch_fiber(cur_fiber->asan_fake_stack, nullptr, nullptr); } + g_ctx = GetFiberContext(); if (g_ctx->prev_fiber) { StoreFiberState(g_ctx->prev_fiber, FiberState::Idle); g_ctx->prev_fiber = nullptr; @@ -633,6 +880,7 @@ s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() { } s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) { + EnsureFiberGlobalsInitialized(); if (!fiber || !name) { return ORBIS_FIBER_ERROR_NULL; } @@ -643,6 +891,12 @@ s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) { return ORBIS_FIBER_ERROR_INVALID; } + if (RazorEnabled()) { + char old_name[ORBIS_FIBER_MAX_NAME_LENGTH + 1]{}; + DecodeFiberName(fiber, old_name, sizeof(old_name)); + RazorCpuFiberLogNameChange(fiber, old_name); + } + EncodeFiberName(fiber, name); return ORBIS_OK; } @@ -657,7 +911,7 @@ s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer) { return ORBIS_FIBER_ERROR_PERMISSION; } - *addr_frame_pointer = g_ctx->rbp; + *addr_frame_pointer = g_ctx->jmp.rbp; return ORBIS_OK; } diff --git a/src/core/libraries/fiber/fiber.h b/src/core/libraries/fiber/fiber.h index 2d7e3a475..46a026b0a 100644 --- a/src/core/libraries/fiber/fiber.h +++ b/src/core/libraries/fiber/fiber.h @@ -34,18 +34,40 @@ enum FiberFlags : u32 { struct OrbisFiber; -struct OrbisFiberContext { - struct { - u64 rax, rcx, rdx, rbx, rsp, rbp, r8, r9, r10, r11, r12, r13, r14, r15; - u16 fpucw; - u32 mxcsr; - }; - OrbisFiber* current_fiber; - OrbisFiber* prev_fiber; - u64 arg_on_run_to; - u64 arg_on_return; - u64 return_val; +struct OrbisFiberJmpBuf { + u64 rsp; // 0x00 + u64 rbp; // 0x08 + u64 ret_addr; // 0x10 + u64 rbx; // 0x18 + u64 r12; // 0x20 + u64 r13; // 0x28 + u64 r14; // 0x30 + u64 r15; // 0x38 + u16 fpucw; // 0x40 + u16 pad0; // 0x42 + u32 mxcsr; // 0x44 }; +static_assert(sizeof(OrbisFiberJmpBuf) == 0x48); + +struct OrbisFiberContext { + OrbisFiberJmpBuf jmp; // 0x00 + OrbisFiber* current_fiber; // 0x48 + OrbisFiber* prev_fiber; // 0x50 + u64 arg_on_run_to; // 0x58 + u64 arg_on_return; // 0x60 + u64 return_val; // 0x68 + u64 owner_thread; // 0x70 + void* asan_fake_stack; // 0x78 + u32 reserved0; // 0x80 + u32 reserved1; // 0x84 + u32 reserved2; // 0x88 + u32 reserved3; // 0x8c +}; +static_assert(sizeof(OrbisFiberContext) == 0x90); +static_assert(offsetof(OrbisFiberContext, current_fiber) == 0x48); +static_assert(offsetof(OrbisFiberContext, arg_on_run_to) == 0x58); +static_assert(offsetof(OrbisFiberContext, owner_thread) == 0x70); +static_assert(offsetof(OrbisFiberContext, asan_fake_stack) == 0x78); struct OrbisFiberData { OrbisFiberEntry entry; @@ -53,10 +75,9 @@ struct OrbisFiberData { u64 arg_on_run_to; void* stack_addr; u32* state; - u16 fpucw; - s8 pad[2]; - u32 mxcsr; + void* asan_fake_stack; }; +static_assert(sizeof(OrbisFiberData) == 0x30); struct alignas(8) OrbisFiber { u32 magic_start; // 0x00 diff --git a/src/core/libraries/fiber/fiber_context.s b/src/core/libraries/fiber/fiber_context.s index 4c8f20f71..7e3cb33c4 100644 --- a/src/core/libraries/fiber/fiber_context.s +++ b/src/core/libraries/fiber/fiber_context.s @@ -3,75 +3,77 @@ .global _sceFiberSetJmp _sceFiberSetJmp: - movq %rax, 0x0(%rdi) + movq %rsp, 0x00(%rdi) + movq %rbp, 0x08(%rdi) - movq (%rsp), %rdx - movq %rdx, 0x10(%rdi) + movq (%rsp), %rax + movq %rax, 0x10(%rdi) - movq %rcx, 0x08(%rdi) movq %rbx, 0x18(%rdi) - movq %rsp, 0x20(%rdi) - movq %rbp, 0x28(%rdi) + movq %r12, 0x20(%rdi) + movq %r13, 0x28(%rdi) + movq %r14, 0x30(%rdi) + movq %r15, 0x38(%rdi) - movq %r8, 0x30(%rdi) - movq %r9, 0x38(%rdi) - movq %r10, 0x40(%rdi) - movq %r11, 0x48(%rdi) - movq %r12, 0x50(%rdi) - movq %r13, 0x58(%rdi) - movq %r14, 0x60(%rdi) - movq %r15, 0x68(%rdi) - - fnstcw 0x70(%rdi) - stmxcsr 0x72(%rdi) + fnstcw 0x40(%rdi) + stmxcsr 0x44(%rdi) xor %eax, %eax ret .global _sceFiberLongJmp _sceFiberLongJmp: - # MXCSR = (MXCSR & 0x3f) ^ (ctx->mxcsr & ~0x3f) - stmxcsr -0x4(%rsp) - movl 0x72(%rdi), %eax - andl $0xffffffc0, %eax - movl -0x4(%rsp), %ecx - andl $0x3f, %ecx - xorl %eax, %ecx - movl %ecx, -0x4(%rsp) - ldmxcsr -0x4(%rsp) + mov %rdi, %r11 + stmxcsr -4(%rsp) + mov 0x44(%r11), %eax + and $0xffffffc0, %eax + mov -4(%rsp), %ecx + and $0x3f, %ecx + xor %ecx, %eax + mov %eax, -4(%rsp) + ldmxcsr -4(%rsp) - movq 0x00(%rdi), %rax - movq 0x08(%rdi), %rcx - movq 0x10(%rdi), %rdx - movq 0x18(%rdi), %rbx - movq 0x20(%rdi), %rsp - movq 0x28(%rdi), %rbp + movq 0x00(%r11), %rsp + movq 0x08(%r11), %rbp + movq 0x10(%r11), %rcx + movq 0x18(%r11), %rbx + movq 0x20(%r11), %r12 + movq 0x28(%r11), %r13 + movq 0x30(%r11), %r14 + movq 0x38(%r11), %r15 - movq 0x30(%rdi), %r8 - movq 0x38(%rdi), %r9 - movq 0x40(%rdi), %r10 - movq 0x48(%rdi), %r11 - movq 0x50(%rdi), %r12 - movq 0x58(%rdi), %r13 - movq 0x60(%rdi), %r14 - movq 0x68(%rdi), %r15 + fldcw 0x40(%r11) - fldcw 0x70(%rdi) - - # Make the jump and return 1 - movq %rdx, 0x00(%rsp) + movq %rcx, 0x00(%rsp) movl $0x1, %eax ret .global _sceFiberSwitchEntry _sceFiberSwitchEntry: mov %rdi, %r11 + mov %esi, %r8d # Set stack address to provided stack movq 0x18(%r11), %rsp xorl %ebp, %ebp + movq 0x28(%r11), %rdi # data->asan_fake_stack + test %rdi, %rdi + jz .skip_asan_finish + dec %rdi + xor %rsi, %rsi + xor %rdx, %rdx + push %r11 + push %r11 + call __sanitizer_finish_switch_fiber + pop %r11 + pop %r11 +.skip_asan_finish: + + movq 0x08(%r11), %rdi # data->arg_on_initialize + movq 0x10(%r11), %rsi # data->arg_on_run_to movq 0x20(%r11), %r10 # data->state + movq 0x00(%r11), %r11 # data->entry # Set previous fiber state to Idle test %r10, %r10 @@ -79,17 +81,13 @@ _sceFiberSwitchEntry: movl $2, (%r10) .clear_regs: - test %esi, %esi + test %r8d, %r8d jz .skip_fpu_regs - ldmxcsr 0x2c(%r11) - fldcw 0x28(%r11) + ldmxcsr kFiberMxcsrDefault(%rip) + fldcw kFiberFpucwDefault(%rip) .skip_fpu_regs: - movq 0x08(%r11), %rdi # data->arg_on_initialize - movq 0x10(%r11), %rsi # data->arg_on_run_to - movq 0x00(%r11), %r11 # data->entry - xorl %eax, %eax xorl %ebx, %ebx xorl %ecx, %ecx @@ -119,3 +117,10 @@ _sceFiberSwitchEntry: movl $1, %edi call _sceFiberForceQuit ret + + .align 4 +kFiberMxcsrDefault: + .long 0x00009fc0 + .align 2 +kFiberFpucwDefault: + .short 0x037f diff --git a/src/core/libraries/kernel/memory.h b/src/core/libraries/kernel/memory.h index 9f78eb84f..dae6d48e3 100644 --- a/src/core/libraries/kernel/memory.h +++ b/src/core/libraries/kernel/memory.h @@ -186,6 +186,8 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolGetBlockStats(OrbisKernelMemoryPoolBlockStat s32 PS4_SYSV_ABI sceKernelMunmap(void* addr, u64 len); +u32 PS4_SYSV_ABI sceKernelIsAddressSanitizerEnabled(); + void RegisterMemory(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/pthread.h b/src/core/libraries/kernel/threads/pthread.h index cc1cb3829..17e5eddc5 100644 --- a/src/core/libraries/kernel/threads/pthread.h +++ b/src/core/libraries/kernel/threads/pthread.h @@ -346,6 +346,8 @@ using PthreadT = Pthread*; extern thread_local Pthread* g_curthread; +PthreadT PS4_SYSV_ABI posix_pthread_self(); + void RegisterMutex(Core::Loader::SymbolsResolver* sym); void RegisterCond(Core::Loader::SymbolsResolver* sym); void RegisterRwlock(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/libraries/razor_cpu/razor_cpu.h b/src/core/libraries/razor_cpu/razor_cpu.h index c8ed3c942..a63583efd 100644 --- a/src/core/libraries/razor_cpu/razor_cpu.h +++ b/src/core/libraries/razor_cpu/razor_cpu.h @@ -13,5 +13,8 @@ class SymbolsResolver; } namespace Libraries::RazorCpu { +void PS4_SYSV_ABI sceRazorCpuDisableFiberUserMarkers(); +s32 PS4_SYSV_ABI sceRazorCpuFiberLogNameChange(); +s32 PS4_SYSV_ABI sceRazorCpuFiberSwitch(); void RegisterLib(Core::Loader::SymbolsResolver* sym); -} // namespace Libraries::RazorCpu \ No newline at end of file +} // namespace Libraries::RazorCpu diff --git a/src/core/libraries/ulobjmgr/ulobjmgr.cpp b/src/core/libraries/ulobjmgr/ulobjmgr.cpp index ff729b3ec..9f0d6ba9c 100644 --- a/src/core/libraries/ulobjmgr/ulobjmgr.cpp +++ b/src/core/libraries/ulobjmgr/ulobjmgr.cpp @@ -10,6 +10,8 @@ namespace Libraries::Ulobjmgr { s32 PS4_SYSV_ABI Func_046DBA8411A2365C(u64 arg0, s32 arg1, u32* arg2) { + LOG_DEBUG(Lib_Ulobjmgr, "(STUBBED) called arg0={:#x} arg1={} arg2={:#x}", arg0, arg1, + reinterpret_cast(arg2)); if (arg0 == 0 || arg1 == 0 || arg2 == nullptr) { return POSIX_EINVAL; } @@ -18,10 +20,12 @@ s32 PS4_SYSV_ABI Func_046DBA8411A2365C(u64 arg0, s32 arg1, u32* arg2) { } s32 PS4_SYSV_ABI Func_1D9F50D9CFB8054E() { + LOG_DEBUG(Lib_Ulobjmgr, "(STUBBED) called"); return ORBIS_OK; } s32 PS4_SYSV_ABI Func_4A67FE7D435B94F7(u32 arg0) { + LOG_DEBUG(Lib_Ulobjmgr, "(STUBBED) called arg0={:#x}", arg0); if (arg0 >= 0x4000) { return POSIX_EINVAL; } @@ -29,6 +33,7 @@ s32 PS4_SYSV_ABI Func_4A67FE7D435B94F7(u32 arg0) { } s32 PS4_SYSV_ABI Func_4B07893BBB77A649(u64 arg0) { + LOG_DEBUG(Lib_Ulobjmgr, "(STUBBED) called arg0={:#x}", arg0); if (arg0 == 0) { return POSIX_EINVAL; } diff --git a/src/core/libraries/ulobjmgr/ulobjmgr.h b/src/core/libraries/ulobjmgr/ulobjmgr.h index baf90719c..070e5fadd 100644 --- a/src/core/libraries/ulobjmgr/ulobjmgr.h +++ b/src/core/libraries/ulobjmgr/ulobjmgr.h @@ -10,5 +10,14 @@ class SymbolsResolver; } namespace Libraries::Ulobjmgr { +// NID: BG26hBGiNlw +s32 PS4_SYSV_ABI Func_046DBA8411A2365C(u64 arg0, s32 arg1, u32* arg2); +// NID: HZ9Q2c+4BU4 +s32 PS4_SYSV_ABI Func_1D9F50D9CFB8054E(); +// NID: Smf+fUNblPc +s32 PS4_SYSV_ABI Func_4A67FE7D435B94F7(u32 arg0); +// NID: SweJO7t3pkk +s32 PS4_SYSV_ABI Func_4B07893BBB77A649(u64 arg0); + void RegisterLib(Core::Loader::SymbolsResolver* sym); -} // namespace Libraries::Ulobjmgr \ No newline at end of file +} // namespace Libraries::Ulobjmgr diff --git a/src/core/tls.h b/src/core/tls.h index 83940be7a..04f694489 100644 --- a/src/core/tls.h +++ b/src/core/tls.h @@ -60,8 +60,11 @@ void ClearStack() { template ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) { EnsureThreadInitialized(); - // clear stack to avoid trash from EnsureThreadInitialized - ClearStack<12_KB>(); + // clear stack to avoid trash from EnsureThreadInitialized (skip on fiber stacks) + auto* tcb = GetTcbBase(); + if (tcb == nullptr || tcb->tcb_fiber == nullptr) { + ClearStack<12_KB>(); + } return func(std::forward(args)...); }