diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 22b19c275044..ad3d2031c327 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -724,6 +724,50 @@ int process_fpemu_return(int sig, void __user *fault_addr) | |||
724 | } | 724 | } |
725 | } | 725 | } |
726 | 726 | ||
727 | static int simulate_fp(struct pt_regs *regs, unsigned int opcode, | ||
728 | unsigned long old_epc, unsigned long old_ra) | ||
729 | { | ||
730 | union mips_instruction inst = { .word = opcode }; | ||
731 | void __user *fault_addr = NULL; | ||
732 | int sig; | ||
733 | |||
734 | /* If it's obviously not an FP instruction, skip it */ | ||
735 | switch (inst.i_format.opcode) { | ||
736 | case cop1_op: | ||
737 | case cop1x_op: | ||
738 | case lwc1_op: | ||
739 | case ldc1_op: | ||
740 | case swc1_op: | ||
741 | case sdc1_op: | ||
742 | break; | ||
743 | |||
744 | default: | ||
745 | return -1; | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * do_ri skipped over the instruction via compute_return_epc, undo | ||
750 | * that for the FPU emulator. | ||
751 | */ | ||
752 | regs->cp0_epc = old_epc; | ||
753 | regs->regs[31] = old_ra; | ||
754 | |||
755 | /* Save the FP context to struct thread_struct */ | ||
756 | lose_fpu(1); | ||
757 | |||
758 | /* Run the emulator */ | ||
759 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, | ||
760 | &fault_addr); | ||
761 | |||
762 | /* If something went wrong, signal */ | ||
763 | process_fpemu_return(sig, fault_addr); | ||
764 | |||
765 | /* Restore the hardware register state */ | ||
766 | own_fpu(1); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
727 | /* | 771 | /* |
728 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX | 772 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX |
729 | */ | 773 | */ |
@@ -1016,6 +1060,9 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
1016 | 1060 | ||
1017 | if (status < 0) | 1061 | if (status < 0) |
1018 | status = simulate_sync(regs, opcode); | 1062 | status = simulate_sync(regs, opcode); |
1063 | |||
1064 | if (status < 0) | ||
1065 | status = simulate_fp(regs, opcode, old_epc, old31); | ||
1019 | } | 1066 | } |
1020 | 1067 | ||
1021 | if (status < 0) | 1068 | if (status < 0) |
@@ -1380,12 +1427,19 @@ asmlinkage void do_mcheck(struct pt_regs *regs) | |||
1380 | show_regs(regs); | 1427 | show_regs(regs); |
1381 | 1428 | ||
1382 | if (multi_match) { | 1429 | if (multi_match) { |
1383 | printk("Index : %0x\n", read_c0_index()); | 1430 | pr_err("Index : %0x\n", read_c0_index()); |
1384 | printk("Pagemask: %0x\n", read_c0_pagemask()); | 1431 | pr_err("Pagemask: %0x\n", read_c0_pagemask()); |
1385 | printk("EntryHi : %0*lx\n", field, read_c0_entryhi()); | 1432 | pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); |
1386 | printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); | 1433 | pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); |
1387 | printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); | 1434 | pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); |
1388 | printk("\n"); | 1435 | pr_err("Wired : %0x\n", read_c0_wired()); |
1436 | pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); | ||
1437 | if (cpu_has_htw) { | ||
1438 | pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); | ||
1439 | pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); | ||
1440 | pr_err("PWCtl : %0x\n", read_c0_pwctl()); | ||
1441 | } | ||
1442 | pr_err("\n"); | ||
1389 | dump_tlb_all(); | 1443 | dump_tlb_all(); |
1390 | } | 1444 | } |
1391 | 1445 | ||