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 | } |
