diff options
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r-- | arch/mips/kernel/branch.c | 29 |
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 | */ |
22 | int __compute_return_epc(struct pt_regs *regs) | 23 | int __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 | |||
216 | sigill: | ||
217 | printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); | ||
218 | force_sig(SIGBUS, current); | ||
219 | return -EFAULT; | ||
199 | } | 220 | } |