aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/branch.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r--arch/mips/kernel/branch.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 01117e977a7f..374de839558d 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -12,6 +12,7 @@
12#include <asm/branch.h> 12#include <asm/branch.h>
13#include <asm/cpu.h> 13#include <asm/cpu.h>
14#include <asm/cpu-features.h> 14#include <asm/cpu-features.h>
15#include <asm/fpu.h>
15#include <asm/inst.h> 16#include <asm/inst.h>
16#include <asm/ptrace.h> 17#include <asm/ptrace.h>
17#include <asm/uaccess.h> 18#include <asm/uaccess.h>
@@ -21,7 +22,7 @@
21 */ 22 */
22int __compute_return_epc(struct pt_regs *regs) 23int __compute_return_epc(struct pt_regs *regs)
23{ 24{
24 unsigned int *addr, bit, fcr31; 25 unsigned int *addr, bit, fcr31, dspcontrol;
25 long epc; 26 long epc;
26 union mips_instruction insn; 27 union mips_instruction insn;
27 28
@@ -98,6 +99,18 @@ int __compute_return_epc(struct pt_regs *regs)
98 epc += 8; 99 epc += 8;
99 regs->cp0_epc = epc; 100 regs->cp0_epc = epc;
100 break; 101 break;
102 case bposge32_op:
103 if (!cpu_has_dsp)
104 goto sigill;
105
106 dspcontrol = rddsp(0x01);
107
108 if (dspcontrol >= 32) {
109 epc = epc + 4 + (insn.i_format.simmediate << 2);
110 } else
111 epc += 8;
112 regs->cp0_epc = epc;
113 break;
101 } 114 }
102 break; 115 break;
103 116
@@ -161,10 +174,13 @@ int __compute_return_epc(struct pt_regs *regs)
161 * And now the FPA/cp1 branch instructions. 174 * And now the FPA/cp1 branch instructions.
162 */ 175 */
163 case cop1_op: 176 case cop1_op:
164 if (!cpu_has_fpu) 177 preempt_disable();
165 fcr31 = current->thread.fpu.soft.fcr31; 178 if (is_fpu_owner())
166 else
167 asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); 179 asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
180 else
181 fcr31 = current->thread.fpu.hard.fcr31;
182 preempt_enable();
183
168 bit = (insn.i_format.rt >> 2); 184 bit = (insn.i_format.rt >> 2);
169 bit += (bit != 0); 185 bit += (bit != 0);
170 bit += 23; 186 bit += 23;
@@ -196,4 +212,9 @@ unaligned:
196 printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); 212 printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
197 force_sig(SIGBUS, current); 213 force_sig(SIGBUS, current);
198 return -EFAULT; 214 return -EFAULT;
215
216sigill:
217 printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
218 force_sig(SIGBUS, current);
219 return -EFAULT;
199} 220}