Oracle bug 7708133 FP corruption running a JRockit test program Chuck Anderson chuck.anderson@oracle.com 02/17/2011 Oracle patch linux-2.6-x86_64-7708133-fix-fp-corruption.patch was mostly replaced by Red Hat's: linux-2.6.9-x86_64-floating-point-state-corruption-after-handlin.patch They left out an important part of our patch. This patch adds it back in. The header in linux-2.6-x86_64-7708133-fix-fp-corruption.patch describes the original problem. The excerpt below describes why we must add back in the part that Red Hat left out. See the last paragraph below: If we needed to save FP state prior to calling a signal handler (used_math() was true) then we saved it to the address pointed to by struct sigcontext.fpstate. If !used_math() then we set fpstate = NULL. restore_sigcontext() is called to restore that context after returning from the signal handler. If fpstate != NULL then restore_i387() is called to restore FP state. The problem is that TS_USEDFPU may not be set. When set, TS_USEDFPU indicates that the FP state for the task is in the FP registers. We just restored state to the FP registers so TS_USEDFPU must also be set. Otherwise, if we are preempted after restoring FP state then context switching code will assume that there is no context in the FP registers that needs to be saved. It will assume that the FP context for this task has been saved to struct task_struct.thread.i387.fxsave, which has a stale context. It could be from the signal handler causing us to inherit the signal handler's FP values. The correct state is in the FP registers. The fix is to check if TS_USEDFPU is set. If not, set it and make sure CR0.ts is not set (clts()) to indicate that the FPU has this task's context and is ready for use. We must also clear TS_USEDFPU when we save our FP context in save_i387() and set CR0.ts (stts()) to indicate that the FPU must be initialized on first use by the signal handler. --- linux-2.6.9/arch/x86_64/kernel/i387.c.orig 2011-02-17 11:52:51.000000000 -0800 +++ linux-2.6.9/arch/x86_64/kernel/i387.c 2011-02-17 12:04:36.000000000 -0800 @@ -96,6 +96,7 @@ if (tsk->thread_info->status & TS_USEDFPU) { err = save_i387_checking((struct i387_fxsave_struct __user *)buf); if (err) return err; + tsk->thread_info->status &= ~TS_USEDFPU; stts(); } else { if (__copy_to_user(buf, &tsk->thread.i387.fxsave,