mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 12:00:17 +02:00
Merge pull request #5401 from Sonicadvance1/126
Linux/GuestFrames: Ensure MXCSR is saved and restored on signal
This commit is contained in:
5 files changed
+89
-6
No files matched your search
@@ -2756,7 +2756,7 @@ void OpDispatchBuilder::SaveSSEState(Ref MemBase) {
|
||||
|
||||
void OpDispatchBuilder::SaveMXCSRState(Ref MemBase) {
|
||||
// Store MXCSR and the mask for all bits.
|
||||
_StoreMemPairGPR(OpSize::i32Bit, GetMXCSR(), Constant(0xFFFF), MemBase, 24);
|
||||
_StoreMemPairGPR(OpSize::i32Bit, GetMXCSR(), Constant(0xFFC0), MemBase, 24);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SaveAVXState(Ref MemBase) {
|
||||
|
||||
@@ -180,6 +180,10 @@ void SignalDelegator::RestoreFrame_x64(FEXCore::Core::InternalThreadState* Threa
|
||||
CTX->SetXMMRegistersFromState(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
// Technically if mxcsr contains invalid bits then rt_sigreturn should return -EINVAL.
|
||||
// TODO: FEX doesn't support this today.
|
||||
Frame->State.mxcsr = fpstate->mxcsr & 0xFFC0;
|
||||
|
||||
// FCW store default
|
||||
Frame->State.FCW = fpstate->fcw;
|
||||
Frame->State.AbridgedFTW = fpstate->ftw;
|
||||
@@ -254,6 +258,9 @@ void SignalDelegator::RestoreFrame_ia32(FEXCore::Core::InternalThreadState* Thre
|
||||
CTX->SetXMMRegistersFromState(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
// Invalid bits are silently masked off in 32-bit.
|
||||
Frame->State.mxcsr = fpstate->mxcsr & 0xFFC0;
|
||||
|
||||
// FCW store default
|
||||
Frame->State.FCW = fpstate->fcw;
|
||||
Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw);
|
||||
@@ -330,6 +337,9 @@ void SignalDelegator::RestoreRTFrame_ia32(FEXCore::Core::InternalThreadState* Th
|
||||
CTX->SetXMMRegistersFromState(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
// Invalid bits are silently masked off in 32-bit.
|
||||
Frame->State.mxcsr = fpstate->mxcsr & 0xFFC0;
|
||||
|
||||
// FCW store default
|
||||
Frame->State.FCW = fpstate->fcw;
|
||||
Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw);
|
||||
@@ -471,6 +481,10 @@ uint64_t SignalDelegator::SetupFrame_x64(FEXCore::Core::InternalThreadState* Thr
|
||||
CTX->ReconstructXMMRegisters(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
// Save mxcsr and the default mask.
|
||||
fpstate->mxcsr = Frame->State.mxcsr;
|
||||
fpstate->mxcsr_mask = 0xFFC0;
|
||||
|
||||
// FCW store default
|
||||
fpstate->fcw = Frame->State.FCW;
|
||||
fpstate->ftw = Frame->State.AbridgedFTW;
|
||||
@@ -594,6 +608,8 @@ uint64_t SignalDelegator::SetupFrame_ia32(FEXCore::Core::InternalThreadState* Th
|
||||
CTX->ReconstructXMMRegisters(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
fpstate->mxcsr = Frame->State.mxcsr;
|
||||
|
||||
// FCW store default
|
||||
fpstate->fcw = Frame->State.FCW;
|
||||
// Reconstruct FSW
|
||||
@@ -729,6 +745,8 @@ uint64_t SignalDelegator::SetupRTFrame_ia32(FEXCore::Core::InternalThreadState*
|
||||
CTX->ReconstructXMMRegisters(Thread, fpstate->_xmm, nullptr);
|
||||
}
|
||||
|
||||
fpstate->mxcsr = Frame->State.mxcsr;
|
||||
|
||||
// FCW store default
|
||||
fpstate->fcw = Frame->State.FCW;
|
||||
// Reconstruct FSW
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <signal.h>
|
||||
|
||||
extern "C" void IntInstruction();
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wattributes" // Suppress warning in case control-flow checks aren't enabled
|
||||
__attribute__((naked, nocf_check)) static void InvalidINT() {
|
||||
__asm volatile(R"(
|
||||
IntInstruction:
|
||||
hlt;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((noinline)) uint32_t GetMXCSR() {
|
||||
uint32_t Result {};
|
||||
asm volatile("stmxcsr %[Result]" : [Result] "=m"(Result)::"memory");
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void SetMXCSR(uint32_t MXCSR) {
|
||||
asm volatile("ldmxcsr %[MXCSR]" ::[MXCSR] "m"(MXCSR) : "memory");
|
||||
}
|
||||
|
||||
static uint32_t MXCSRFromContext {};
|
||||
static void MXCSR_Handler(int signal, siginfo_t* siginfo, void* context) {
|
||||
ucontext_t* _context = (ucontext_t*)context;
|
||||
|
||||
// Enable DAZ. This will get masked off on signal return.
|
||||
SetMXCSR(0x1fc0);
|
||||
|
||||
#ifdef REG_RIP
|
||||
#define FEX_IP_REG REG_RIP
|
||||
#else
|
||||
#define FEX_IP_REG REG_EIP
|
||||
#endif
|
||||
_context->uc_mcontext.gregs[FEX_IP_REG] += 1;
|
||||
|
||||
// Save the MXCSR from the context.
|
||||
MXCSRFromContext = _context->uc_mcontext.fpregs->mxcsr;
|
||||
#undef FEX_IP_REG
|
||||
}
|
||||
|
||||
TEST_CASE("Signals: Restoring MXCSR") {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = MXCSR_Handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &act, nullptr);
|
||||
|
||||
// Get the old MXCSR mask.
|
||||
auto MXCSROld = GetMXCSR();
|
||||
|
||||
InvalidINT();
|
||||
|
||||
// Get the potentially broken MXCSR mask.
|
||||
auto MXCSRNew = GetMXCSR();
|
||||
|
||||
// Ensure that all three masks match.
|
||||
CHECK(MXCSRFromContext == MXCSROld);
|
||||
CHECK(MXCSROld == MXCSRNew);
|
||||
printf("0x%08x 0x%08x\n", MXCSROld, MXCSRNew);
|
||||
}
|
||||
@@ -1343,8 +1343,8 @@
|
||||
"stp q28, q29, [x4, #352]",
|
||||
"stp q30, q31, [x4, #384]",
|
||||
"ldr w20, [x28, #972]",
|
||||
"mov w21, #0xffc0",
|
||||
"and w20, w20, #0xffc0",
|
||||
"mov w21, #0xffff",
|
||||
"stp w20, w21, [x4, #24]"
|
||||
]
|
||||
},
|
||||
@@ -1583,8 +1583,8 @@
|
||||
"cbnz x20, #+0x8",
|
||||
"b #+0x14",
|
||||
"ldr w20, [x28, #972]",
|
||||
"mov w21, #0xffc0",
|
||||
"and w20, w20, #0xffc0",
|
||||
"mov w21, #0xffff",
|
||||
"stp w20, w21, [x4, #24]",
|
||||
"ubfx x20, x4, #0, #3",
|
||||
"str x20, [x4, #512]"
|
||||
@@ -1687,8 +1687,8 @@
|
||||
"cbnz x20, #+0x8",
|
||||
"b #+0x14",
|
||||
"ldr w20, [x28, #972]",
|
||||
"mov w21, #0xffc0",
|
||||
"and w20, w20, #0xffc0",
|
||||
"mov w21, #0xffff",
|
||||
"stp w20, w21, [x4, #24]",
|
||||
"ubfx x20, x4, #0, #3",
|
||||
"str x20, [x4, #512]"
|
||||
|
||||
@@ -1615,8 +1615,8 @@
|
||||
"stp q28, q29, [x4, #352]",
|
||||
"stp q30, q31, [x4, #384]",
|
||||
"ldr w20, [x28, #972]",
|
||||
"mov w21, #0xffc0",
|
||||
"and w20, w20, #0xffc0",
|
||||
"mov w21, #0xffff",
|
||||
"stp w20, w21, [x4, #24]"
|
||||
]
|
||||
},
|
||||
@@ -1855,8 +1855,8 @@
|
||||
"cbnz x20, #+0x8",
|
||||
"b #+0x14",
|
||||
"ldr w20, [x28, #972]",
|
||||
"mov w21, #0xffc0",
|
||||
"and w20, w20, #0xffc0",
|
||||
"mov w21, #0xffff",
|
||||
"stp w20, w21, [x4, #24]",
|
||||
"ubfx x20, x4, #0, #3",
|
||||
"str x20, [x4, #512]"
|
||||
|
||||
Reference in new issue
Block a user