diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
| -rw-r--r-- | arch/mips/kernel/traps.c | 84 |
1 files changed, 37 insertions, 47 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 18f56a9dbcfa..7d76a85422b2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -610,16 +610,6 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 610 | if (fcr31 & FPU_CSR_UNI_X) { | 610 | if (fcr31 & FPU_CSR_UNI_X) { |
| 611 | int sig; | 611 | int sig; |
| 612 | 612 | ||
| 613 | preempt_disable(); | ||
| 614 | |||
| 615 | #ifdef CONFIG_PREEMPT | ||
| 616 | if (!is_fpu_owner()) { | ||
| 617 | /* We might lose fpu before disabling preempt... */ | ||
| 618 | own_fpu(); | ||
| 619 | BUG_ON(!used_math()); | ||
| 620 | restore_fp(current); | ||
| 621 | } | ||
| 622 | #endif | ||
| 623 | /* | 613 | /* |
| 624 | * Unimplemented operation exception. If we've got the full | 614 | * Unimplemented operation exception. If we've got the full |
| 625 | * software emulator on-board, let's use it... | 615 | * software emulator on-board, let's use it... |
| @@ -630,18 +620,12 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 630 | * register operands before invoking the emulator, which seems | 620 | * register operands before invoking the emulator, which seems |
| 631 | * a bit extreme for what should be an infrequent event. | 621 | * a bit extreme for what should be an infrequent event. |
| 632 | */ | 622 | */ |
| 633 | save_fp(current); | ||
| 634 | /* Ensure 'resume' not overwrite saved fp context again. */ | 623 | /* Ensure 'resume' not overwrite saved fp context again. */ |
| 635 | lose_fpu(); | 624 | lose_fpu(1); |
| 636 | |||
| 637 | preempt_enable(); | ||
| 638 | 625 | ||
| 639 | /* Run the emulator */ | 626 | /* Run the emulator */ |
| 640 | sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); | 627 | sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); |
| 641 | 628 | ||
| 642 | preempt_disable(); | ||
| 643 | |||
| 644 | own_fpu(); /* Using the FPU again. */ | ||
| 645 | /* | 629 | /* |
| 646 | * We can't allow the emulated instruction to leave any of | 630 | * We can't allow the emulated instruction to leave any of |
| 647 | * the cause bit set in $fcr31. | 631 | * the cause bit set in $fcr31. |
| @@ -649,9 +633,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 649 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | 633 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; |
| 650 | 634 | ||
| 651 | /* Restore the hardware register state */ | 635 | /* Restore the hardware register state */ |
| 652 | restore_fp(current); | 636 | own_fpu(1); /* Using the FPU again. */ |
| 653 | |||
| 654 | preempt_enable(); | ||
| 655 | 637 | ||
| 656 | /* If something went wrong, signal */ | 638 | /* If something went wrong, signal */ |
| 657 | if (sig) | 639 | if (sig) |
| @@ -775,12 +757,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
| 775 | { | 757 | { |
| 776 | unsigned int cpid; | 758 | unsigned int cpid; |
| 777 | 759 | ||
| 778 | die_if_kernel("do_cpu invoked from kernel context!", regs); | ||
| 779 | |||
| 780 | cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; | 760 | cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; |
| 781 | 761 | ||
| 782 | switch (cpid) { | 762 | switch (cpid) { |
| 783 | case 0: | 763 | case 0: |
| 764 | die_if_kernel("do_cpu invoked from kernel context!", regs); | ||
| 784 | if (!cpu_has_llsc) | 765 | if (!cpu_has_llsc) |
| 785 | if (!simulate_llsc(regs)) | 766 | if (!simulate_llsc(regs)) |
| 786 | return; | 767 | return; |
| @@ -791,21 +772,30 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
| 791 | break; | 772 | break; |
| 792 | 773 | ||
| 793 | case 1: | 774 | case 1: |
| 794 | preempt_disable(); | 775 | if (!test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) |
| 795 | 776 | die_if_kernel("do_cpu invoked from kernel context!", | |
| 796 | own_fpu(); | 777 | regs); |
| 797 | if (used_math()) { /* Using the FPU again. */ | 778 | if (used_math()) /* Using the FPU again. */ |
| 798 | restore_fp(current); | 779 | own_fpu(1); |
| 799 | } else { /* First time FPU user. */ | 780 | else { /* First time FPU user. */ |
| 800 | init_fpu(); | 781 | init_fpu(); |
| 801 | set_used_math(); | 782 | set_used_math(); |
| 802 | } | 783 | } |
| 803 | 784 | ||
| 804 | if (cpu_has_fpu) { | 785 | if (raw_cpu_has_fpu) { |
| 805 | preempt_enable(); | 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 | } | ||
| 806 | } else { | 797 | } else { |
| 807 | int sig; | 798 | int sig; |
| 808 | preempt_enable(); | ||
| 809 | sig = fpu_emulator_cop1Handler(regs, | 799 | sig = fpu_emulator_cop1Handler(regs, |
| 810 | ¤t->thread.fpu, 0); | 800 | ¤t->thread.fpu, 0); |
| 811 | if (sig) | 801 | if (sig) |
| @@ -1259,26 +1249,26 @@ static inline void mips_srs_init(void) | |||
| 1259 | /* | 1249 | /* |
| 1260 | * This is used by native signal handling | 1250 | * This is used by native signal handling |
| 1261 | */ | 1251 | */ |
| 1262 | asmlinkage int (*save_fp_context)(struct sigcontext *sc); | 1252 | asmlinkage int (*save_fp_context)(struct sigcontext __user *sc); |
| 1263 | asmlinkage int (*restore_fp_context)(struct sigcontext *sc); | 1253 | asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc); |
| 1264 | 1254 | ||
| 1265 | extern asmlinkage int _save_fp_context(struct sigcontext *sc); | 1255 | extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); |
| 1266 | extern asmlinkage int _restore_fp_context(struct sigcontext *sc); | 1256 | extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); |
| 1267 | 1257 | ||
| 1268 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); | 1258 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); |
| 1269 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); | 1259 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); |
| 1270 | 1260 | ||
| 1271 | #ifdef CONFIG_SMP | 1261 | #ifdef CONFIG_SMP |
| 1272 | static int smp_save_fp_context(struct sigcontext *sc) | 1262 | static int smp_save_fp_context(struct sigcontext __user *sc) |
| 1273 | { | 1263 | { |
| 1274 | return cpu_has_fpu | 1264 | return raw_cpu_has_fpu |
| 1275 | ? _save_fp_context(sc) | 1265 | ? _save_fp_context(sc) |
| 1276 | : fpu_emulator_save_context(sc); | 1266 | : fpu_emulator_save_context(sc); |
| 1277 | } | 1267 | } |
| 1278 | 1268 | ||
| 1279 | static int smp_restore_fp_context(struct sigcontext *sc) | 1269 | static int smp_restore_fp_context(struct sigcontext __user *sc) |
| 1280 | { | 1270 | { |
| 1281 | return cpu_has_fpu | 1271 | return raw_cpu_has_fpu |
| 1282 | ? _restore_fp_context(sc) | 1272 | ? _restore_fp_context(sc) |
| 1283 | : fpu_emulator_restore_context(sc); | 1273 | : fpu_emulator_restore_context(sc); |
| 1284 | } | 1274 | } |
| @@ -1306,14 +1296,14 @@ static inline void signal_init(void) | |||
| 1306 | /* | 1296 | /* |
| 1307 | * This is used by 32-bit signal stuff on the 64-bit kernel | 1297 | * This is used by 32-bit signal stuff on the 64-bit kernel |
| 1308 | */ | 1298 | */ |
| 1309 | asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc); | 1299 | asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc); |
| 1310 | asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc); | 1300 | asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc); |
| 1311 | 1301 | ||
| 1312 | extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc); | 1302 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); |
| 1313 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc); | 1303 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); |
| 1314 | 1304 | ||
| 1315 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc); | 1305 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); |
| 1316 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc); | 1306 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); |
| 1317 | 1307 | ||
| 1318 | static inline void signal32_init(void) | 1308 | static inline void signal32_init(void) |
| 1319 | { | 1309 | { |
