]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/mips/kernel/traps.c
MIPS: Support for hybrid FPRs
[karo-tx-linux.git] / arch / mips / kernel / traps.c
index 22b19c2750447418d5133df5d2d01f40e4b5ca85..165c275163b8f3cb2748dd5f3275c5950269c8a3 100644 (file)
@@ -724,6 +724,50 @@ int process_fpemu_return(int sig, void __user *fault_addr)
        }
 }
 
+static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
+                      unsigned long old_epc, unsigned long old_ra)
+{
+       union mips_instruction inst = { .word = opcode };
+       void __user *fault_addr = NULL;
+       int sig;
+
+       /* If it's obviously not an FP instruction, skip it */
+       switch (inst.i_format.opcode) {
+       case cop1_op:
+       case cop1x_op:
+       case lwc1_op:
+       case ldc1_op:
+       case swc1_op:
+       case sdc1_op:
+               break;
+
+       default:
+               return -1;
+       }
+
+       /*
+        * do_ri skipped over the instruction via compute_return_epc, undo
+        * that for the FPU emulator.
+        */
+       regs->cp0_epc = old_epc;
+       regs->regs[31] = old_ra;
+
+       /* Save the FP context to struct thread_struct */
+       lose_fpu(1);
+
+       /* Run the emulator */
+       sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
+                                      &fault_addr);
+
+       /* If something went wrong, signal */
+       process_fpemu_return(sig, fault_addr);
+
+       /* Restore the hardware register state */
+       own_fpu(1);
+
+       return 0;
+}
+
 /*
  * XXX Delayed fp exceptions when doing a lazy ctx switch XXX
  */
@@ -1016,6 +1060,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
 
                if (status < 0)
                        status = simulate_sync(regs, opcode);
+
+               if (status < 0)
+                       status = simulate_fp(regs, opcode, old_epc, old31);
        }
 
        if (status < 0)