aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/i387.h
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-02-13 16:56:14 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-02-13 16:56:14 -0500
commit5b1cbac37798805c1fee18c8cebe5c0a13975b17 (patch)
treee56487f2338b236d21913f74f66a779fd71a5d7c /arch/x86/include/asm/i387.h
parentbe98c2cdb15ba26148cd2bd58a857d4f7759ed38 (diff)
i387: make irq_fpu_usable() tests more robust
Some code - especially the crypto layer - wants to use the x86 FP/MMX/AVX register set in what may be interrupt (typically softirq) context. That *can* be ok, but the tests for when it was ok were somewhat suspect. We cannot touch the thread-specific status bits either, so we'd better check that we're not going to try to save FP state or anything like that. Now, it may be that the TS bit is always cleared *before* we set the USEDFPU bit (and only set when we had already cleared the USEDFP before), so the TS bit test may actually have been sufficient, but it certainly was not obviously so. So this explicitly verifies that we will not touch the TS_USEDFPU bit, and adds a few related sanity-checks. Because it seems that somehow AES-NI is corrupting user FP state. The cause is not clear, and this patch doesn't fix it, but while debugging it I really wanted the code to be more obviously correct and robust. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86/include/asm/i387.h')
-rw-r--r--arch/x86/include/asm/i387.h54
1 files changed, 46 insertions, 8 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index a5c7ae504176..a29571821b99 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -307,9 +307,54 @@ static inline void __clear_fpu(struct task_struct *tsk)
307 } 307 }
308} 308}
309 309
310/*
311 * Were we in an interrupt that interrupted kernel mode?
312 *
313 * We can do a kernel_fpu_begin/end() pair *ONLY* if that
314 * pair does nothing at all: TS_USEDFPU must be clear (so
315 * that we don't try to save the FPU state), and TS must
316 * be set (so that the clts/stts pair does nothing that is
317 * visible in the interrupted kernel thread).
318 */
319static inline bool interrupted_kernel_fpu_idle(void)
320{
321 return !(current_thread_info()->status & TS_USEDFPU) &&
322 (read_cr0() & X86_CR0_TS);
323}
324
325/*
326 * Were we in user mode (or vm86 mode) when we were
327 * interrupted?
328 *
329 * Doing kernel_fpu_begin/end() is ok if we are running
330 * in an interrupt context from user mode - we'll just
331 * save the FPU state as required.
332 */
333static inline bool interrupted_user_mode(void)
334{
335 struct pt_regs *regs = get_irq_regs();
336 return regs && user_mode_vm(regs);
337}
338
339/*
340 * Can we use the FPU in kernel mode with the
341 * whole "kernel_fpu_begin/end()" sequence?
342 *
343 * It's always ok in process context (ie "not interrupt")
344 * but it is sometimes ok even from an irq.
345 */
346static inline bool irq_fpu_usable(void)
347{
348 return !in_interrupt() ||
349 interrupted_user_mode() ||
350 interrupted_kernel_fpu_idle();
351}
352
310static inline void kernel_fpu_begin(void) 353static inline void kernel_fpu_begin(void)
311{ 354{
312 struct thread_info *me = current_thread_info(); 355 struct thread_info *me = current_thread_info();
356
357 WARN_ON_ONCE(!irq_fpu_usable());
313 preempt_disable(); 358 preempt_disable();
314 if (me->status & TS_USEDFPU) 359 if (me->status & TS_USEDFPU)
315 __save_init_fpu(me->task); 360 __save_init_fpu(me->task);
@@ -323,14 +368,6 @@ static inline void kernel_fpu_end(void)
323 preempt_enable(); 368 preempt_enable();
324} 369}
325 370
326static inline bool irq_fpu_usable(void)
327{
328 struct pt_regs *regs;
329
330 return !in_interrupt() || !(regs = get_irq_regs()) || \
331 user_mode(regs) || (read_cr0() & X86_CR0_TS);
332}
333
334/* 371/*
335 * Some instructions like VIA's padlock instructions generate a spurious 372 * Some instructions like VIA's padlock instructions generate a spurious
336 * DNA fault but don't modify SSE registers. And these instructions 373 * DNA fault but don't modify SSE registers. And these instructions
@@ -367,6 +404,7 @@ static inline void irq_ts_restore(int TS_state)
367 */ 404 */
368static inline void save_init_fpu(struct task_struct *tsk) 405static inline void save_init_fpu(struct task_struct *tsk)
369{ 406{
407 WARN_ON_ONCE(task_thread_info(tsk)->status & TS_USEDFPU);
370 preempt_disable(); 408 preempt_disable();
371 __save_init_fpu(tsk); 409 __save_init_fpu(tsk);
372 stts(); 410 stts();