aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r--arch/sh/kernel/traps_32.c95
1 files changed, 46 insertions, 49 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 511a9426cec..b359b08a8e3 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 = &regs->regs[index]; 199 rn = &regs->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*) &regs->regs[0]; 291 src = (unsigned char *) &regs->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*) &regs->regs[0]; 306 dst = (unsigned char *) &regs->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
765asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, 762asmlinkage 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