mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 10:00:16 +02:00
Linux/GuestFrames: Ensure MXCSR is saved and restored on signal
This was causing an unfortunate set of circumstances where Dark Souls III was modifying MXCSR and we weren't saving it, cause the value to change from 0x9fc0 to 0. This "enabled" float exceptions by unmasking the exception masks in MXCSR. This in turn had Dark Souls III's `expf` function to fault out, as it checks if the MXCSR exception masks are set or not for determining if underflow should assert or not. Wow64/arm64ec has a similar problem where it always sets back to default on signal. Which means game lose DAZ, but I'm not fixing that bug right now. Fixes #5391
This commit is contained in:
1 file changed
+18
@@ -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
|
||||
|
||||
Reference in new issue
Block a user