diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-04-13 13:37:26 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-04-20 09:58:37 -0400 |
commit | 5323180db75d562a287cb2020b07c9422df13df6 (patch) | |
tree | 71039fd0a03f89ebb3172d75a9e594d4f9f56fd6 /arch/mips/kernel | |
parent | 9a9943575ade643368849e2c963094ac637867e0 (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>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/r2300_switch.S | 10 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_switch.S | 10 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 21 |
5 files changed, 21 insertions, 40 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 | ||
81 | 1: | 80 | 1: |
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 |
80 | 1: | 79 | 1: |
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 | ¤t->thread.fpu, 0); | 786 | ¤t->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 | ||