diff options
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r-- | arch/sh/kernel/traps_32.c | 95 |
1 files changed, 46 insertions, 49 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 511a9426cec5..b359b08a8e33 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/system.h> | 26 | #include <asm/system.h> |
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | #include <asm/fpu.h> | 28 | #include <asm/fpu.h> |
29 | #include <asm/kprobes.h> | ||
29 | 30 | ||
30 | #ifdef CONFIG_SH_KGDB | 31 | #ifdef CONFIG_SH_KGDB |
31 | #include <asm/kgdb.h> | 32 | #include <asm/kgdb.h> |
@@ -192,6 +193,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
192 | int ret, index, count; | 193 | int ret, index, count; |
193 | unsigned long *rm, *rn; | 194 | unsigned long *rm, *rn; |
194 | unsigned char *src, *dst; | 195 | unsigned char *src, *dst; |
196 | unsigned char __user *srcu, *dstu; | ||
195 | 197 | ||
196 | index = (instruction>>8)&15; /* 0x0F00 */ | 198 | index = (instruction>>8)&15; /* 0x0F00 */ |
197 | rn = ®s->regs[index]; | 199 | rn = ®s->regs[index]; |
@@ -206,28 +208,28 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
206 | case 0: /* mov.[bwl] to/from memory via r0+rn */ | 208 | case 0: /* mov.[bwl] to/from memory via r0+rn */ |
207 | if (instruction & 8) { | 209 | if (instruction & 8) { |
208 | /* from memory */ | 210 | /* from memory */ |
209 | src = (unsigned char*) *rm; | 211 | srcu = (unsigned char __user *)*rm; |
210 | src += regs->regs[0]; | 212 | srcu += regs->regs[0]; |
211 | dst = (unsigned char*) rn; | 213 | dst = (unsigned char *)rn; |
212 | *(unsigned long*)dst = 0; | 214 | *(unsigned long *)dst = 0; |
213 | 215 | ||
214 | #if !defined(__LITTLE_ENDIAN__) | 216 | #if !defined(__LITTLE_ENDIAN__) |
215 | dst += 4-count; | 217 | dst += 4-count; |
216 | #endif | 218 | #endif |
217 | if (ma->from(dst, src, count)) | 219 | if (ma->from(dst, srcu, count)) |
218 | goto fetch_fault; | 220 | goto fetch_fault; |
219 | 221 | ||
220 | sign_extend(count, dst); | 222 | sign_extend(count, dst); |
221 | } else { | 223 | } else { |
222 | /* to memory */ | 224 | /* to memory */ |
223 | src = (unsigned char*) rm; | 225 | src = (unsigned char *)rm; |
224 | #if !defined(__LITTLE_ENDIAN__) | 226 | #if !defined(__LITTLE_ENDIAN__) |
225 | src += 4-count; | 227 | src += 4-count; |
226 | #endif | 228 | #endif |
227 | dst = (unsigned char*) *rn; | 229 | dstu = (unsigned char __user *)*rn; |
228 | dst += regs->regs[0]; | 230 | dstu += regs->regs[0]; |
229 | 231 | ||
230 | if (ma->to(dst, src, count)) | 232 | if (ma->to(dstu, src, count)) |
231 | goto fetch_fault; | 233 | goto fetch_fault; |
232 | } | 234 | } |
233 | ret = 0; | 235 | ret = 0; |
@@ -235,10 +237,10 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
235 | 237 | ||
236 | case 1: /* mov.l Rm,@(disp,Rn) */ | 238 | case 1: /* mov.l Rm,@(disp,Rn) */ |
237 | src = (unsigned char*) rm; | 239 | src = (unsigned char*) rm; |
238 | dst = (unsigned char*) *rn; | 240 | dstu = (unsigned char __user *)*rn; |
239 | dst += (instruction&0x000F)<<2; | 241 | dstu += (instruction&0x000F)<<2; |
240 | 242 | ||
241 | if (ma->to(dst, src, 4)) | 243 | if (ma->to(dstu, src, 4)) |
242 | goto fetch_fault; | 244 | goto fetch_fault; |
243 | ret = 0; | 245 | ret = 0; |
244 | break; | 246 | break; |
@@ -247,28 +249,28 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
247 | if (instruction & 4) | 249 | if (instruction & 4) |
248 | *rn -= count; | 250 | *rn -= count; |
249 | src = (unsigned char*) rm; | 251 | src = (unsigned char*) rm; |
250 | dst = (unsigned char*) *rn; | 252 | dstu = (unsigned char __user *)*rn; |
251 | #if !defined(__LITTLE_ENDIAN__) | 253 | #if !defined(__LITTLE_ENDIAN__) |
252 | src += 4-count; | 254 | src += 4-count; |
253 | #endif | 255 | #endif |
254 | if (ma->to(dst, src, count)) | 256 | if (ma->to(dstu, src, count)) |
255 | goto fetch_fault; | 257 | goto fetch_fault; |
256 | ret = 0; | 258 | ret = 0; |
257 | break; | 259 | break; |
258 | 260 | ||
259 | case 5: /* mov.l @(disp,Rm),Rn */ | 261 | case 5: /* mov.l @(disp,Rm),Rn */ |
260 | src = (unsigned char*) *rm; | 262 | srcu = (unsigned char __user *)*rm; |
261 | src += (instruction&0x000F)<<2; | 263 | srcu += (instruction & 0x000F) << 2; |
262 | dst = (unsigned char*) rn; | 264 | dst = (unsigned char *)rn; |
263 | *(unsigned long*)dst = 0; | 265 | *(unsigned long *)dst = 0; |
264 | 266 | ||
265 | if (ma->from(dst, src, 4)) | 267 | if (ma->from(dst, srcu, 4)) |
266 | goto fetch_fault; | 268 | goto fetch_fault; |
267 | ret = 0; | 269 | ret = 0; |
268 | break; | 270 | break; |
269 | 271 | ||
270 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ | 272 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ |
271 | src = (unsigned char*) *rm; | 273 | srcu = (unsigned char __user *)*rm; |
272 | if (instruction & 4) | 274 | if (instruction & 4) |
273 | *rm += count; | 275 | *rm += count; |
274 | dst = (unsigned char*) rn; | 276 | dst = (unsigned char*) rn; |
@@ -277,7 +279,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
277 | #if !defined(__LITTLE_ENDIAN__) | 279 | #if !defined(__LITTLE_ENDIAN__) |
278 | dst += 4-count; | 280 | dst += 4-count; |
279 | #endif | 281 | #endif |
280 | if (ma->from(dst, src, count)) | 282 | if (ma->from(dst, srcu, count)) |
281 | goto fetch_fault; | 283 | goto fetch_fault; |
282 | sign_extend(count, dst); | 284 | sign_extend(count, dst); |
283 | ret = 0; | 285 | ret = 0; |
@@ -286,28 +288,28 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
286 | case 8: | 288 | case 8: |
287 | switch ((instruction&0xFF00)>>8) { | 289 | switch ((instruction&0xFF00)>>8) { |
288 | case 0x81: /* mov.w R0,@(disp,Rn) */ | 290 | case 0x81: /* mov.w R0,@(disp,Rn) */ |
289 | src = (unsigned char*) ®s->regs[0]; | 291 | src = (unsigned char *) ®s->regs[0]; |
290 | #if !defined(__LITTLE_ENDIAN__) | 292 | #if !defined(__LITTLE_ENDIAN__) |
291 | src += 2; | 293 | src += 2; |
292 | #endif | 294 | #endif |
293 | dst = (unsigned char*) *rm; /* called Rn in the spec */ | 295 | dstu = (unsigned char __user *)*rm; /* called Rn in the spec */ |
294 | dst += (instruction&0x000F)<<1; | 296 | dstu += (instruction & 0x000F) << 1; |
295 | 297 | ||
296 | if (ma->to(dst, src, 2)) | 298 | if (ma->to(dstu, src, 2)) |
297 | goto fetch_fault; | 299 | goto fetch_fault; |
298 | ret = 0; | 300 | ret = 0; |
299 | break; | 301 | break; |
300 | 302 | ||
301 | case 0x85: /* mov.w @(disp,Rm),R0 */ | 303 | case 0x85: /* mov.w @(disp,Rm),R0 */ |
302 | src = (unsigned char*) *rm; | 304 | srcu = (unsigned char __user *)*rm; |
303 | src += (instruction&0x000F)<<1; | 305 | srcu += (instruction & 0x000F) << 1; |
304 | dst = (unsigned char*) ®s->regs[0]; | 306 | dst = (unsigned char *) ®s->regs[0]; |
305 | *(unsigned long*)dst = 0; | 307 | *(unsigned long *)dst = 0; |
306 | 308 | ||
307 | #if !defined(__LITTLE_ENDIAN__) | 309 | #if !defined(__LITTLE_ENDIAN__) |
308 | dst += 2; | 310 | dst += 2; |
309 | #endif | 311 | #endif |
310 | if (ma->from(dst, src, 2)) | 312 | if (ma->from(dst, srcu, 2)) |
311 | goto fetch_fault; | 313 | goto fetch_fault; |
312 | sign_extend(2, dst); | 314 | sign_extend(2, dst); |
313 | ret = 0; | 315 | ret = 0; |
@@ -333,7 +335,8 @@ static inline int handle_delayslot(struct pt_regs *regs, | |||
333 | struct mem_access *ma) | 335 | struct mem_access *ma) |
334 | { | 336 | { |
335 | opcode_t instruction; | 337 | opcode_t instruction; |
336 | void *addr = (void *)(regs->pc + instruction_size(old_instruction)); | 338 | void __user *addr = (void __user *)(regs->pc + |
339 | instruction_size(old_instruction)); | ||
337 | 340 | ||
338 | if (copy_from_user(&instruction, addr, sizeof(instruction))) { | 341 | if (copy_from_user(&instruction, addr, sizeof(instruction))) { |
339 | /* the instruction-fetch faulted */ | 342 | /* the instruction-fetch faulted */ |
@@ -511,14 +514,6 @@ int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs, | |||
511 | return ret; | 514 | return ret; |
512 | } | 515 | } |
513 | 516 | ||
514 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
515 | #define lookup_exception_vector(x) \ | ||
516 | __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x))) | ||
517 | #else | ||
518 | #define lookup_exception_vector(x) \ | ||
519 | __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x))) | ||
520 | #endif | ||
521 | |||
522 | /* | 517 | /* |
523 | * Handle various address error exceptions: | 518 | * Handle various address error exceptions: |
524 | * - instruction address error: | 519 | * - instruction address error: |
@@ -542,7 +537,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
542 | 537 | ||
543 | /* Intentional ifdef */ | 538 | /* Intentional ifdef */ |
544 | #ifdef CONFIG_CPU_HAS_SR_RB | 539 | #ifdef CONFIG_CPU_HAS_SR_RB |
545 | lookup_exception_vector(error_code); | 540 | error_code = lookup_exception_vector(); |
546 | #endif | 541 | #endif |
547 | 542 | ||
548 | oldfs = get_fs(); | 543 | oldfs = get_fs(); |
@@ -559,7 +554,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
559 | } | 554 | } |
560 | 555 | ||
561 | set_fs(USER_DS); | 556 | set_fs(USER_DS); |
562 | if (copy_from_user(&instruction, (void *)(regs->pc), | 557 | if (copy_from_user(&instruction, (void __user *)(regs->pc), |
563 | sizeof(instruction))) { | 558 | sizeof(instruction))) { |
564 | /* Argh. Fault on the instruction itself. | 559 | /* Argh. Fault on the instruction itself. |
565 | This should never happen non-SMP | 560 | This should never happen non-SMP |
@@ -589,7 +584,7 @@ uspace_segv: | |||
589 | die("unaligned program counter", regs, error_code); | 584 | die("unaligned program counter", regs, error_code); |
590 | 585 | ||
591 | set_fs(KERNEL_DS); | 586 | set_fs(KERNEL_DS); |
592 | if (copy_from_user(&instruction, (void *)(regs->pc), | 587 | if (copy_from_user(&instruction, (void __user *)(regs->pc), |
593 | sizeof(instruction))) { | 588 | sizeof(instruction))) { |
594 | /* Argh. Fault on the instruction itself. | 589 | /* Argh. Fault on the instruction itself. |
595 | This should never happen non-SMP | 590 | This should never happen non-SMP |
@@ -683,7 +678,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | |||
683 | } | 678 | } |
684 | #endif | 679 | #endif |
685 | 680 | ||
686 | lookup_exception_vector(error_code); | 681 | error_code = lookup_exception_vector(); |
687 | 682 | ||
688 | local_irq_enable(); | 683 | local_irq_enable(); |
689 | CHK_REMOTE_DEBUG(regs); | 684 | CHK_REMOTE_DEBUG(regs); |
@@ -739,11 +734,13 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | |||
739 | struct pt_regs __regs) | 734 | struct pt_regs __regs) |
740 | { | 735 | { |
741 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 736 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
742 | unsigned long error_code; | 737 | unsigned long inst; |
743 | struct task_struct *tsk = current; | 738 | struct task_struct *tsk = current; |
744 | #ifdef CONFIG_SH_FPU_EMU | ||
745 | unsigned short inst = 0; | ||
746 | 739 | ||
740 | if (kprobe_handle_illslot(regs->pc) == 0) | ||
741 | return; | ||
742 | |||
743 | #ifdef CONFIG_SH_FPU_EMU | ||
747 | get_user(inst, (unsigned short *)regs->pc + 1); | 744 | get_user(inst, (unsigned short *)regs->pc + 1); |
748 | if (!do_fpu_inst(inst, regs)) { | 745 | if (!do_fpu_inst(inst, regs)) { |
749 | get_user(inst, (unsigned short *)regs->pc); | 746 | get_user(inst, (unsigned short *)regs->pc); |
@@ -754,12 +751,12 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | |||
754 | /* not a FPU inst. */ | 751 | /* not a FPU inst. */ |
755 | #endif | 752 | #endif |
756 | 753 | ||
757 | lookup_exception_vector(error_code); | 754 | inst = lookup_exception_vector(); |
758 | 755 | ||
759 | local_irq_enable(); | 756 | local_irq_enable(); |
760 | CHK_REMOTE_DEBUG(regs); | 757 | CHK_REMOTE_DEBUG(regs); |
761 | force_sig(SIGILL, tsk); | 758 | force_sig(SIGILL, tsk); |
762 | die_if_no_fixup("illegal slot instruction", regs, error_code); | 759 | die_if_no_fixup("illegal slot instruction", regs, inst); |
763 | } | 760 | } |
764 | 761 | ||
765 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | 762 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, |
@@ -769,7 +766,7 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | |||
769 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 766 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
770 | long ex; | 767 | long ex; |
771 | 768 | ||
772 | lookup_exception_vector(ex); | 769 | ex = lookup_exception_vector(); |
773 | die_if_kernel("exception", regs, ex); | 770 | die_if_kernel("exception", regs, ex); |
774 | } | 771 | } |
775 | 772 | ||