i387: use 'restore_fpu_checking()' directly in task switching code

This inlines what is usually just a couple of instructions, but more
importantly it also fixes the theoretical error case (can that FPU
restore really ever fail? Maybe we should remove the checking).

We can't start sending signals from within the scheduler, we're much too
deep in the kernel and are holding the runqueue lock etc.  So don't
bother even trying.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2012-02-19 11:48:44 -08:00
parent cea20ca3f3
commit 80ab6f1e8c
2 changed files with 22 additions and 35 deletions

View File

@ -29,7 +29,6 @@ extern unsigned int sig_xstate_size;
extern void fpu_init(void); extern void fpu_init(void);
extern void mxcsr_feature_mask_init(void); extern void mxcsr_feature_mask_init(void);
extern int init_fpu(struct task_struct *child); extern int init_fpu(struct task_struct *child);
extern void __math_state_restore(struct task_struct *);
extern void math_state_restore(void); extern void math_state_restore(void);
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
@ -269,6 +268,16 @@ static inline int fpu_restore_checking(struct fpu *fpu)
static inline int restore_fpu_checking(struct task_struct *tsk) static inline int restore_fpu_checking(struct task_struct *tsk)
{ {
/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
is pending. Clear the x87 state here by setting it to fixed
values. "m" is a random variable that should be in L1 */
alternative_input(
ASM_NOP8 ASM_NOP2,
"emms\n\t" /* clear stack tags */
"fildl %P[addr]", /* set F?P to defined value */
X86_FEATURE_FXSAVE_LEAK,
[addr] "m" (tsk->thread.has_fpu));
return fpu_restore_checking(&tsk->thread.fpu); return fpu_restore_checking(&tsk->thread.fpu);
} }
@ -378,8 +387,10 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
*/ */
static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
{ {
if (fpu.preload) if (fpu.preload) {
__math_state_restore(new); if (unlikely(restore_fpu_checking(new)))
__thread_fpu_end(new);
}
} }
/* /*

View File

@ -570,37 +570,6 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void)
{ {
} }
/*
* This gets called with the process already owning the
* FPU state, and with CR0.TS cleared. It just needs to
* restore the FPU register state.
*/
void __math_state_restore(struct task_struct *tsk)
{
/* We need a safe address that is cheap to find and that is already
in L1. We've just brought in "tsk->thread.has_fpu", so use that */
#define safe_address (tsk->thread.has_fpu)
/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
is pending. Clear the x87 state here by setting it to fixed
values. safe_address is a random variable that should be in L1 */
alternative_input(
ASM_NOP8 ASM_NOP2,
"emms\n\t" /* clear stack tags */
"fildl %P[addr]", /* set F?P to defined value */
X86_FEATURE_FXSAVE_LEAK,
[addr] "m" (safe_address));
/*
* Paranoid restore. send a SIGSEGV if we fail to restore the state.
*/
if (unlikely(restore_fpu_checking(tsk))) {
__thread_fpu_end(tsk);
force_sig(SIGSEGV, tsk);
return;
}
}
/* /*
* 'math_state_restore()' saves the current math information in the * 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task * old math state array, and gets the new ones from the current task
@ -631,7 +600,14 @@ void math_state_restore(void)
} }
__thread_fpu_begin(tsk); __thread_fpu_begin(tsk);
__math_state_restore(tsk); /*
* Paranoid restore. send a SIGSEGV if we fail to restore the state.
*/
if (unlikely(restore_fpu_checking(tsk))) {
__thread_fpu_end(tsk);
force_sig(SIGSEGV, tsk);
return;
}
tsk->fpu_counter++; tsk->fpu_counter++;
} }