Merge pull request #1247 from Sonicadvance1/handle_xmm_state_32bit

Linux: Handle fpstate in the signal delegator correctly
This commit is contained in:
Ryan Houdek authored and GitHub committed 2021-09-02 12:36:02 -07:00
commit 1c4503e26a
3 files changed
+69 -33

No files matched your search

@@ -184,20 +184,27 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
// Setup ucontext a bit
if (Is64BitMode) {
NewGuestSP -= sizeof(FEXCore::x86_64::_libc_fpstate);
NewGuestSP = AlignDown(NewGuestSP, alignof(FEXCore::x86_64::_libc_fpstate));
uint64_t FPStateLocation = NewGuestSP;
NewGuestSP -= sizeof(FEXCore::x86_64::ucontext_t);
NewGuestSP = AlignDown(NewGuestSP, alignof(FEXCore::x86_64::ucontext_t));
uint64_t UContextLocation = NewGuestSP;
NewGuestSP -= sizeof(siginfo_t);
NewGuestSP = AlignDown(NewGuestSP, alignof(siginfo_t));
uint64_t SigInfoLocation = NewGuestSP;
FEXCore::x86_64::ucontext_t *guest_uctx = reinterpret_cast<FEXCore::x86_64::ucontext_t*>(UContextLocation);
siginfo_t *guest_siginfo = reinterpret_cast<siginfo_t*>(SigInfoLocation);
// We have extended float information
guest_uctx->uc_flags |= FEXCore::x86_64::UC_FP_XSTATE;
guest_uctx->uc_flags = FEXCore::x86_64::UC_FP_XSTATE;
// Pointer to where the fpreg memory is
guest_uctx->uc_mcontext.fpregs = &guest_uctx->__fpregs_mem;
guest_uctx->uc_mcontext.fpregs = reinterpret_cast<FEXCore::x86_64::_libc_fpstate*>(FPStateLocation);
FEXCore::x86_64::_libc_fpstate *fpstate = reinterpret_cast<FEXCore::x86_64::_libc_fpstate*>(FPStateLocation);
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] = Frame->State.rip;
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL] = 0;
@@ -228,15 +235,15 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
#undef COPY_REG
// Copy float registers
memcpy(guest_uctx->__fpregs_mem._st, Frame->State.mm, sizeof(Frame->State.mm));
memcpy(guest_uctx->__fpregs_mem._xmm, Frame->State.xmm, sizeof(Frame->State.xmm));
memcpy(fpstate->_st, Frame->State.mm, sizeof(Frame->State.mm));
memcpy(fpstate->_xmm, Frame->State.xmm, sizeof(Frame->State.xmm));
// FCW store default
guest_uctx->__fpregs_mem.fcw = Frame->State.FCW;
guest_uctx->__fpregs_mem.ftw = Frame->State.FTW;
fpstate->fcw = Frame->State.FCW;
fpstate->ftw = Frame->State.FTW;
// Reconstruct FSW
guest_uctx->__fpregs_mem.fsw =
fpstate->fsw =
(Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) |
(Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) |
(Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) |
@@ -257,20 +264,27 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
Frame->State.gregs[X86State::REG_RDX] = UContextLocation;
}
else {
// XXX: 32bit Support
NewGuestSP -= sizeof(FEXCore::x86::_libc_fpstate);
NewGuestSP = AlignDown(NewGuestSP, alignof(FEXCore::x86::_libc_fpstate));
uint64_t FPStateLocation = NewGuestSP;
NewGuestSP -= sizeof(FEXCore::x86::ucontext_t);
NewGuestSP = AlignDown(NewGuestSP, alignof(FEXCore::x86::ucontext_t));
uint64_t UContextLocation = NewGuestSP;
NewGuestSP -= sizeof(FEXCore::x86::siginfo_t);
NewGuestSP = AlignDown(NewGuestSP, alignof(FEXCore::x86::siginfo_t));
uint64_t SigInfoLocation = NewGuestSP;
FEXCore::x86::ucontext_t *guest_uctx = reinterpret_cast<FEXCore::x86::ucontext_t*>(UContextLocation);
FEXCore::x86::siginfo_t *guest_siginfo = reinterpret_cast<FEXCore::x86::siginfo_t*>(SigInfoLocation);
// We have extended float information
guest_uctx->uc_flags |= FEXCore::x86::UC_FP_XSTATE;
guest_uctx->uc_flags = FEXCore::x86::UC_FP_XSTATE;
// Pointer to where the fpreg memory is
guest_uctx->uc_mcontext.fpregs = static_cast<uint32_t>(reinterpret_cast<uint64_t>(&guest_uctx->__fpregs_mem));
guest_uctx->uc_mcontext.fpregs = static_cast<uint32_t>(FPStateLocation);
FEXCore::x86::_libc_fpstate *fpstate = reinterpret_cast<FEXCore::x86::_libc_fpstate*>(FPStateLocation);
guest_uctx->uc_mcontext.gregs[FEXCore::x86::FEX_REG_GS] = Frame->State.gs;
guest_uctx->uc_mcontext.gregs[FEXCore::x86::FEX_REG_FS] = Frame->State.fs;
@@ -297,20 +311,20 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
#undef COPY_REG
// Copy float registers
memcpy(guest_uctx->__fpregs_mem._st, Frame->State.mm, sizeof(Frame->State.mm));
if (0) {
// XXX: Handle XMM
// memcpy(guest_uctx->__fpregs_mem._xmm, Frame->State.xmm, sizeof(Frame->State.xmm));
guest_uctx->__fpregs_mem.status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE;
}
else {
guest_uctx->__fpregs_mem.status = FEXCore::x86::fpstate_magic::MAGIC_FPU;
for (size_t i = 0; i < 8; ++i) {
// 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64
memcpy(&fpstate->_st[i], &Frame->State.mm[i], 10);
}
// Extended XMM state
fpstate->status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE;
memcpy(fpstate->_xmm, Frame->State.xmm, sizeof(Frame->State.xmm));
// FCW store default
guest_uctx->__fpregs_mem.fcw = Frame->State.FCW;
guest_uctx->__fpregs_mem.ftw = Frame->State.FTW;
fpstate->fcw = Frame->State.FCW;
fpstate->ftw = Frame->State.FTW;
// Reconstruct FSW
guest_uctx->__fpregs_mem.fsw =
fpstate->fsw =
(Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) |
(Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) |
(Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) |
@@ -347,9 +361,14 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
guest_siginfo->_sifields._sigchld.utime = HostSigInfo->si_utime;
guest_siginfo->_sifields._sigchld.stime = HostSigInfo->si_stime;
break;
case SIGALRM:
case SIGVTALRM:
guest_siginfo->_sifields._timer.tid = HostSigInfo->si_timerid;
guest_siginfo->_sifields._timer.overrun = HostSigInfo->si_overrun;
guest_siginfo->_sifields._timer.sigval.sival_int = HostSigInfo->si_int;
break;
default:
// Hope for the best, most things just copy over
memcpy(&guest_siginfo->_sifields, &HostSigInfo->_sifields, sizeof(siginfo_t));
LogMan::Msg::E("Unhandled siginfo_t for signal: %d\n", Signal);
break;
}
+23 -7
View File
@@ -86,12 +86,10 @@ namespace FEXCore {
FEXCore::x86_64::stack_t uc_stack;
FEXCore::x86_64::mcontext_t uc_mcontext;
FEXCore::x86_64::sigset_t uc_sigmask;
FEXCore::x86_64::_libc_fpstate __fpregs_mem;
uint64_t __ssp[4];
};
static_assert(offsetof(FEXCore::x86_64::ucontext_t, uc_mcontext) == 40, "Needs to be correct");
static_assert(sizeof(FEXCore::x86_64::ucontext_t) == 968, "This needs to be the right size");
static_assert(sizeof(FEXCore::x86_64::ucontext_t) == 424, "This needs to be the right size");
}
namespace x86 {
@@ -123,6 +121,11 @@ namespace FEXCore {
};
static_assert(FEX_REG_SS == 18, "Oops");
union sigval_t {
int sival_int;
uint32_t sival_ptr; // XXX: Should be compat_ptr<void>
};
struct FEX_PACKED siginfo_t {
int si_signo;
int si_errno;
@@ -141,6 +144,12 @@ namespace FEXCore {
int32_t utime;
int32_t stime;
} _sigchld;
/* SIGALRM, SIGVTALRM */
struct {
int tid;
int overrun;
FEXCore::x86::sigval_t sigval;
} _timer;
} _sifields;
};
static_assert(sizeof(FEXCore::x86::siginfo_t) == 128, "This needs to be the right size");
@@ -183,8 +192,17 @@ namespace FEXCore {
uint32_t datasel;
FEXCore::x86::_libc_fpreg _st[8];
uint32_t status;
// Extended FPU data
uint32_t pad[6]; // Ignored FXSR data
uint32_t mxcsr;
uint32_t reserved;
__uint128_t _st_pad[8]; // Ignored st data
__uint128_t _xmm[8]; // First 8 XMM registers
uint32_t pad2[44]; // Second 8 XMM registers plus padding
uint32_t pad3[12]; // extended state encoding
};
static_assert(sizeof(FEXCore::x86::_libc_fpstate) == 112, "This needs to be the right size");
static_assert(sizeof(FEXCore::x86::_libc_fpstate) == 624, "This needs to be the right size");
struct FEX_PACKED ucontext_t {
uint32_t uc_flags;
@@ -192,10 +210,8 @@ namespace FEXCore {
FEXCore::x86::stack_t uc_stack;
FEXCore::x86::mcontext_t uc_mcontext;
FEXCore::x86_64::sigset_t uc_sigmask; // This matches across architectures
FEXCore::x86::_libc_fpstate __fpregs_mem;
uint32_t __ssp[4];
};
static_assert(sizeof(FEXCore::x86::ucontext_t) == 364, "This needs to be the right size");
static_assert(sizeof(FEXCore::x86::ucontext_t) == 236, "This needs to be the right size");
}
}
@@ -174,9 +174,10 @@ namespace FEX::HLE {
// Now install the thunk handler
SignalHandler.HostAction.sigaction = SignalHandlerThunk;
if (SignalHandler.GuestAction.sa_flags & SA_NODEFER) {
// If the guest is using NODEFER then make sure to set it for the host as well
SignalHandler.HostAction.sa_flags |= SA_NODEFER;
if ((SignalHandler.HostAction.sa_flags ^ SignalHandler.GuestAction.sa_flags) & SA_NODEFER) {
// If the guest is using SA_NODEFER then make sure to set it for the host as well
SignalHandler.HostAction.sa_flags &= ~SA_NODEFER;
SignalHandler.HostAction.sa_flags |= SignalHandler.GuestAction.sa_flags & SA_NODEFER;
}
if ((SignalHandler.HostAction.sa_flags ^ SignalHandler.GuestAction.sa_flags) & SA_RESTART) {