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:
parent
cea20ca3f3
commit
80ab6f1e8c
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue