rpcsx/rpcsx-os/thread.cpp

114 lines
3.1 KiB
C++
Raw Normal View History

2023-07-06 13:26:57 +02:00
#include "thread.hpp"
#include "align.hpp"
#include "orbis/sys/sysentry.hpp"
#include "orbis/thread/Process.hpp"
#include "orbis/thread/Thread.hpp"
2023-07-06 13:26:57 +02:00
#include <asm/prctl.h>
#include <csignal>
2023-07-06 13:26:57 +02:00
#include <immintrin.h>
#include <link.h>
#include <linux/prctl.h>
#include <sys/prctl.h>
#include <ucontext.h>
#include <unistd.h>
2023-07-18 02:26:33 +02:00
#include <xbyak/xbyak.h>
2023-07-06 13:26:57 +02:00
2023-07-18 02:26:33 +02:00
static auto setContext = [] {
struct SetContext : Xbyak::CodeGenerator {
SetContext() {
mov(rbp, rdi);
mov(rax, qword[rbp + REG_RAX * sizeof(unsigned long long)]);
mov(rdi, qword[rbp + REG_RDI * sizeof(unsigned long long)]);
mov(rdx, qword[rbp + REG_RDX * sizeof(unsigned long long)]);
mov(rcx, qword[rbp + REG_RCX * sizeof(unsigned long long)]);
mov(rbx, qword[rbp + REG_RBX * sizeof(unsigned long long)]);
mov(rsi, qword[rbp + REG_RSI * sizeof(unsigned long long)]);
mov(rsp, qword[rbp + REG_RSP * sizeof(unsigned long long)]);
mov(rbp, qword[rbp + REG_RIP * sizeof(unsigned long long)]);
call(rbp);
}
} static setContextStorage;
return setContextStorage.getCode<void (*)(const mcontext_t &)>();
}();
static __attribute__((no_stack_protector)) void
handleSigSys(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
2023-07-13 14:53:05 +02:00
// rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext),
// rx::thread::g_current, 1);
auto thread = orbis::g_currentThread;
auto prevContext = std::exchange(thread->context, ucontext);
orbis::syscall_entry(thread);
thread = orbis::g_currentThread;
thread->context = prevContext;
_writefsbase_u64(thread->fsBase);
}
2023-07-06 13:26:57 +02:00
void rx::thread::initialize() {
struct sigaction act {};
act.sa_sigaction = handleSigSys;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSYS, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
2023-07-06 13:26:57 +02:00
}
void rx::thread::deinitialize() {}
void rx::thread::setupSignalStack() {
stack_t ss{};
auto sigStackSize = std::max<std::size_t>(
SIGSTKSZ, ::utils::alignUp(64 * 1024 * 1024, sysconf(_SC_PAGE_SIZE)));
ss.ss_sp = malloc(sigStackSize);
if (ss.ss_sp == NULL) {
perror("malloc");
std::exit(EXIT_FAILURE);
}
ss.ss_size = sigStackSize;
ss.ss_flags = 1 << 31;
2023-07-06 13:26:57 +02:00
if (sigaltstack(&ss, NULL) == -1) {
perror("sigaltstack");
std::exit(EXIT_FAILURE);
}
}
void rx::thread::setupThisThread() {
sigset_t unblockSigs{};
sigset_t oldSigmask{};
sigaddset(&unblockSigs, SIGSYS);
if (pthread_sigmask(SIG_UNBLOCK, &unblockSigs, &oldSigmask)) {
perror("pthread_sigmask failed\n");
std::exit(-1);
}
2023-07-06 13:26:57 +02:00
if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON,
(void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) {
2023-07-06 13:26:57 +02:00
perror("prctl failed\n");
std::exit(-1);
2023-07-06 13:26:57 +02:00
}
}
void rx::thread::invoke(orbis::Thread *thread) {
orbis::g_currentThread = thread;
std::uint64_t hostFs = _readfsbase_u64();
_writegsbase_u64(hostFs);
2023-07-06 13:26:57 +02:00
_writefsbase_u64(thread->fsBase);
auto context = reinterpret_cast<ucontext_t *>(thread->context);
2023-07-18 02:26:33 +02:00
setContext(context->uc_mcontext);
2023-07-06 13:26:57 +02:00
_writefsbase_u64(hostFs);
}