Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Exceptions #955

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/audio_core/sdl_audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/audio_core/sdl_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
85 changes: 78 additions & 7 deletions src/core/libraries/kernel/libkernel.cpp
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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>
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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);
Expand Down
185 changes: 185 additions & 0 deletions src/core/libraries/kernel/orbis_signals.h
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading