mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-09 02:01:07 +01:00
orbis: implement initial guest signals support
This commit is contained in:
parent
36b9e969c2
commit
70fa577a7b
|
|
@ -73,6 +73,7 @@ struct ProcessOps {
|
|||
SysResult (*thr_kill2)(Thread *thread, pid_t pid, slong id, sint sig);
|
||||
SysResult (*thr_suspend)(Thread *thread, ptr<const timespec> timeout);
|
||||
SysResult (*thr_wake)(Thread *thread, slong id);
|
||||
SysResult (*sigreturn)(Thread *thread, ptr<UContext> context);
|
||||
SysResult (*thr_set_name)(Thread *thread, slong id, ptr<const char> name);
|
||||
|
||||
SysResult (*unmount)(Thread *thread, ptr<char> path, sint flags);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ struct Thread {
|
|||
kvector<SigInfo> queuedSignals;
|
||||
shared_atomic32 suspendFlags{0};
|
||||
|
||||
utils::shared_atomic32 interruptedMtx{ 0 };
|
||||
|
||||
std::int64_t hostTid = -1;
|
||||
lwpid_t tid = -1;
|
||||
unsigned unblocked = 0;
|
||||
|
|
@ -64,13 +66,14 @@ struct Thread {
|
|||
// Print backtrace
|
||||
void where();
|
||||
|
||||
void unblock();
|
||||
void block();
|
||||
bool unblock();
|
||||
bool block();
|
||||
|
||||
void suspend();
|
||||
void resume();
|
||||
void sendSignal(int signo);
|
||||
void notifyUnblockedSignal(int signo);
|
||||
void setSigMask(SigSet newSigMask);
|
||||
|
||||
// FIXME: implement thread destruction
|
||||
void incRef() {}
|
||||
|
|
|
|||
|
|
@ -162,4 +162,10 @@ struct SigInfo {
|
|||
} spare;
|
||||
} reason;
|
||||
};
|
||||
|
||||
struct SigFrame {
|
||||
uint64_t handler;
|
||||
UContext context;
|
||||
SigInfo info;
|
||||
};
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ static constexpr auto kRelaxSpinCount = 12;
|
|||
static constexpr auto kSpinCount = 16;
|
||||
|
||||
inline namespace utils {
|
||||
inline thread_local void (*g_scopedUnblock)(bool) = nullptr;
|
||||
inline thread_local bool (*g_scopedUnblock)(bool) = nullptr;
|
||||
|
||||
bool try_spin_wait(auto &&pred) {
|
||||
for (std::size_t i = 0; i < kSpinCount; ++i) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <sys/mman.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
static const std::uint64_t g_allocProtWord = 0xDEADBEAFBADCAFE1;
|
||||
static constexpr std::uintptr_t kHeapBaseAddress = 0x00000600'0000'0000;
|
||||
|
|
@ -318,9 +319,31 @@ void Thread::suspend() { sendSignal(-1); }
|
|||
void Thread::resume() { sendSignal(-2); }
|
||||
|
||||
void Thread::sendSignal(int signo) {
|
||||
if (signo >= 0) {
|
||||
if (!sigMask.test(signo)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) {
|
||||
perror("pthread_sigqueue");
|
||||
}
|
||||
|
||||
|
||||
// TODO: suspend uses another delivery confirmation
|
||||
if (signo != -1) {
|
||||
interruptedMtx.store(1, std::memory_order::release);
|
||||
while (interruptedMtx.wait(1, std::chrono::microseconds(1000)) !=
|
||||
std::errc{}) {
|
||||
if (interruptedMtx.load() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = -2})) {
|
||||
perror("pthread_sigqueue");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::notifyUnblockedSignal(int signo) {
|
||||
|
|
@ -335,19 +358,55 @@ void Thread::notifyUnblockedSignal(int signo) {
|
|||
}
|
||||
}
|
||||
|
||||
void Thread::setSigMask(SigSet newSigMask) {
|
||||
newSigMask.clear(kSigKill);
|
||||
newSigMask.clear(kSigStop);
|
||||
|
||||
auto oldSigMask = std::exchange(sigMask, newSigMask);
|
||||
|
||||
for (std::size_t word = 0; word < std::size(newSigMask.bits); ++word) {
|
||||
auto unblockedBits = ~oldSigMask.bits[word] & newSigMask.bits[word];
|
||||
std::uint32_t offset = word * 32 + 1;
|
||||
|
||||
for (std::uint32_t i = std::countr_zero(unblockedBits); i < 32;
|
||||
i += std::countr_zero(unblockedBits >> (i + 1)) + 1) {
|
||||
notifyUnblockedSignal(offset + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::where() { tproc->ops->where(this); }
|
||||
|
||||
void Thread::unblock() { tproc->ops->unblock(this); }
|
||||
void Thread::block() { tproc->ops->block(this); }
|
||||
bool Thread::unblock() {
|
||||
if (interruptedMtx.load(std::memory_order::relaxed) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tproc->ops->unblock(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Thread::block() {
|
||||
tproc->ops->block(this);
|
||||
|
||||
std::uint32_t prev = interruptedMtx.exchange(0, std::memory_order::relaxed);
|
||||
if (prev != 0) {
|
||||
interruptedMtx.notify_one();
|
||||
}
|
||||
|
||||
return prev == 0;
|
||||
}
|
||||
|
||||
scoped_unblock::scoped_unblock() {
|
||||
if (g_currentThread && g_currentThread->context) {
|
||||
g_scopedUnblock = [](bool unblock) {
|
||||
if (unblock) {
|
||||
g_currentThread->unblock();
|
||||
} else {
|
||||
g_currentThread->block();
|
||||
return g_currentThread->unblock();
|
||||
}
|
||||
|
||||
g_currentThread->block();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -572,6 +572,7 @@ orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need,
|
|||
|
||||
std::lock_guard lock(sem->mtx);
|
||||
bool timedout = false;
|
||||
ErrorCode result{};
|
||||
while (true) {
|
||||
if (sem->isDeleted)
|
||||
return ErrorCode::ACCES;
|
||||
|
|
@ -591,7 +592,12 @@ orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need,
|
|||
}
|
||||
|
||||
orbis::scoped_unblock unblock;
|
||||
sem->cond.wait(sem->mtx, ut);
|
||||
auto waitResult = sem->cond.wait(sem->mtx, ut);
|
||||
|
||||
if (waitResult == std::errc::interrupted) {
|
||||
result = ErrorCode::INTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pTimeout) {
|
||||
|
|
@ -613,7 +619,7 @@ orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need,
|
|||
if (timedout) {
|
||||
return SysResult::notAnError(ErrorCode::TIMEDOUT);
|
||||
}
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_trywait(Thread *thread, sint id, sint need) {
|
||||
ORBIS_LOG_TRACE(__FUNCTION__, thread, id, need);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
#include "thread/Process.hpp"
|
||||
#include "thread/Thread.hpp"
|
||||
#include "thread/ProcessOps.hpp"
|
||||
#include "ucontext.hpp"
|
||||
#include "utils/Logs.hpp"
|
||||
#include <csignal>
|
||||
|
|
@ -120,11 +121,11 @@ orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) {
|
|||
hostPid = process->hostPid;
|
||||
}
|
||||
|
||||
// TODO: wrap signal
|
||||
// int result = ::kill(hostPid, signum);
|
||||
// if (result < 0) {
|
||||
// return static_cast<ErrorCode>(errno);
|
||||
// }
|
||||
// FIXME: invoke subscriber thread
|
||||
int result = ::sigqueue(hostPid, SIGUSR1, {.sival_int = signum});
|
||||
if (result < 0) {
|
||||
return static_cast<ErrorCode>(errno);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
@ -139,13 +140,11 @@ orbis::SysResult orbis::sys_sigqueue(Thread *thread, pid_t pid, sint signum,
|
|||
orbis::SysResult orbis::sys_sigreturn(Thread *thread, ptr<UContext> sigcntxp) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, sigcntxp);
|
||||
|
||||
// auto sigRet = thread->sigReturns.front();
|
||||
// thread->sigReturns.erase(thread->sigReturns.begin(),
|
||||
// thread->sigReturns.begin() + 1); writeRegister(thread->context,
|
||||
// RegisterId::rip, sigRet.rip); writeRegister(thread->context,
|
||||
// RegisterId::rsp, sigRet.rsp); ORBIS_LOG_ERROR(__FUNCTION__, sigRet.rip,
|
||||
// sigRet.rsp);
|
||||
return {};
|
||||
if (auto sigreturn = thread->tproc->ops->sigreturn) {
|
||||
return sigreturn(thread, sigcntxp);
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
|
||||
orbis::SysResult orbis::nosys(Thread *thread) {
|
||||
|
|
|
|||
|
|
@ -63,10 +63,6 @@ uint UmtxChain::notify_all(const UmtxKey &key) {
|
|||
}
|
||||
} // namespace orbis
|
||||
|
||||
static bool isSpuriousWakeup(orbis::ErrorCode errc) {
|
||||
return errc == orbis::ErrorCode::AGAIN || errc == orbis::ErrorCode::INTR;
|
||||
}
|
||||
|
||||
orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
|
||||
std::uint64_t ut) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id, ut);
|
||||
|
|
@ -97,8 +93,7 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
|
|||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx));
|
||||
if ((result != ErrorCode{} && !isSpuriousWakeup(result)) ||
|
||||
node->second.thr != thread)
|
||||
if ((result != ErrorCode{}) || node->second.thr != thread)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -117,7 +112,7 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
|
|||
result = ErrorCode::TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
if (result != ErrorCode{} && !isSpuriousWakeup(result)) {
|
||||
if (result != ErrorCode{}) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -193,7 +188,7 @@ static ErrorCode do_lock_normal(Thread *thread, ptr<umutex> m, uint flags,
|
|||
if (mode == umutex_lock_mode::try_)
|
||||
return ErrorCode::BUSY;
|
||||
|
||||
if (error != ErrorCode{} && !isSpuriousWakeup(error))
|
||||
if (error != ErrorCode{})
|
||||
return error;
|
||||
|
||||
auto node = chain.enqueue(key, thread);
|
||||
|
|
@ -202,8 +197,8 @@ static ErrorCode do_lock_normal(Thread *thread, ptr<umutex> m, uint flags,
|
|||
orbis::scoped_unblock unblock;
|
||||
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
|
||||
}
|
||||
if (error == ErrorCode{} && !isSpuriousWakeup(error) &&
|
||||
node->second.thr == thread && m->owner.load() != 0) {
|
||||
if (error == ErrorCode{} && node->second.thr == thread &&
|
||||
m->owner.load() != 0) {
|
||||
error = ErrorCode::TIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
|
@ -358,12 +353,12 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
|
|||
|
||||
ErrorCode result = umtx_unlock_umutex(thread, m);
|
||||
if (result == ErrorCode{}) {
|
||||
orbis::scoped_unblock unblock;
|
||||
if (ut + 1 == 0) {
|
||||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
|
||||
if ((result != ErrorCode{} && !isSpuriousWakeup(result)) ||
|
||||
node->second.thr != thread) {
|
||||
|
||||
if (result != ErrorCode{} || node->second.thr != thread) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -371,7 +366,6 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
|
|||
auto start = std::chrono::steady_clock::now();
|
||||
std::uint64_t udiff = 0;
|
||||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
result =
|
||||
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
|
||||
if (node->second.thr != thread) {
|
||||
|
|
@ -385,7 +379,7 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
|
|||
break;
|
||||
}
|
||||
|
||||
if (result != ErrorCode{} && !isSpuriousWakeup(result)) {
|
||||
if (result != ErrorCode{}) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -470,8 +464,7 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<urwlock> rwlock,
|
|||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
|
||||
if ((result != ErrorCode{} && !isSpuriousWakeup(result)) ||
|
||||
node->second.thr != thread) {
|
||||
if (result != ErrorCode{} || node->second.thr != thread) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -492,7 +485,7 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<urwlock> rwlock,
|
|||
break;
|
||||
}
|
||||
|
||||
if (result != ErrorCode{} && !isSpuriousWakeup(result)) {
|
||||
if (result != ErrorCode{}) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -574,8 +567,7 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<urwlock> rwlock,
|
|||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
|
||||
if ((error != ErrorCode{} && !isSpuriousWakeup(error)) ||
|
||||
node->second.thr != thread) {
|
||||
if ((error != ErrorCode{}) || node->second.thr != thread) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -595,7 +587,7 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<urwlock> rwlock,
|
|||
error = ErrorCode::TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
if (error != ErrorCode{} && !isSpuriousWakeup(error)) {
|
||||
if (error != ErrorCode{}) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -757,8 +749,7 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<usem> sem,
|
|||
while (true) {
|
||||
orbis::scoped_unblock unblock;
|
||||
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
|
||||
if ((result != ErrorCode{} && !isSpuriousWakeup(result)) ||
|
||||
node->second.thr != thread)
|
||||
if ((result != ErrorCode{}) || node->second.thr != thread)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -777,7 +768,7 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<usem> sem,
|
|||
result = ErrorCode::TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
if (result != ErrorCode{} && !isSpuriousWakeup(result)) {
|
||||
if (result != ErrorCode{}) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,18 +19,28 @@ std::errc shared_atomic32::wait_impl(std::uint32_t oldValue,
|
|||
g_scopedUnblock != nullptr;
|
||||
|
||||
if (unblock) {
|
||||
g_scopedUnblock(true);
|
||||
if (!g_scopedUnblock(true)) {
|
||||
return std::errc::interrupted;
|
||||
}
|
||||
}
|
||||
|
||||
int result = syscall(SYS_futex, this, FUTEX_WAIT, oldValue,
|
||||
useTimeout ? &timeout : nullptr);
|
||||
|
||||
auto errorCode = result < 0 ? static_cast<std::errc>(errno) : std::errc{};
|
||||
|
||||
if (unblock) {
|
||||
g_scopedUnblock(false);
|
||||
if (!g_scopedUnblock(false)) {
|
||||
if (result < 0) {
|
||||
return std::errc::interrupted;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
return static_cast<std::errc>(errno);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -650,6 +650,11 @@ SysResult thr_wake(orbis::Thread *thread, orbis::slong id) {
|
|||
ORBIS_LOG_FATAL(__FUNCTION__, id);
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
SysResult sigreturn(orbis::Thread *thread,
|
||||
orbis::ptr<orbis::UContext> context) {
|
||||
rx::thread::setContext(thread, *context);
|
||||
return{};
|
||||
}
|
||||
SysResult thr_set_name(orbis::Thread *thread, orbis::slong id,
|
||||
orbis::ptr<const char> name) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, name, id, thread->tid);
|
||||
|
|
@ -1023,6 +1028,7 @@ ProcessOps rx::procOpsTable = {
|
|||
.thr_kill2 = thr_kill2,
|
||||
.thr_suspend = thr_suspend,
|
||||
.thr_wake = thr_wake,
|
||||
.sigreturn = sigreturn,
|
||||
.thr_set_name = thr_set_name,
|
||||
.unmount = unmount,
|
||||
.nmount = nmount,
|
||||
|
|
|
|||
110
rpcsx/thread.cpp
110
rpcsx/thread.cpp
|
|
@ -4,6 +4,7 @@
|
|||
#include "orbis/thread/Process.hpp"
|
||||
#include "orbis/thread/Thread.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "rx/debug.hpp"
|
||||
#include "rx/mem.hpp"
|
||||
#include <asm/prctl.h>
|
||||
#include <csignal>
|
||||
|
|
@ -125,6 +126,53 @@ handleSigUser(int sig, siginfo_t *info, void *ucontext) {
|
|||
}
|
||||
|
||||
// ORBIS_LOG_ERROR("thread wake", thread->tid);
|
||||
} else if (guestSignal >= 0) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, "handled signal", guestSignal, inGuestCode,
|
||||
::getpid(), thread->tid);
|
||||
auto it = thread->tproc->sigActions.find(guestSignal);
|
||||
|
||||
if (it != thread->tproc->sigActions.end()) {
|
||||
auto guestContext = reinterpret_cast<ucontext_t *>(
|
||||
inGuestCode ? context : thread->context);
|
||||
|
||||
auto sigact = it->second;
|
||||
thread->setSigMask(sigact.mask);
|
||||
auto handlerPtr = reinterpret_cast<std::uintptr_t>(sigact.handler);
|
||||
|
||||
auto rsp = guestContext->uc_mcontext.gregs[REG_RSP];
|
||||
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, "invoking signal handler", guestSignal,
|
||||
rsp, thread->stackStart, thread->stackEnd);
|
||||
|
||||
// FIXME: alt stack?
|
||||
rsp -= 128; // redzone
|
||||
rsp -= sizeof(orbis::SigFrame);
|
||||
|
||||
// FIXME handle flags
|
||||
auto &sigFrame = *std::bit_cast<orbis::SigFrame *>(rsp);
|
||||
sigFrame = {};
|
||||
|
||||
rx::thread::copyContext(thread, sigFrame.context, *guestContext);
|
||||
sigFrame.info.signo = guestSignal;
|
||||
sigFrame.handler = handlerPtr;
|
||||
|
||||
guestContext->uc_mcontext.gregs[REG_RDI] = guestSignal; // arg1, signo
|
||||
guestContext->uc_mcontext.gregs[REG_RSI] =
|
||||
std::bit_cast<std::uintptr_t>(&sigFrame.info); // arg2, siginfo
|
||||
guestContext->uc_mcontext.gregs[REG_RDX] =
|
||||
std::bit_cast<std::uintptr_t>(&sigFrame.context); // arg3, ucontext
|
||||
guestContext->uc_mcontext.gregs[REG_RCX] = 0; // arg4, si_addr
|
||||
guestContext->uc_mcontext.gregs[REG_RIP] = handlerPtr;
|
||||
|
||||
guestContext->uc_mcontext.gregs[REG_RSP] = rx::alignDown(rsp, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (inGuestCode && guestSignal != -1) {
|
||||
std::uint32_t prevValue = 1;
|
||||
if (thread->interruptedMtx.compare_exchange_strong(prevValue, 0)) {
|
||||
thread->interruptedMtx.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
if (inGuestCode) {
|
||||
|
|
@ -187,11 +235,69 @@ void rx::thread::copyContext(orbis::Thread *thread, orbis::UContext &dst,
|
|||
dst = {};
|
||||
dst.stack.sp = thread->stackStart;
|
||||
dst.stack.size = (char *)thread->stackEnd - (char *)thread->stackStart;
|
||||
dst.stack.align = 0x10000;
|
||||
dst.stack.align = 16;
|
||||
dst.sigmask = thread->sigMask;
|
||||
copyContext(dst.mcontext, src.uc_mcontext);
|
||||
}
|
||||
|
||||
void rx::thread::setContext(orbis::Thread *thread, const orbis::UContext &src) {
|
||||
auto &context = *std::bit_cast<ucontext_t *>(thread->context);
|
||||
thread->stackStart = src.stack.sp;
|
||||
thread->stackEnd = (char *)thread->stackStart + src.stack.size;
|
||||
thread->setSigMask(src.sigmask);
|
||||
|
||||
// dst.onstack = src.gregs[REG_ONSTACK];
|
||||
context.uc_mcontext.gregs[REG_RDI] = src.mcontext.rdi;
|
||||
context.uc_mcontext.gregs[REG_RSI] = src.mcontext.rsi;
|
||||
context.uc_mcontext.gregs[REG_RDX] = src.mcontext.rdx;
|
||||
context.uc_mcontext.gregs[REG_RCX] = src.mcontext.rcx;
|
||||
context.uc_mcontext.gregs[REG_R8] = src.mcontext.r8;
|
||||
context.uc_mcontext.gregs[REG_R9] = src.mcontext.r9;
|
||||
context.uc_mcontext.gregs[REG_RAX] = src.mcontext.rax;
|
||||
context.uc_mcontext.gregs[REG_RBX] = src.mcontext.rbx;
|
||||
context.uc_mcontext.gregs[REG_RBP] = src.mcontext.rbp;
|
||||
context.uc_mcontext.gregs[REG_R10] = src.mcontext.r10;
|
||||
context.uc_mcontext.gregs[REG_R11] = src.mcontext.r11;
|
||||
context.uc_mcontext.gregs[REG_R12] = src.mcontext.r12;
|
||||
context.uc_mcontext.gregs[REG_R13] = src.mcontext.r13;
|
||||
context.uc_mcontext.gregs[REG_R14] = src.mcontext.r14;
|
||||
context.uc_mcontext.gregs[REG_R15] = src.mcontext.r15;
|
||||
|
||||
context.uc_mcontext.gregs[REG_TRAPNO] = src.mcontext.trapno;
|
||||
|
||||
// in perfect world:
|
||||
// std::uint64_t csgsfs = 0;
|
||||
// csgsfs |= src.mcontext.fs;
|
||||
// csgsfs |= static_cast<std::uint64_t>(src.mcontext.gs) << 16;
|
||||
// csgsfs |= static_cast<std::uint64_t>(src.mcontext.cs) << 32;
|
||||
// context.uc_mcontext.gregs[REG_CSGSFS] = csgsfs;
|
||||
|
||||
context.uc_mcontext.gregs[REG_CSGSFS] &= ~0xff'ffull;
|
||||
context.uc_mcontext.gregs[REG_CSGSFS] |= src.mcontext.fs;
|
||||
|
||||
// dst.addr = src.gregs[REG_ADDR];
|
||||
// dst.flags = src.gregs[REG_FLAGS];
|
||||
// dst.es = src.gregs[REG_ES];
|
||||
// dst.ds = src.gregs[REG_DS];
|
||||
context.uc_mcontext.gregs[REG_ERR] = src.mcontext.err;
|
||||
context.uc_mcontext.gregs[REG_RIP] = src.mcontext.rip;
|
||||
context.uc_mcontext.gregs[REG_EFL] = src.mcontext.rflags;
|
||||
context.uc_mcontext.gregs[REG_RSP] = src.mcontext.rsp;
|
||||
// dst.ss = src.gregs[REG_SS];
|
||||
// dst.len = sizeof(orbis::MContext);
|
||||
// dst.fpformat = src.gregs[REG_FPFORMAT];
|
||||
// dst.ownedfp = src.gregs[REG_OWNEDFP];
|
||||
// dst.lbrfrom = src.gregs[REG_LBRFROM];
|
||||
// dst.lbrto = src.gregs[REG_LBRTO];
|
||||
// dst.aux1 = src.gregs[REG_AUX1];
|
||||
// dst.aux2 = src.gregs[REG_AUX2];
|
||||
// dst.fpstate = src.gregs[REG_FPSTATE];
|
||||
// dst.fsbase = src.gregs[REG_FSBASE];
|
||||
// dst.gsbase = src.gregs[REG_GSBASE];
|
||||
// dst.xfpustate = src.gregs[REG_XFPUSTATE];
|
||||
// dst.xfpustate_len = src.gregs[REG_XFPUSTATE_LEN];
|
||||
}
|
||||
|
||||
void rx::thread::initialize() {
|
||||
struct sigaction act{};
|
||||
act.sa_sigaction = handleSigSys;
|
||||
|
|
@ -271,6 +377,6 @@ void rx::thread::invoke(orbis::Thread *thread) {
|
|||
_writefsbase_u64(thread->fsBase);
|
||||
auto context = reinterpret_cast<ucontext_t *>(thread->context);
|
||||
|
||||
setContext(context->uc_mcontext);
|
||||
::setContext(context->uc_mcontext);
|
||||
_writefsbase_u64(hostFs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@ void setupThisThread();
|
|||
void copyContext(orbis::MContext &dst, const mcontext_t &src);
|
||||
void copyContext(orbis::Thread *thread, orbis::UContext &dst,
|
||||
const ucontext_t &src);
|
||||
void setContext(orbis::Thread *thread, const orbis::UContext &src);
|
||||
void invoke(orbis::Thread *thread);
|
||||
} // namespace rx::thread
|
||||
|
|
|
|||
Loading…
Reference in a new issue