aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2007-04-13 13:37:26 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-04-20 09:58:37 -0400
commit5323180db75d562a287cb2020b07c9422df13df6 (patch)
tree71039fd0a03f89ebb3172d75a9e594d4f9f56fd6
parent9a9943575ade643368849e2c963094ac637867e0 (diff)
[MIPS] Disallow CpU exception in kernel again.
The commit 4d40bff7110e9e1a97ff8c01bdd6350e9867cc10 ("Allow CpU exception in kernel partially") was broken. The commit was to fix theoretical problem but broke usual case. Revert it for now. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/r2300_switch.S10
-rw-r--r--arch/mips/kernel/r4k_switch.S10
-rw-r--r--arch/mips/kernel/signal.c10
-rw-r--r--arch/mips/kernel/signal32.c10
-rw-r--r--arch/mips/kernel/traps.c21
-rw-r--r--include/asm-mips/fpu.h16
-rw-r--r--include/asm-mips/thread_info.h1
7 files changed, 21 insertions, 57 deletions
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 28c2e2e6af73..656bde2e11b1 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -49,7 +49,8 @@ LEAF(resume)
49#ifndef CONFIG_CPU_HAS_LLSC 49#ifndef CONFIG_CPU_HAS_LLSC
50 sw zero, ll_bit 50 sw zero, ll_bit
51#endif 51#endif
52 mfc0 t2, CP0_STATUS 52 mfc0 t1, CP0_STATUS
53 sw t1, THREAD_STATUS(a0)
53 cpu_save_nonscratch a0 54 cpu_save_nonscratch a0
54 sw ra, THREAD_REG31(a0) 55 sw ra, THREAD_REG31(a0)
55 56
@@ -59,8 +60,8 @@ LEAF(resume)
59 lw t3, TASK_THREAD_INFO(a0) 60 lw t3, TASK_THREAD_INFO(a0)
60 lw t0, TI_FLAGS(t3) 61 lw t0, TI_FLAGS(t3)
61 li t1, _TIF_USEDFPU 62 li t1, _TIF_USEDFPU
62 and t1, t0 63 and t2, t0, t1
63 beqz t1, 1f 64 beqz t2, 1f
64 nor t1, zero, t1 65 nor t1, zero, t1
65 66
66 and t0, t0, t1 67 and t0, t0, t1
@@ -73,13 +74,10 @@ LEAF(resume)
73 li t1, ~ST0_CU1 74 li t1, ~ST0_CU1
74 and t0, t0, t1 75 and t0, t0, t1
75 sw t0, ST_OFF(t3) 76 sw t0, ST_OFF(t3)
76 /* clear thread_struct CU1 bit */
77 and t2, t1
78 77
79 fpu_save_single a0, t0 # clobbers t0 78 fpu_save_single a0, t0 # clobbers t0
80 79
811: 801:
82 sw t2, THREAD_STATUS(a0)
83 /* 81 /*
84 * The order of restoring the registers takes care of the race 82 * The order of restoring the registers takes care of the race
85 * updating $28, $29 and kernelsp without disabling ints. 83 * updating $28, $29 and kernelsp without disabling ints.
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index c7698fd9955c..cc566cf12246 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -48,7 +48,8 @@
48#ifndef CONFIG_CPU_HAS_LLSC 48#ifndef CONFIG_CPU_HAS_LLSC
49 sw zero, ll_bit 49 sw zero, ll_bit
50#endif 50#endif
51 mfc0 t2, CP0_STATUS 51 mfc0 t1, CP0_STATUS
52 LONG_S t1, THREAD_STATUS(a0)
52 cpu_save_nonscratch a0 53 cpu_save_nonscratch a0
53 LONG_S ra, THREAD_REG31(a0) 54 LONG_S ra, THREAD_REG31(a0)
54 55
@@ -58,8 +59,8 @@
58 PTR_L t3, TASK_THREAD_INFO(a0) 59 PTR_L t3, TASK_THREAD_INFO(a0)
59 LONG_L t0, TI_FLAGS(t3) 60 LONG_L t0, TI_FLAGS(t3)
60 li t1, _TIF_USEDFPU 61 li t1, _TIF_USEDFPU
61 and t1, t0 62 and t2, t0, t1
62 beqz t1, 1f 63 beqz t2, 1f
63 nor t1, zero, t1 64 nor t1, zero, t1
64 65
65 and t0, t0, t1 66 and t0, t0, t1
@@ -72,13 +73,10 @@
72 li t1, ~ST0_CU1 73 li t1, ~ST0_CU1
73 and t0, t0, t1 74 and t0, t0, t1
74 LONG_S t0, ST_OFF(t3) 75 LONG_S t0, ST_OFF(t3)
75 /* clear thread_struct CU1 bit */
76 and t2, t1
77 76
78 fpu_save_double a0 t0 t1 # c0_status passed in t0 77 fpu_save_double a0 t0 t1 # c0_status passed in t0
79 # clobbers t1 78 # clobbers t1
801: 791:
81 LONG_S t2, THREAD_STATUS(a0)
82 80
83 /* 81 /*
84 * The order of restoring the registers takes care of the race 82 * The order of restoring the registers takes care of the race
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 8c3c5a5789b0..fa581192de21 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -113,10 +113,10 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
113 * Save FPU state to signal context. Signal handler 113 * Save FPU state to signal context. Signal handler
114 * will "inherit" current FPU state. 114 * will "inherit" current FPU state.
115 */ 115 */
116 preempt_disable();
116 own_fpu(1); 117 own_fpu(1);
117 enable_fp_in_kernel();
118 err |= save_fp_context(sc); 118 err |= save_fp_context(sc);
119 disable_fp_in_kernel(); 119 preempt_enable();
120 } 120 }
121 return err; 121 return err;
122} 122}
@@ -148,7 +148,10 @@ check_and_restore_fp_context(struct sigcontext __user *sc)
148 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 148 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
149 if (err > 0) 149 if (err > 0)
150 err = 0; 150 err = 0;
151 preempt_disable();
152 own_fpu(0);
151 err |= restore_fp_context(sc); 153 err |= restore_fp_context(sc);
154 preempt_enable();
152 return err ?: sig; 155 return err ?: sig;
153} 156}
154 157
@@ -187,11 +190,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
187 190
188 if (used_math) { 191 if (used_math) {
189 /* restore fpu context if we have used it before */ 192 /* restore fpu context if we have used it before */
190 own_fpu(0);
191 enable_fp_in_kernel();
192 if (!err) 193 if (!err)
193 err = check_and_restore_fp_context(sc); 194 err = check_and_restore_fp_context(sc);
194 disable_fp_in_kernel();
195 } else { 195 } else {
196 /* signal handler may have used FPU. Give it up. */ 196 /* signal handler may have used FPU. Give it up. */
197 lose_fpu(0); 197 lose_fpu(0);
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 151fd2f0893a..53a337cfeb66 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -209,10 +209,10 @@ static int setup_sigcontext32(struct pt_regs *regs,
209 * Save FPU state to signal context. Signal handler 209 * Save FPU state to signal context. Signal handler
210 * will "inherit" current FPU state. 210 * will "inherit" current FPU state.
211 */ 211 */
212 preempt_disable();
212 own_fpu(1); 213 own_fpu(1);
213 enable_fp_in_kernel();
214 err |= save_fp_context32(sc); 214 err |= save_fp_context32(sc);
215 disable_fp_in_kernel(); 215 preempt_enable();
216 } 216 }
217 return err; 217 return err;
218} 218}
@@ -225,7 +225,10 @@ check_and_restore_fp_context32(struct sigcontext32 __user *sc)
225 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 225 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
226 if (err > 0) 226 if (err > 0)
227 err = 0; 227 err = 0;
228 preempt_disable();
229 own_fpu(0);
228 err |= restore_fp_context32(sc); 230 err |= restore_fp_context32(sc);
231 preempt_enable();
229 return err ?: sig; 232 return err ?: sig;
230} 233}
231 234
@@ -261,11 +264,8 @@ static int restore_sigcontext32(struct pt_regs *regs,
261 264
262 if (used_math) { 265 if (used_math) {
263 /* restore fpu context if we have used it before */ 266 /* restore fpu context if we have used it before */
264 own_fpu(0);
265 enable_fp_in_kernel();
266 if (!err) 267 if (!err)
267 err = check_and_restore_fp_context32(sc); 268 err = check_and_restore_fp_context32(sc);
268 disable_fp_in_kernel();
269 } else { 269 } else {
270 /* signal handler may have used FPU. Give it up. */ 270 /* signal handler may have used FPU. Give it up. */
271 lose_fpu(0); 271 lose_fpu(0);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 7d76a85422b2..6b356f62289e 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -757,11 +757,12 @@ asmlinkage void do_cpu(struct pt_regs *regs)
757{ 757{
758 unsigned int cpid; 758 unsigned int cpid;
759 759
760 die_if_kernel("do_cpu invoked from kernel context!", regs);
761
760 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; 762 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
761 763
762 switch (cpid) { 764 switch (cpid) {
763 case 0: 765 case 0:
764 die_if_kernel("do_cpu invoked from kernel context!", regs);
765 if (!cpu_has_llsc) 766 if (!cpu_has_llsc)
766 if (!simulate_llsc(regs)) 767 if (!simulate_llsc(regs))
767 return; 768 return;
@@ -772,9 +773,6 @@ asmlinkage void do_cpu(struct pt_regs *regs)
772 break; 773 break;
773 774
774 case 1: 775 case 1:
775 if (!test_thread_flag(TIF_ALLOW_FP_IN_KERNEL))
776 die_if_kernel("do_cpu invoked from kernel context!",
777 regs);
778 if (used_math()) /* Using the FPU again. */ 776 if (used_math()) /* Using the FPU again. */
779 own_fpu(1); 777 own_fpu(1);
780 else { /* First time FPU user. */ 778 else { /* First time FPU user. */
@@ -782,19 +780,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
782 set_used_math(); 780 set_used_math();
783 } 781 }
784 782
785 if (raw_cpu_has_fpu) { 783 if (!raw_cpu_has_fpu) {
786 if (test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) {
787 local_irq_disable();
788 if (cpu_has_fpu)
789 regs->cp0_status |= ST0_CU1;
790 /*
791 * We must return without enabling
792 * interrupts to ensure keep FPU
793 * ownership until resume.
794 */
795 return;
796 }
797 } else {
798 int sig; 784 int sig;
799 sig = fpu_emulator_cop1Handler(regs, 785 sig = fpu_emulator_cop1Handler(regs,
800 &current->thread.fpu, 0); 786 &current->thread.fpu, 0);
@@ -836,7 +822,6 @@ asmlinkage void do_cpu(struct pt_regs *regs)
836 822
837 case 2: 823 case 2:
838 case 3: 824 case 3:
839 die_if_kernel("do_cpu invoked from kernel context!", regs);
840 break; 825 break;
841 } 826 }
842 827
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
index 4e12d1f9534f..71436f90203f 100644
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -68,8 +68,6 @@ do { \
68 /* We don't care about the c0 hazard here */ \ 68 /* We don't care about the c0 hazard here */ \
69} while (0) 69} while (0)
70 70
71#define __fpu_enabled() (read_c0_status() & ST0_CU1)
72
73#define enable_fpu() \ 71#define enable_fpu() \
74do { \ 72do { \
75 if (cpu_has_fpu) \ 73 if (cpu_has_fpu) \
@@ -162,18 +160,4 @@ static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
162 return tsk->thread.fpu.fpr; 160 return tsk->thread.fpu.fpr;
163} 161}
164 162
165static inline void enable_fp_in_kernel(void)
166{
167 set_thread_flag(TIF_ALLOW_FP_IN_KERNEL);
168 /* make sure CU1 and FPU ownership are consistent */
169 if (!__is_fpu_owner() && __fpu_enabled())
170 __disable_fpu();
171}
172
173static inline void disable_fp_in_kernel(void)
174{
175 BUG_ON(!__is_fpu_owner() && __fpu_enabled());
176 clear_thread_flag(TIF_ALLOW_FP_IN_KERNEL);
177}
178
179#endif /* _ASM_FPU_H */ 163#endif /* _ASM_FPU_H */
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index 6cf05f4a4e7e..fbcda8204473 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -119,7 +119,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
119#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ 119#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
120#define TIF_MEMDIE 18 120#define TIF_MEMDIE 18
121#define TIF_FREEZE 19 121#define TIF_FREEZE 19
122#define TIF_ALLOW_FP_IN_KERNEL 20
123#define TIF_SYSCALL_TRACE 31 /* syscall trace active */ 122#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
124 123
125#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) 124#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)