mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-11-26 20:50:40 +00:00
WIP
This commit is contained in:
parent
749fe92882
commit
522a74ee7e
@ -107,6 +107,10 @@ check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMED
|
||||
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
|
||||
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
endif()
|
||||
check_symbol_exists(sem_timedwait "semaphore.h" HAVE_SEM_TIMEDWAIT)
|
||||
if(HAVE_SEM_TIMEDWAIT OR WIN32)
|
||||
add_compile_options(-DHAVE_SEM_TIMEDWAIT)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
|
||||
@ -184,10 +188,12 @@ set(KERNEL_LIB
|
||||
src/core/libraries/kernel/libkernel.h
|
||||
src/core/libraries/kernel/memory_management.cpp
|
||||
src/core/libraries/kernel/memory_management.h
|
||||
src/core/libraries/kernel/orbis_signals.h
|
||||
src/core/libraries/kernel/thread_management.cpp
|
||||
src/core/libraries/kernel/thread_management.h
|
||||
src/core/libraries/kernel/time_management.cpp
|
||||
src/core/libraries/kernel/time_management.h
|
||||
src/core/libraries/kernel/win32_signals.cpp
|
||||
)
|
||||
|
||||
set(NETWORK_LIBS src/core/libraries/network/http.cpp
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include <mutex> // std::unique_lock
|
||||
|
||||
namespace Audio {
|
||||
SDLAudio::~SDLAudio() {
|
||||
std::unique_lock lock{m_mutex};
|
||||
}
|
||||
|
||||
int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
|
||||
Libraries::AudioOut::OrbisAudioOutParamFormat format) {
|
||||
|
@ -12,7 +12,7 @@ namespace Audio {
|
||||
class SDLAudio {
|
||||
public:
|
||||
SDLAudio() = default;
|
||||
virtual ~SDLAudio() = default;
|
||||
~SDLAudio();
|
||||
|
||||
int AudioOutOpen(int type, u32 samples_num, u32 freq,
|
||||
Libraries::AudioOut::OrbisAudioOutParamFormat format);
|
||||
|
@ -1,10 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
@ -19,14 +16,20 @@
|
||||
#include "core/libraries/kernel/event_flag/event_flag.h"
|
||||
#include "core/libraries/kernel/event_queues.h"
|
||||
#include "core/libraries/kernel/file_system.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/kernel/memory_management.h"
|
||||
#include "core/libraries/kernel/orbis_signals.h"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/linker.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <io.h>
|
||||
#include <objbase.h>
|
||||
@ -86,11 +89,11 @@ static PS4_SYSV_ABI void stack_chk_fail() {
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
|
||||
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}", fmt::ptr(addr), len);
|
||||
if (len == 0) {
|
||||
return ORBIS_OK;
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);
|
||||
return SCE_OK;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
struct iovec {
|
||||
@ -398,6 +401,70 @@ int PS4_SYSV_ABI posix_getpagesize() {
|
||||
return 4096;
|
||||
}
|
||||
|
||||
int sceKernelError(int err) {
|
||||
if (err == 0) {
|
||||
return 0;
|
||||
}
|
||||
return err + -SCE_KERNEL_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelRaiseException(ScePthread thread, s32 sig) {
|
||||
LOG_INFO(Lib_Kernel, "called. thread = {} sig = {}", uintptr_t(thread), sig);
|
||||
if (sig != ORBIS_SIGUSR1) {
|
||||
return sceKernelError(POSIX_EINVAL);
|
||||
}
|
||||
Orbis::pthread_kill(thread->pth, sig);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
using ExceptionHandler = void (*PS4_SYSV_ABI)(s32, void*);
|
||||
|
||||
static std::atomic<ExceptionHandler> g_exception_handlers[32];
|
||||
|
||||
void ExceptionSignalHandler(s32 sig, Orbis::siginfo_t*, void* context) {
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
if (sig > ORBIS_SIG_MAXSIG32) {
|
||||
return;
|
||||
}
|
||||
const auto handler = g_exception_handlers[ORBIS_SIG_IDX(sig)].load();
|
||||
if (intptr_t(handler) > 0) {
|
||||
handler(sig, context);
|
||||
}
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelInstallExceptionHandler(s32 sig, ExceptionHandler handler) {
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
if (sig > ORBIS_SIG_MAXSIG32) {
|
||||
return sceKernelError(POSIX_EINVAL);
|
||||
}
|
||||
|
||||
auto expected = ExceptionHandler(nullptr);
|
||||
if (!g_exception_handlers[ORBIS_SIG_IDX(sig)].compare_exchange_strong(expected, handler)) {
|
||||
return sceKernelError(POSIX_EAGAIN);
|
||||
}
|
||||
|
||||
struct Orbis::sigaction sact = {
|
||||
.sa_sigaction = &ExceptionSignalHandler,
|
||||
.sa_flags = ORBIS_SA_RESTART,
|
||||
};
|
||||
return sceKernelError(Orbis::sigaction(sig, &sact, nullptr));
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 sig) {
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
if (sig > ORBIS_SIG_MAXSIG32) {
|
||||
return sceKernelError(POSIX_EINVAL);
|
||||
}
|
||||
auto expected = g_exception_handlers[sig - 1].load();
|
||||
if (!g_exception_handlers[ORBIS_SIG_IDX(sig)].compare_exchange_strong(expected, nullptr)) {
|
||||
return sceKernelError(POSIX_EAGAIN);
|
||||
}
|
||||
struct Orbis::sigaction sact = {
|
||||
.sa_flags = ORBIS_SA_RESETHAND,
|
||||
};
|
||||
return sceKernelError(Orbis::sigaction(sig, &sact, nullptr));
|
||||
}
|
||||
|
||||
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||
service_thread = std::jthread{KernelServiceThread};
|
||||
|
||||
@ -471,6 +538,10 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
|
||||
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
|
||||
|
||||
LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1,
|
||||
sceKernelInstallExceptionHandler);
|
||||
LIB_FUNCTION("il03nluKfMk", "libkernel_unity", 1, "libkernel", 1, 1, sceKernelRaiseException);
|
||||
|
||||
Libraries::Kernel::fileSystemSymbolsRegister(sym);
|
||||
Libraries::Kernel::timeSymbolsRegister(sym);
|
||||
Libraries::Kernel::pthreadSymbolsRegister(sym);
|
||||
|
185
src/core/libraries/kernel/orbis_signals.h
Normal file
185
src/core/libraries/kernel/orbis_signals.h
Normal file
@ -0,0 +1,185 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define ORBIS_SA_RESTART 0x0002
|
||||
#define ORBIS_SA_RESETHAND 0x0004
|
||||
#define ORBIS_SA_NODEFER 0x0010
|
||||
#define ORBIS_SA_SIGINFO 0x0040
|
||||
|
||||
#define ORBIS_SIGKILL 9
|
||||
#define ORBIS_SIGURG 16
|
||||
#define ORBIS_SIGSTOP 17
|
||||
#define ORBIS_SIGCHLD 20
|
||||
#define ORBIS_SIGWINCH 28
|
||||
#define ORBIS_SIGINFO 29
|
||||
#define ORBIS_SIGUSR1 30
|
||||
|
||||
#define ORBIS_SI_USER 0x10001
|
||||
|
||||
#define ORBIS_SIG_WORDS 4
|
||||
#define ORBIS_SIG_MAXSIG 128
|
||||
#define ORBIS_SIG_MAXSIG32 32
|
||||
#define ORBIS_SIG_IDX(sig) ((sig)-1)
|
||||
#define ORBIS_SIG_WORD(sig) (_SIG_IDX(sig) >> 5)
|
||||
#define ORBIS_SIG_BIT(sig) (1 << (_SIG_IDX(sig) & 31))
|
||||
#define ORBIS_SIG_VALID(sig) ((sig) <= _SIG_MAXSIG && (sig) > 0)
|
||||
|
||||
#define ORBIS_SIG_ERR (uintptr_t(-1))
|
||||
#define ORBIS_SIG_DFL (uintptr_t(0))
|
||||
#define ORBIS_SIG_IGN (uintptr_t(1))
|
||||
#define ORBIS_SIG_CATCH (uintptr_t(2))
|
||||
#define ORBIS_SIG_HOLD (uintptr_t(3))
|
||||
|
||||
#define ORBIS_SS_ONSTACK 0x0001; // take signal on alternate stack
|
||||
#define ORBIS_SS_DISABLE 0x0004; // disable taking signals on alternate stack
|
||||
#define ORBIS_MINSIGSTKSZ (512 * 4); // minimum stack size
|
||||
#define ORBIS_SIGSTKSZ (MINSIGSTKSZ + 0x8000); // recommended stack size
|
||||
|
||||
#define ORBIS_UC_SIGMASK 0x01; // valid uc_sigmask
|
||||
#define ORBIS_UC_STACK 0x02; // valid uc_stack
|
||||
#define ORBIS_UC_CPU 0x04; // valid GPR context in uc_mcontext
|
||||
#define ORBIS_UC_FPU 0x08; // valid FPU context in uc_mcontext
|
||||
|
||||
#define ORBIS_MC_HASSEGS 0x01
|
||||
#define ORBIS_MC_FPFMT_XMM 0x10002
|
||||
#define ORBIS_MC_FPOWNED_FPU 0x20001 // FP state came from FPU
|
||||
|
||||
namespace Orbis {
|
||||
using pid_t = u32;
|
||||
using uid_t = u32;
|
||||
|
||||
union sigval {
|
||||
/* Members as suggested by Annex C of POSIX 1003.1b. */
|
||||
s32 sival_int;
|
||||
void* sival_ptr;
|
||||
/* 6.0 compatibility */
|
||||
s32 sigval_int;
|
||||
void* sigval_ptr;
|
||||
};
|
||||
|
||||
struct siginfo_t {
|
||||
s32 si_signo; /* signal number */
|
||||
s32 si_errno; /* errno association */
|
||||
/*
|
||||
* Cause of signal, one of the SI_ macros or signal-specific
|
||||
* values, i.e. one of the FPE_... values for SIGFPE. This
|
||||
* value is equivalent to the second argument to an old-style
|
||||
* FreeBSD signal handler.
|
||||
*/
|
||||
s32 si_code; /* signal code */
|
||||
pid_t si_pid; /* sending process */
|
||||
uid_t si_uid; /* sender's ruid */
|
||||
s32 si_status; /* exit value */
|
||||
void* si_addr; /* faulting instruction */
|
||||
sigval si_value; /* signal value */
|
||||
union {
|
||||
struct {
|
||||
s32 _trapno; /* machine specific trap code */
|
||||
} _fault;
|
||||
struct {
|
||||
s32 _timerid;
|
||||
s32 _overrun;
|
||||
} _timer;
|
||||
struct {
|
||||
s32 _mqd;
|
||||
} _mesgq;
|
||||
struct {
|
||||
s64 _band; /* band event for SIGPOLL */
|
||||
} _poll; /* was this ever used ? */
|
||||
struct {
|
||||
s64 __spare1__;
|
||||
s32 __spare2__[7];
|
||||
} __spare__;
|
||||
} _reason;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct sigset_t {
|
||||
u32 __bits[ORBIS_SIG_WORDS];
|
||||
};
|
||||
|
||||
struct mcontext_t {
|
||||
s64 mc_onstack; /* sigstack state to restore */
|
||||
s64 mc_rdi; /* machine state (struct trapframe) */
|
||||
s64 mc_rsi;
|
||||
s64 mc_rdx;
|
||||
s64 mc_rcx;
|
||||
s64 mc_r8;
|
||||
s64 mc_r9;
|
||||
s64 mc_rax;
|
||||
s64 mc_rbx;
|
||||
s64 mc_rbp;
|
||||
s64 mc_r10;
|
||||
s64 mc_r11;
|
||||
s64 mc_r12;
|
||||
s64 mc_r13;
|
||||
s64 mc_r14;
|
||||
s64 mc_r15;
|
||||
s32 mc_trapno;
|
||||
s16 mc_fs;
|
||||
s16 mc_gs;
|
||||
s64 mc_addr;
|
||||
s32 mc_flags;
|
||||
s16 mc_es;
|
||||
s16 mc_ds;
|
||||
s64 mc_err;
|
||||
s64 mc_rip;
|
||||
s64 mc_cs;
|
||||
s64 mc_rflags;
|
||||
s64 mc_rsp;
|
||||
s64 mc_ss;
|
||||
s64 mc_len; /* sizeof(mcontext_t) */
|
||||
s64 mc_fpformat;
|
||||
s64 mc_ownedfp;
|
||||
s64 mc_lbrfrom;
|
||||
s64 mc_lbrto;
|
||||
s64 mc_aux1;
|
||||
s64 mc_aux2;
|
||||
s64 mc_fpstate[104];
|
||||
s64 mc_fsbase;
|
||||
s64 mc_gsbase;
|
||||
s64 mc_spare[6];
|
||||
};
|
||||
|
||||
struct stack_t {
|
||||
void* ss_sp; // signal stack base
|
||||
size_t ss_size; // signal stack length SIGSTKSZ
|
||||
s32 ss_flags; // SS_DISABLE and/or SS_ONSTACK
|
||||
s32 _align;
|
||||
};
|
||||
|
||||
struct ucontext_t {
|
||||
sigset_t sc_mask; /* signal mask to restore */
|
||||
s32 field1_0x10[12];
|
||||
struct mcontext_t uc_mcontext;
|
||||
struct ucontext_t* uc_link;
|
||||
struct stack_t uc_stack;
|
||||
s32 uc_flags;
|
||||
s32 __spare[4];
|
||||
s32 field7_0x4f4[3];
|
||||
};
|
||||
|
||||
struct sigaction {
|
||||
union {
|
||||
void (*sa_handler)(s32, s32, void*);
|
||||
void (*sa_sigaction)(s32, siginfo_t*, void*);
|
||||
};
|
||||
s32 sa_flags;
|
||||
sigset_t sa_mask;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(ucontext_t) == 0x500);
|
||||
|
||||
using pthread_t = uintptr_t;
|
||||
|
||||
s32 sigaction(s32 sig, const struct sigaction* act, struct sigaction* oldact);
|
||||
s32 pthread_kill(pthread_t thread, s32 sig);
|
||||
|
||||
} // namespace Orbis
|
@ -1,10 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <thread>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
@ -19,6 +15,12 @@
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/linker.h"
|
||||
#include "core/tls.h"
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#else
|
||||
@ -1373,97 +1375,90 @@ int PS4_SYSV_ABI posix_pthread_detach(ScePthread thread) {
|
||||
return pthread_detach(thread->pth);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_init(PthreadSemInternal** sem, int pshared, unsigned int value) {
|
||||
if (value > ORBIS_KERNEL_SEM_VALUE_MAX) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_init(sem_t* sem, int pshared, unsigned int value) {
|
||||
int result = sem_init(sem, pshared, value);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
if (sem != nullptr) {
|
||||
*sem = new PthreadSemInternal{
|
||||
.semaphore = std::counting_semaphore<ORBIS_KERNEL_SEM_VALUE_MAX>{value},
|
||||
.value = {static_cast<int>(value)},
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_wait(PthreadSemInternal** sem) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_wait(sem_t* sem) {
|
||||
int result = sem_wait(sem);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
(*sem)->semaphore.acquire();
|
||||
--(*sem)->value;
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_trywait(PthreadSemInternal** sem) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_trywait(sem_t* sem) {
|
||||
int result = sem_trywait(sem);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
if (!(*sem)->semaphore.try_acquire()) {
|
||||
SetPosixErrno(EAGAIN);
|
||||
return -1;
|
||||
}
|
||||
--(*sem)->value;
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_timedwait(PthreadSemInternal** sem, const timespec* t) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
#ifndef HAVE_SEM_TIMEDWAIT
|
||||
int sem_timedwait(sem_t* sem, const struct timespec* abstime) {
|
||||
int rc;
|
||||
while ((rc = sem_trywait(sem)) == EAGAIN) {
|
||||
struct timespec curr_time;
|
||||
clock_gettime(CLOCK_REALTIME, &curr_time);
|
||||
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::nanoseconds;
|
||||
using std::chrono::seconds;
|
||||
using std::chrono::system_clock;
|
||||
s64 remaining_ns = 0;
|
||||
remaining_ns +=
|
||||
(static_cast<s64>(abstime->tv_sec) - static_cast<s64>(curr_time.tv_sec)) * 1000000000L;
|
||||
remaining_ns += static_cast<s64>(abstime->tv_nsec) - static_cast<s64>(curr_time.tv_nsec);
|
||||
|
||||
const system_clock::time_point time{
|
||||
duration_cast<system_clock::duration>(seconds{t->tv_sec} + nanoseconds{t->tv_nsec})};
|
||||
if (!(*sem)->semaphore.try_acquire_until(time)) {
|
||||
SetPosixErrno(ETIMEDOUT);
|
||||
return -1;
|
||||
if (remaining_ns <= 0) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
struct timespec sleep_time;
|
||||
sleep_time.tv_sec = 0;
|
||||
if (remaining_ns < 5000000L) {
|
||||
sleep_time.tv_nsec = remaining_ns;
|
||||
} else {
|
||||
sleep_time.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&sleep_time, nullptr);
|
||||
}
|
||||
--(*sem)->value;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_timedwait(sem_t* sem, const timespec* t) {
|
||||
int result = sem_timedwait(sem, t);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_post(PthreadSemInternal** sem) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_post(sem_t* sem) {
|
||||
int result = sem_post(sem);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
if ((*sem)->value == ORBIS_KERNEL_SEM_VALUE_MAX) {
|
||||
SetPosixErrno(EOVERFLOW);
|
||||
return -1;
|
||||
}
|
||||
++(*sem)->value;
|
||||
(*sem)->semaphore.release();
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_destroy(PthreadSemInternal** sem) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_destroy(sem_t* sem) {
|
||||
int result = sem_destroy(sem);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
delete *sem;
|
||||
*sem = nullptr;
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_getvalue(PthreadSemInternal** sem, int* sval) {
|
||||
if (sem == nullptr || *sem == nullptr) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
int PS4_SYSV_ABI posix_sem_getvalue(sem_t* sem, int* sval) {
|
||||
int result = sem_getvalue(sem, sval);
|
||||
if (result == -1) {
|
||||
SetPosixErrno(errno);
|
||||
}
|
||||
if (sval) {
|
||||
*sval = (*sem)->value;
|
||||
}
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* size) {
|
||||
|
@ -112,11 +112,6 @@ struct PthreadRwInternal {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct PthreadSemInternal {
|
||||
std::counting_semaphore<ORBIS_KERNEL_SEM_VALUE_MAX> semaphore;
|
||||
std::atomic<s32> value;
|
||||
};
|
||||
|
||||
class PThreadPool {
|
||||
public:
|
||||
ScePthread Create();
|
||||
|
325
src/core/libraries/kernel/win32_signals.cpp
Normal file
325
src/core/libraries/kernel/win32_signals.cpp
Normal file
@ -0,0 +1,325 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/libraries/kernel/orbis_signals.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include "common/assert.h"
|
||||
#include "common/enum.h"
|
||||
#include "common/error.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
#include "pthread.h"
|
||||
extern "C" {
|
||||
// Hack to get winpthreads internal state to get detached thread handle
|
||||
#include "externals/winpthreads/src/thread.h"
|
||||
}
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#define NTDLL_VERSION_WIN10_RS5_1809 17763
|
||||
#define DR7_LAST_BRANCH 0x100
|
||||
|
||||
enum QUEUE_USER_APC_FLAGS {
|
||||
QUEUE_USER_APC_FLAGS_NONE = 0x00000000,
|
||||
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC = 0x00000001,
|
||||
QUEUE_USER_APC_CALLBACK_DATA_CONTEXT = 0x00010000,
|
||||
};
|
||||
|
||||
using NTSTATUS = LONG;
|
||||
using PPS_APC_ROUTINE = VOID(NTAPI*)(PVOID, PVOID, PVOID, PCONTEXT);
|
||||
union USER_APC_OPTION {
|
||||
ULONG_PTR UserApcFlags;
|
||||
HANDLE MemoryReserveHandle;
|
||||
};
|
||||
|
||||
using PNT_QUEUE_APC_THREAD_EX = NTSTATUS(NTAPI*)(HANDLE, USER_APC_OPTION, PPS_APC_ROUTINE, PVOID,
|
||||
PVOID, PVOID);
|
||||
|
||||
static PNT_QUEUE_APC_THREAD_EX pfnNtQueueApcThreadEx;
|
||||
|
||||
struct Orbis::sigaction g_sigacts[ORBIS_SIG_MAXSIG32];
|
||||
|
||||
static FARPROC GetModuleProcAddr(const wchar_t* dll, u16 min_version, const char* proc_name) {
|
||||
// DWORD ver_handle = 0;
|
||||
// DWORD ver_size = GetFileVersionInfoSizeW(dll, &ver_handle);
|
||||
// if (ver_size == 0) {
|
||||
// UNREACHABLE_MSG("Could not get {} version", dll);
|
||||
// }
|
||||
// std::vector<s8> ver_buf(ver_size, 0);
|
||||
// if (GetFileVersionInfoW(dll, ver_handle, ver_size, ver_buf.data()) == FALSE) {
|
||||
// UNREACHABLE_MSG("Could not get {} version", dll);
|
||||
// }
|
||||
|
||||
// UINT size = 0;
|
||||
// LPBYTE buffer = NULL;
|
||||
// if (VerQueryValueW(ver_buf.data(), L"\\", (VOID FAR * FAR*)&buffer, &size) == FALSE ||
|
||||
// size == 0) {
|
||||
// UNREACHABLE_MSG("Could not get {} version", dll);
|
||||
// }
|
||||
|
||||
// const VS_FIXEDFILEINFO* p_ver = (VS_FIXEDFILEINFO*)buffer;
|
||||
// const u16 version = (p_ver->dwProductVersionLS >> 16 & 0xFFFF);
|
||||
// ASSERT_MSG(version >= min_version, "Your Windows version is too old, please update.");
|
||||
|
||||
return GetProcAddress(GetModuleHandleW(dll), proc_name);
|
||||
}
|
||||
|
||||
NTSTATUS NtQueueApcThreadEx(HANDLE ThreadHandle, USER_APC_OPTION UserApcOption,
|
||||
PPS_APC_ROUTINE ApcRoutine, PVOID arg1, PVOID arg2, PVOID arg3) {
|
||||
LOG_INFO(Lib_Kernel, "called");
|
||||
static const auto pfn = reinterpret_cast<PNT_QUEUE_APC_THREAD_EX>(
|
||||
GetModuleProcAddr(L"ntdll.dll", NTDLL_VERSION_WIN10_RS5_1809, "NtQueueApcThreadEx"));
|
||||
return pfn(ThreadHandle, UserApcOption, ApcRoutine, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
namespace Orbis {
|
||||
|
||||
static uintptr_t SigDfl(int sig) {
|
||||
switch (sig) {
|
||||
case ORBIS_SIGURG:
|
||||
case ORBIS_SIGCHLD:
|
||||
case ORBIS_SIGWINCH:
|
||||
case ORBIS_SIGINFO:
|
||||
return ORBIS_SIG_IGN;
|
||||
default:
|
||||
return ORBIS_SIG_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
static uintptr_t SigActType(s32 sig, const struct sigaction& act) {
|
||||
switch (reinterpret_cast<uintptr_t>(act.sa_sigaction)) {
|
||||
case ORBIS_SIG_DFL:
|
||||
return SigDfl(sig);
|
||||
case ORBIS_SIG_IGN:
|
||||
return ORBIS_SIG_IGN;
|
||||
case ORBIS_SIG_ERR:
|
||||
return ORBIS_SIG_ERR;
|
||||
case ORBIS_SIG_CATCH:
|
||||
return ORBIS_SIG_ERR;
|
||||
case ORBIS_SIG_HOLD:
|
||||
return ORBIS_SIG_ERR;
|
||||
default:
|
||||
return ORBIS_SIG_DFL;
|
||||
}
|
||||
}
|
||||
|
||||
s32 sigaction(s32 sig, const struct sigaction* act, struct sigaction* oldact) {
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
if (sig > ORBIS_SIG_MAXSIG32) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
struct sigaction tmp = {};
|
||||
if (act != nullptr) {
|
||||
tmp = *act;
|
||||
}
|
||||
|
||||
switch (sig) {
|
||||
case ORBIS_SIGKILL:
|
||||
case ORBIS_SIGSTOP: {
|
||||
if (tmp.sa_sigaction != ORBIS_SIG_DFL) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto& info = g_sigacts[ORBIS_SIG_IDX(sig)];
|
||||
if (oldact != nullptr) {
|
||||
*oldact = info;
|
||||
}
|
||||
info = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct YMMCONTEXT {
|
||||
M128A Ymm0;
|
||||
M128A Ymm1;
|
||||
M128A Ymm2;
|
||||
M128A Ymm3;
|
||||
M128A Ymm4;
|
||||
M128A Ymm5;
|
||||
M128A Ymm6;
|
||||
M128A Ymm7;
|
||||
M128A Ymm8;
|
||||
M128A Ymm9;
|
||||
M128A Ymm10;
|
||||
M128A Ymm11;
|
||||
M128A Ymm12;
|
||||
M128A Ymm13;
|
||||
M128A Ymm14;
|
||||
M128A Ymm15;
|
||||
};
|
||||
|
||||
struct XSTATE {
|
||||
DWORD64 Mask;
|
||||
DWORD64 CompactionMask;
|
||||
DWORD64 Reserved[6];
|
||||
YMMCONTEXT YmmContext;
|
||||
};
|
||||
using PXSTATE = XSTATE*;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Taken from fpPS4
|
||||
ucontext_t UContextFromWin64(CONTEXT& context) {
|
||||
ucontext_t ucontext{};
|
||||
|
||||
const u32 flags = context.ContextFlags & (~CONTEXT_AMD64);
|
||||
if ((flags & CONTEXT_INTEGER) != 0) {
|
||||
ucontext.uc_flags |= ORBIS_UC_CPU;
|
||||
ucontext.uc_mcontext.mc_rax = context.Rax;
|
||||
ucontext.uc_mcontext.mc_rbx = context.Rbx;
|
||||
ucontext.uc_mcontext.mc_rcx = context.Rcx;
|
||||
ucontext.uc_mcontext.mc_rdx = context.Rdx;
|
||||
ucontext.uc_mcontext.mc_rsi = context.Rsi;
|
||||
ucontext.uc_mcontext.mc_rdi = context.Rdi;
|
||||
ucontext.uc_mcontext.mc_r8 = context.R8;
|
||||
ucontext.uc_mcontext.mc_r9 = context.R9;
|
||||
ucontext.uc_mcontext.mc_r10 = context.R10;
|
||||
ucontext.uc_mcontext.mc_r11 = context.R11;
|
||||
ucontext.uc_mcontext.mc_r12 = context.R12;
|
||||
ucontext.uc_mcontext.mc_r13 = context.R13;
|
||||
ucontext.uc_mcontext.mc_r14 = context.R14;
|
||||
ucontext.uc_mcontext.mc_r15 = context.R15;
|
||||
}
|
||||
if ((flags & CONTEXT_CONTROL) != 0) {
|
||||
ucontext.uc_flags |= ORBIS_UC_CPU;
|
||||
ucontext.uc_mcontext.mc_rsp = context.Rsp;
|
||||
ucontext.uc_mcontext.mc_rbp = context.Rbp;
|
||||
ucontext.uc_mcontext.mc_rip = context.Rip;
|
||||
ucontext.uc_mcontext.mc_rflags = context.EFlags;
|
||||
ucontext.uc_mcontext.mc_cs = context.SegCs;
|
||||
ucontext.uc_mcontext.mc_ss = context.SegSs;
|
||||
}
|
||||
if ((flags & CONTEXT_SEGMENTS) != 0) {
|
||||
ucontext.uc_flags |= ORBIS_UC_CPU;
|
||||
ucontext.uc_mcontext.mc_ds = context.SegDs;
|
||||
ucontext.uc_mcontext.mc_es = context.SegEs;
|
||||
ucontext.uc_mcontext.mc_fs = context.SegFs;
|
||||
ucontext.uc_mcontext.mc_gs = context.SegGs;
|
||||
}
|
||||
|
||||
auto uc_xsave = reinterpret_cast<PXMM_SAVE_AREA32>(&ucontext.uc_mcontext.mc_fpstate[0]);
|
||||
auto uc_xstate = reinterpret_cast<PXSTATE>(uc_xsave + 1);
|
||||
if ((flags & CONTEXT_FLOATING_POINT) != 0) {
|
||||
ucontext.uc_flags |= ORBIS_UC_FPU;
|
||||
*uc_xsave = context.FltSave;
|
||||
uc_xstate->Mask = uc_xstate->Mask | XSTATE_MASK_LEGACY;
|
||||
}
|
||||
if ((flags & CONTEXT_XSTATE) != 0) {
|
||||
DWORD64 xs_mask{};
|
||||
ASSERT(GetXStateFeaturesMask(&context, &xs_mask) == TRUE);
|
||||
if ((xs_mask & XSTATE_MASK_AVX) != 0) {
|
||||
DWORD length;
|
||||
auto xs_ymm =
|
||||
reinterpret_cast<YMMCONTEXT*>(LocateXStateFeature(&context, XSTATE_AVX, &length));
|
||||
ASSERT(length >= sizeof(YMMCONTEXT));
|
||||
uc_xstate->YmmContext = *xs_ymm;
|
||||
}
|
||||
}
|
||||
if ((flags & CONTEXT_DEBUG_REGISTERS) != 0) {
|
||||
ucontext.uc_mcontext.mc_spare[0] = context.Dr0;
|
||||
ucontext.uc_mcontext.mc_spare[1] = context.Dr1;
|
||||
ucontext.uc_mcontext.mc_spare[2] = context.Dr2;
|
||||
ucontext.uc_mcontext.mc_spare[3] = context.Dr3;
|
||||
ucontext.uc_mcontext.mc_spare[4] = context.Dr6;
|
||||
ucontext.uc_mcontext.mc_spare[5] = context.Dr7;
|
||||
}
|
||||
|
||||
// fix me
|
||||
if (context.Dr7 & DR7_LAST_BRANCH) {
|
||||
ucontext.uc_mcontext.mc_lbrfrom = context.LastBranchFromRip;
|
||||
ucontext.uc_mcontext.mc_lbrto = context.LastBranchToRip;
|
||||
} else {
|
||||
ucontext.uc_mcontext.mc_lbrfrom = 0; // context.Rsp;
|
||||
ucontext.uc_mcontext.mc_lbrto = 0; // context.Rbp;
|
||||
}
|
||||
|
||||
ucontext.uc_flags |= (flags << 8); // set as extended
|
||||
|
||||
ucontext.uc_mcontext.mc_addr = ucontext.uc_mcontext.mc_rip;
|
||||
ucontext.uc_mcontext.mc_len = sizeof(mcontext_t);
|
||||
ucontext.uc_mcontext.mc_flags = ORBIS_MC_HASSEGS;
|
||||
ucontext.uc_mcontext.mc_fpformat = ORBIS_MC_FPFMT_XMM;
|
||||
ucontext.uc_mcontext.mc_ownedfp = ORBIS_MC_FPOWNED_FPU;
|
||||
|
||||
return ucontext;
|
||||
}
|
||||
|
||||
static thread_local sigset_t g_sc_mask;
|
||||
|
||||
VOID NTAPI ThreadApcProc(PVOID arg1, PVOID arg2, PVOID arg3, PCONTEXT context) {
|
||||
int sig = static_cast<int>(reinterpret_cast<intptr_t>(arg1));
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
const auto sact = g_sigacts[ORBIS_SIG_IDX(sig)];
|
||||
if (sact.sa_flags & ORBIS_SA_RESETHAND) {
|
||||
g_sigacts[ORBIS_SIG_IDX(sig)] = {};
|
||||
}
|
||||
switch (SigActType(sig, sact)) {
|
||||
case ORBIS_SIG_IGN:
|
||||
case ORBIS_SIG_ERR:
|
||||
return;
|
||||
}
|
||||
ucontext_t ucontext = UContextFromWin64(*context);
|
||||
ucontext.uc_mcontext.mc_err = errno;
|
||||
|
||||
sigset_t save = g_sc_mask;
|
||||
if (sact.sa_flags & ORBIS_SA_NODEFER) {
|
||||
ucontext.sc_mask = sact.sa_mask;
|
||||
} else {
|
||||
g_sc_mask.__bits[0] |= sact.sa_mask.__bits[0];
|
||||
g_sc_mask.__bits[1] |= sact.sa_mask.__bits[1];
|
||||
g_sc_mask.__bits[2] |= sact.sa_mask.__bits[2];
|
||||
g_sc_mask.__bits[3] |= sact.sa_mask.__bits[3];
|
||||
ucontext.sc_mask = g_sc_mask;
|
||||
}
|
||||
|
||||
if (sact.sa_flags & ORBIS_SA_SIGINFO) {
|
||||
siginfo_t info = {
|
||||
.si_signo = sig,
|
||||
.si_code = ORBIS_SI_USER,
|
||||
.si_pid = GetCurrentProcessId(),
|
||||
};
|
||||
sact.sa_sigaction(sig, &info, &ucontext);
|
||||
} else {
|
||||
sact.sa_handler(sig, ORBIS_SI_USER, &ucontext);
|
||||
}
|
||||
g_sc_mask = save;
|
||||
}
|
||||
|
||||
s32 pthread_kill(pthread_t thread, s32 sig) {
|
||||
int result = 0;
|
||||
LOG_INFO(Lib_Kernel, "called. sig = {}", sig);
|
||||
if (sig == 0) {
|
||||
return result;
|
||||
}
|
||||
const auto tv = __pth_gpointer_locked(thread);
|
||||
const auto handle = OpenThread(THREAD_SET_CONTEXT, FALSE, tv->tid);
|
||||
USER_APC_OPTION option;
|
||||
option.UserApcFlags = QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC;
|
||||
|
||||
if (NtQueueApcThreadEx(handle, option, &ThreadApcProc,
|
||||
reinterpret_cast<PVOID>(static_cast<intptr_t>(sig)), nullptr,
|
||||
nullptr) != 0) {
|
||||
const auto error = GetLastError();
|
||||
LOG_ERROR(Lib_Kernel, "NtQueueApcThreadEx failed. error = {}: {}", error,
|
||||
Common::NativeErrorToString(error));
|
||||
// TODO: error conversion
|
||||
// result = ???
|
||||
} else if (tv->evStart != nullptr) {
|
||||
SetEvent(tv->evStart);
|
||||
}
|
||||
CloseHandle(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Orbis
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user