Skip to content

Commit

Permalink
The way to Unity, pt.3 (#1681)
Browse files Browse the repository at this point in the history
  • Loading branch information
polybiusproxy authored Dec 8, 2024
1 parent 1793fd4 commit fea2593
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 50 deletions.
2 changes: 2 additions & 0 deletions src/common/ntapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ NtClose_t NtClose = nullptr;
NtSetInformationFile_t NtSetInformationFile = nullptr;
NtCreateThread_t NtCreateThread = nullptr;
NtTerminateThread_t NtTerminateThread = nullptr;
NtQueueApcThreadEx_t NtQueueApcThreadEx = nullptr;

namespace Common::NtApi {

Expand All @@ -21,6 +22,7 @@ void Initialize() {
(NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile");
NtCreateThread = (NtCreateThread_t)GetProcAddress(nt_handle, "NtCreateThread");
NtTerminateThread = (NtTerminateThread_t)GetProcAddress(nt_handle, "NtTerminateThread");
NtQueueApcThreadEx = (NtQueueApcThreadEx_t)GetProcAddress(nt_handle, "NtQueueApcThreadEx");
}

} // namespace Common::NtApi
Expand Down
20 changes: 20 additions & 0 deletions src/common/ntapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,20 @@ typedef struct _TEB { /* win32/win64 */
static_assert(offsetof(TEB, DeallocationStack) ==
0x1478); /* The only member we care about at the moment */

typedef enum _QUEUE_USER_APC_FLAGS {
QueueUserApcFlagsNone,
QueueUserApcFlagsSpecialUserApc,
QueueUserApcFlagsMaxValue
} QUEUE_USER_APC_FLAGS;

typedef union _USER_APC_OPTION {
ULONG_PTR UserApcFlags;
HANDLE MemoryReserveHandle;
} USER_APC_OPTION, *PUSER_APC_OPTION;

using PPS_APC_ROUTINE = void (*)(PVOID ApcArgument1, PVOID ApcArgument2, PVOID ApcArgument3,
PCONTEXT Context);

typedef u64(__stdcall* NtClose_t)(HANDLE Handle);

typedef u64(__stdcall* NtSetInformationFile_t)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
Expand All @@ -522,10 +536,16 @@ typedef u64(__stdcall* NtCreateThread_t)(PHANDLE ThreadHandle, ACCESS_MASK Desir

typedef u64(__stdcall* NtTerminateThread_t)(HANDLE ThreadHandle, u64 ExitStatus);

typedef u64(__stdcall* NtQueueApcThreadEx_t)(HANDLE ThreadHandle,
USER_APC_OPTION UserApcReserveHandle,
PPS_APC_ROUTINE ApcRoutine, PVOID ApcArgument1,
PVOID ApcArgument2, PVOID ApcArgument3);

extern NtClose_t NtClose;
extern NtSetInformationFile_t NtSetInformationFile;
extern NtCreateThread_t NtCreateThread;
extern NtTerminateThread_t NtTerminateThread;
extern NtQueueApcThreadEx_t NtQueueApcThreadEx;

namespace Common::NtApi {
void Initialize();
Expand Down
2 changes: 2 additions & 0 deletions src/core/libraries/ajm/ajm_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "common/assert.h"
#include "common/logging/log.h"
#include "common/thread.h"
#include "core/libraries/ajm/ajm.h"
#include "core/libraries/ajm/ajm_at9.h"
#include "core/libraries/ajm/ajm_context.h"
Expand Down Expand Up @@ -53,6 +54,7 @@ s32 AjmContext::ModuleRegister(AjmCodecType type) {
}

void AjmContext::WorkerThread(std::stop_token stop) {
Common::SetCurrentThreadName("shadPS4:AjmWorker");
while (!stop.stop_requested()) {
auto batch = batch_queue.PopWait(stop);
if (batch != nullptr) {
Expand Down
3 changes: 2 additions & 1 deletion src/core/libraries/kernel/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void KernelSignalRequest() {
}

static void KernelServiceThread(std::stop_token stoken) {
Common::SetCurrentThreadName("shadPS4:Kernel_ServiceThread");
Common::SetCurrentThreadName("shadPS4:KernelServiceThread");

while (!stoken.stop_requested()) {
HLE_TRACE;
Expand Down Expand Up @@ -255,6 +255,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("FN4gaPmuFV8", "libScePosix", 1, "libkernel", 1, 1, ps4__write);
}

} // namespace Libraries::Kernel
3 changes: 1 addition & 2 deletions src/core/libraries/kernel/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,7 @@ int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
return ORBIS_OK;
}
auto* memory = Core::Memory::Instance();
memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);
return ORBIS_OK;
return memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);
}

int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
Expand Down
15 changes: 11 additions & 4 deletions src/core/libraries/kernel/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t arg

// Load PRX module and relocate any modules that import it.
auto* linker = Common::Singleton<Core::Linker>::Instance();
u32 handle = linker->LoadModule(path, true);
if (handle == -1) {
return ORBIS_KERNEL_ERROR_EINVAL;
u32 handle = linker->FindByName(path);
if (handle != -1) {
return handle;
}
handle = linker->LoadModule(path, true);
auto* module = linker->GetModule(handle);
linker->RelocateAnyImports(module);

Expand All @@ -60,7 +61,10 @@ s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t arg
// Retrieve and verify proc param according to libkernel.
u64* param = module->GetProcParam<u64*>();
ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]);
module->Start(args, argp, param);
s32 ret = module->Start(args, argp, param);
if (pRes) {
*pRes = ret;
}

return handle;
}
Expand Down Expand Up @@ -104,6 +108,9 @@ s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, int flags,
LOG_INFO(Lib_Kernel, "called addr = {:#x}, flags = {:#x}", addr, flags);
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* module = linker->FindByAddress(addr);
if (!module) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
const auto mod_info = module->GetModuleInfoEx();

// Fill in module info.
Expand Down
42 changes: 29 additions & 13 deletions src/core/libraries/kernel/sync/semaphore.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,23 @@ class Semaphore {
template <class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time) {
#ifdef _WIN64
const auto rel_time_ms = std::chrono::ceil<std::chrono::milliseconds>(rel_time);
const u64 timeout_ms = static_cast<u64>(rel_time_ms.count());
const auto start_time = std::chrono::high_resolution_clock::now();
auto rel_time_ms = std::chrono::ceil<std::chrono::milliseconds>(rel_time);

if (timeout_ms == 0) {
return false;
while (rel_time_ms.count() > 0) {
u64 timeout_ms = static_cast<u64>(rel_time_ms.count());
u64 res = WaitForSingleObjectEx(sem, timeout_ms, true);
if (res == WAIT_OBJECT_0) {
return true;
} else if (res == WAIT_IO_COMPLETION) {
auto elapsed_time = std::chrono::high_resolution_clock::now() - start_time;
rel_time_ms -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time);
} else {
return false;
}
}

return WaitForSingleObjectEx(sem, timeout_ms, true) == WAIT_OBJECT_0;
return false;
#elif defined(__APPLE__)
const auto rel_time_ns = std::chrono::ceil<std::chrono::nanoseconds>(rel_time).count();
const auto timeout = dispatch_time(DISPATCH_TIME_NOW, rel_time_ns);
Expand All @@ -107,19 +116,26 @@ class Semaphore {
template <class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
#ifdef _WIN64
const auto now = Clock::now();
if (now >= abs_time) {
const auto start_time = Clock::now();
if (start_time >= abs_time) {
return false;
}

const auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - now);
const u64 timeout_ms = static_cast<u64>(rel_time.count());
if (timeout_ms == 0) {
return false;
auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - start_time);
while (rel_time.count() > 0) {
u64 timeout_ms = static_cast<u64>(rel_time.count());
u64 res = WaitForSingleObjectEx(sem, timeout_ms, true);
if (res == WAIT_OBJECT_0) {
return true;
} else if (res == WAIT_IO_COMPLETION) {
auto elapsed_time = Clock::now() - start_time;
rel_time -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time);
} else {
return false;
}
}

u64 res = WaitForSingleObjectEx(sem, static_cast<u64>(timeout_ms), true);
return res == WAIT_OBJECT_0;
return false;
#elif defined(__APPLE__)
auto abs_s = std::chrono::time_point_cast<std::chrono::seconds>(abs_time);
auto abs_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(abs_time) -
Expand Down
30 changes: 29 additions & 1 deletion src/core/libraries/kernel/threads/event_flag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,33 @@ class EventFlagInternal {
m_bits &= bits;
}

void Cancel(u64 setPattern, int* numWaitThreads) {
std::unique_lock lock{m_mutex};

while (m_status != Status::Set) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}

if (numWaitThreads) {
*numWaitThreads = m_waiting_threads;
}

m_status = Status::Canceled;
m_bits = setPattern;

m_cond_var.notify_all();

while (m_waiting_threads > 0) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}

m_status = Status::Set;
}

private:
enum class Status { Set, Canceled, Deleted };

Expand Down Expand Up @@ -232,7 +259,8 @@ int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern

int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern,
int* pNumWaitThreads) {
LOG_ERROR(Kernel_Event, "(STUBBED) called");
LOG_DEBUG(Kernel_Event, "called");
ef->Cancel(setPattern, pNumWaitThreads);
return ORBIS_OK;
}

Expand Down
50 changes: 40 additions & 10 deletions src/core/libraries/kernel/threads/exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "core/libraries/libs.h"

#ifdef _WIN64
#include "common/ntapi.h"
#else
#include <signal.h>
#endif
Expand Down Expand Up @@ -64,6 +65,34 @@ void SigactionHandler(int signum, siginfo_t* inf, ucontext_t* raw_context) {
handler(POSIX_SIGUSR1, &ctx);
}
}
#else
void ExceptionHandler(void* arg1, void* arg2, void* arg3, PCONTEXT context) {
const char* thrName = (char*)arg1;
LOG_INFO(Lib_Kernel, "Exception raised successfully on thread '{}'", thrName);
const auto handler = Handlers[POSIX_SIGUSR1];
if (handler) {
auto ctx = Ucontext{};
ctx.uc_mcontext.mc_r8 = context->R8;
ctx.uc_mcontext.mc_r9 = context->R9;
ctx.uc_mcontext.mc_r10 = context->R10;
ctx.uc_mcontext.mc_r11 = context->R11;
ctx.uc_mcontext.mc_r12 = context->R12;
ctx.uc_mcontext.mc_r13 = context->R13;
ctx.uc_mcontext.mc_r14 = context->R14;
ctx.uc_mcontext.mc_r15 = context->R15;
ctx.uc_mcontext.mc_rdi = context->Rdi;
ctx.uc_mcontext.mc_rsi = context->Rsi;
ctx.uc_mcontext.mc_rbp = context->Rbp;
ctx.uc_mcontext.mc_rbx = context->Rbx;
ctx.uc_mcontext.mc_rdx = context->Rdx;
ctx.uc_mcontext.mc_rax = context->Rax;
ctx.uc_mcontext.mc_rcx = context->Rcx;
ctx.uc_mcontext.mc_rsp = context->Rsp;
ctx.uc_mcontext.mc_fs = context->SegFs;
ctx.uc_mcontext.mc_gs = context->SegGs;
handler(POSIX_SIGUSR1, &ctx);
}
}
#endif

int PS4_SYSV_ABI sceKernelInstallExceptionHandler(s32 signum, SceKernelExceptionHandler handler) {
Expand All @@ -73,9 +102,7 @@ int PS4_SYSV_ABI sceKernelInstallExceptionHandler(s32 signum, SceKernelException
}
ASSERT_MSG(!Handlers[POSIX_SIGUSR1], "Invalid parameters");
Handlers[POSIX_SIGUSR1] = handler;
#ifdef _WIN64
UNREACHABLE_MSG("Missing exception implementation");
#else
#ifndef _WIN64
struct sigaction act = {};
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.sa_sigaction = reinterpret_cast<decltype(act.sa_sigaction)>(SigactionHandler);
Expand All @@ -91,9 +118,7 @@ int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 signum) {
}
ASSERT_MSG(Handlers[POSIX_SIGUSR1], "Invalid parameters");
Handlers[POSIX_SIGUSR1] = nullptr;
#ifdef _WIN64
UNREACHABLE_MSG("Missing exception implementation");
#else
#ifndef _WIN64
struct sigaction act = {};
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.sa_sigaction = nullptr;
Expand All @@ -103,13 +128,18 @@ int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 signum) {
}

int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) {
LOG_ERROR(Lib_Kernel, "Raising exception");
LOG_WARNING(Lib_Kernel, "Raising exception on thread '{}'", thread->name);
ASSERT_MSG(signum == POSIX_SIGUSR1, "Attempting to raise non user defined signal!");
#ifdef _WIN64
UNREACHABLE_MSG("Missing exception implementation");
#else
#ifndef _WIN64
pthread_t pthr = *reinterpret_cast<pthread_t*>(thread->native_thr.GetHandle());
pthread_kill(pthr, SIGUSR2);
#else
USER_APC_OPTION option;
option.UserApcFlags = QueueUserApcFlagsSpecialUserApc;

u64 res = NtQueueApcThreadEx(reinterpret_cast<HANDLE>(thread->native_thr.GetHandle()), option,
ExceptionHandler, (void*)thread->name.c_str(), nullptr, nullptr);
ASSERT(res == 0);
#endif
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/libraries/kernel/threads/pthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("onNY9Byn-W8", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_join));
LIB_FUNCTION("P41kTWUS3EI", "libkernel", 1, "libkernel", 1, 1,
ORBIS(posix_pthread_getschedparam));
LIB_FUNCTION("oIRFTjoILbg", "libkernel", 1, "libkernel", 1, 1,
ORBIS(posix_pthread_setschedparam));
LIB_FUNCTION("How7B8Oet6k", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_getname_np));
LIB_FUNCTION("3kg7rT0NQIs", "libkernel", 1, "libkernel", 1, 1, posix_pthread_exit);
LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
Expand Down
Loading

0 comments on commit fea2593

Please sign in to comment.