sh: Fix occasional FPU register corruption under preempt.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 26 Mar 2008 10:02:47 +0000 (19:02 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 26 Mar 2008 10:02:47 +0000 (19:02 +0900)
Presently with preempt enabled there's the possibility to be preempted
after the TIF_USEDFPU test and the register save, leading to bogus
state post-__switch_to(). Use an explicit preempt_disable()/enable()
pair around unlazy_fpu()/clear_fpu() to avoid this. Follows the x86
change.

Reported-by: Takuo Koguchi <takuo.koguchi.sw@hitachi.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/cpu/sh2a/fpu.c
arch/sh/kernel/cpu/sh4/fpu.c
arch/sh/kernel/cpu/sh5/fpu.c
arch/sh/kernel/dump_task.c
arch/sh/kernel/process_32.c
arch/sh/kernel/signal_32.c
include/asm-sh/fpu.h
include/asm-sh/processor.h
include/asm-sh/processor_32.h
include/asm-sh/processor_64.h

index ff99562456fbe50f80308f479c960d617fb662bb..5627c0b3ffa82e2c9496fec63eeeb2861eade897 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/signal.h>
 #include <asm/processor.h>
 #include <asm/io.h>
+#include <asm/fpu.h>
 
 /* The PR (precision) bit in the FP Status Register must be clear when
  * an frchg instruction is executed, otherwise the instruction is undefined.
index 817f9939cda69242bd88032ffb6e18dd8262d2eb..8020796139f17ef45a7f860cacea8ac24018f6da 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/cpu/fpu.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/fpu.h>
 
 /* The PR (precision) bit in the FP Status Register must be clear when
  * an frchg instruction is executed, otherwise the instruction is undefined.
index 30b76a94abf2aedaf326fcc8ffd8d19746f227a9..dd4f51ffb50ea81f9af6f0931d27f050a55a1498 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/processor.h>
 #include <asm/user.h>
 #include <asm/io.h>
+#include <asm/fpu.h>
 
 /*
  * Initially load the FPU with signalling NANS.  This bit pattern
index 4a8a4083ff0b6a75ed166f454c5a1d3513819e09..1db7ce0f25d4a9c5089e6011984c3eba05356e16 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/elfcore.h>
 #include <linux/sched.h>
+#include <asm/fpu.h>
 
 /*
  * Capture the user space registers if the task is not running (in user space)
index 9ab1926b9d10c34e14fd24efb385f046990ee5aa..b98e37a1f54c05229c18eb4d865ff0e6e0e26437 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/ubc.h>
+#include <asm/fpu.h>
 
 static int hlt_counter;
 int ubc_usercnt = 0;
index f6b5fbfe75c459acde8d76f310462bd8282f141c..f311551d9a05b253fccd2b2d2ac0b8a78418bd6f 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/fpu.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
index f8429880a27011cab16851b2f83fad36fe3623f3..f89abf5920d808dbe545296b4b6b714c27e2ba5f 100644 (file)
@@ -1,9 +1,8 @@
 #ifndef __ASM_SH_FPU_H
 #define __ASM_SH_FPU_H
 
-#define SR_FD    0x00008000
-
 #ifndef __ASSEMBLY__
+#include <linux/preempt.h>
 #include <asm/ptrace.h>
 
 #ifdef CONFIG_SH_FPU
@@ -28,18 +27,23 @@ extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
 
 extern int do_fpu_inst(unsigned short, struct pt_regs *);
 
-#define unlazy_fpu(tsk, regs) do {                     \
-       if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {   \
-               save_fpu(tsk, regs);                    \
-       }                                               \
-} while (0)
-
-#define clear_fpu(tsk, regs) do {                              \
-       if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {           \
-               clear_tsk_thread_flag(tsk, TIF_USEDFPU);        \
-               release_fpu(regs);                              \
-       }                                                       \
-} while (0)
+static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+       preempt_disable();
+       if (test_tsk_thread_flag(tsk, TIF_USEDFPU))
+               save_fpu(tsk, regs);
+       preempt_enable();
+}
+
+static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+       preempt_disable();
+       if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
+               clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+               release_fpu(regs);
+       }
+       preempt_enable();
+}
 
 #endif /* __ASSEMBLY__ */
 
index 19fe47c1ca172adebdc1b2de45e3902f6352649a..ec707b98e5b91a88e9e21a6aa076490ae1ba6987 100644 (file)
@@ -2,7 +2,6 @@
 #define __ASM_SH_PROCESSOR_H
 
 #include <asm/cpu-features.h>
-#include <asm/fpu.h>
 
 #ifndef __ASSEMBLY__
 /*
index df2d5b039ef41ad5bfdf5bd0e99436461a49bb28..c09305d6a9d94b2ceabbcf5f8984ceb0fc06af93 100644 (file)
@@ -70,6 +70,7 @@ extern struct sh_cpuinfo cpu_data[];
  */
 #define SR_DSP         0x00001000
 #define SR_IMASK       0x000000f0
+#define SR_FD          0x00008000
 
 /*
  * FPU structure and data
index eda4bef448e9f867f70c23a31b9eaa2d5be2a8e4..88a2edf8fa5d000e1070443b736b0accfb3e77b7 100644 (file)
@@ -112,6 +112,7 @@ extern struct sh_cpuinfo cpu_data[];
 #endif
 
 #define SR_IMASK 0x000000f0
+#define SR_FD    0x00008000
 #define SR_SSTEP 0x08000000
 
 #ifndef __ASSEMBLY__