diff options
author | Magnus Damm <magnus.damm@gmail.com> | 2008-02-07 06:04:12 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-02-14 00:22:09 -0500 |
commit | 4b5a9ef5279aed2c34d92fee62cf6d0c6ffacbaa (patch) | |
tree | 52dba448fd983fc6261e83e77a2b9addb7138917 /arch/sh/kernel/traps_32.c | |
parent | 4252c659a4e7f4260e4bdc87538578236c51ab2d (diff) |
sh: use opcode_t and enable unaligned code for sh2a
This patch converts the unaligned access handling code to use opcode_t
instead of u16. While at it, enable unaligned access handling for sh2a.
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r-- | arch/sh/kernel/traps_32.c | 59 |
1 files changed, 25 insertions, 34 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 2e7dd2ebec9a..25b1b8672cf0 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -179,7 +179,7 @@ static inline void sign_extend(unsigned int count, unsigned char *dst) | |||
179 | * (if that instruction is in a branch delay slot) | 179 | * (if that instruction is in a branch delay slot) |
180 | * - return 0 if emulation okay, -EFAULT on existential error | 180 | * - return 0 if emulation okay, -EFAULT on existential error |
181 | */ | 181 | */ |
182 | static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | 182 | static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs) |
183 | { | 183 | { |
184 | int ret, index, count; | 184 | int ret, index, count; |
185 | unsigned long *rm, *rn; | 185 | unsigned long *rm, *rn; |
@@ -320,11 +320,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
320 | * emulate the instruction in the delay slot | 320 | * emulate the instruction in the delay slot |
321 | * - fetches the instruction from PC+2 | 321 | * - fetches the instruction from PC+2 |
322 | */ | 322 | */ |
323 | static inline int handle_unaligned_delayslot(struct pt_regs *regs) | 323 | static inline int handle_unaligned_delayslot(struct pt_regs *regs, |
324 | opcode_t old_instruction) | ||
324 | { | 325 | { |
325 | u16 instruction; | 326 | opcode_t instruction; |
327 | void *addr = (void *)(regs->pc + instruction_size(old_instruction)); | ||
326 | 328 | ||
327 | if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) { | 329 | if (copy_from_user(&instruction, addr, sizeof(instruction))) { |
328 | /* the instruction-fetch faulted */ | 330 | /* the instruction-fetch faulted */ |
329 | if (user_mode(regs)) | 331 | if (user_mode(regs)) |
330 | return -EFAULT; | 332 | return -EFAULT; |
@@ -334,7 +336,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
334 | regs, 0); | 336 | regs, 0); |
335 | } | 337 | } |
336 | 338 | ||
337 | return handle_unaligned_ins(instruction,regs); | 339 | return handle_unaligned_ins(instruction, regs); |
338 | } | 340 | } |
339 | 341 | ||
340 | /* | 342 | /* |
@@ -357,10 +359,10 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
357 | * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit | 359 | * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit |
358 | * opcodes.. | 360 | * opcodes.. |
359 | */ | 361 | */ |
360 | #ifndef CONFIG_CPU_SH2A | 362 | |
361 | static int handle_unaligned_notify_count = 10; | 363 | static int handle_unaligned_notify_count = 10; |
362 | 364 | ||
363 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | 365 | static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs) |
364 | { | 366 | { |
365 | u_int rm; | 367 | u_int rm; |
366 | int ret, index; | 368 | int ret, index; |
@@ -375,7 +377,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
375 | printk(KERN_NOTICE "Fixing up unaligned userspace access " | 377 | printk(KERN_NOTICE "Fixing up unaligned userspace access " |
376 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | 378 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", |
377 | current->comm, task_pid_nr(current), | 379 | current->comm, task_pid_nr(current), |
378 | (u16 *)regs->pc, instruction); | 380 | (void *)regs->pc, instruction); |
379 | } | 381 | } |
380 | 382 | ||
381 | ret = -EFAULT; | 383 | ret = -EFAULT; |
@@ -383,19 +385,19 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
383 | case 0x0000: | 385 | case 0x0000: |
384 | if (instruction==0x000B) { | 386 | if (instruction==0x000B) { |
385 | /* rts */ | 387 | /* rts */ |
386 | ret = handle_unaligned_delayslot(regs); | 388 | ret = handle_unaligned_delayslot(regs, instruction); |
387 | if (ret==0) | 389 | if (ret==0) |
388 | regs->pc = regs->pr; | 390 | regs->pc = regs->pr; |
389 | } | 391 | } |
390 | else if ((instruction&0x00FF)==0x0023) { | 392 | else if ((instruction&0x00FF)==0x0023) { |
391 | /* braf @Rm */ | 393 | /* braf @Rm */ |
392 | ret = handle_unaligned_delayslot(regs); | 394 | ret = handle_unaligned_delayslot(regs, instruction); |
393 | if (ret==0) | 395 | if (ret==0) |
394 | regs->pc += rm + 4; | 396 | regs->pc += rm + 4; |
395 | } | 397 | } |
396 | else if ((instruction&0x00FF)==0x0003) { | 398 | else if ((instruction&0x00FF)==0x0003) { |
397 | /* bsrf @Rm */ | 399 | /* bsrf @Rm */ |
398 | ret = handle_unaligned_delayslot(regs); | 400 | ret = handle_unaligned_delayslot(regs, instruction); |
399 | if (ret==0) { | 401 | if (ret==0) { |
400 | regs->pr = regs->pc + 4; | 402 | regs->pr = regs->pc + 4; |
401 | regs->pc += rm + 4; | 403 | regs->pc += rm + 4; |
@@ -416,13 +418,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
416 | case 0x4000: | 418 | case 0x4000: |
417 | if ((instruction&0x00FF)==0x002B) { | 419 | if ((instruction&0x00FF)==0x002B) { |
418 | /* jmp @Rm */ | 420 | /* jmp @Rm */ |
419 | ret = handle_unaligned_delayslot(regs); | 421 | ret = handle_unaligned_delayslot(regs, instruction); |
420 | if (ret==0) | 422 | if (ret==0) |
421 | regs->pc = rm; | 423 | regs->pc = rm; |
422 | } | 424 | } |
423 | else if ((instruction&0x00FF)==0x000B) { | 425 | else if ((instruction&0x00FF)==0x000B) { |
424 | /* jsr @Rm */ | 426 | /* jsr @Rm */ |
425 | ret = handle_unaligned_delayslot(regs); | 427 | ret = handle_unaligned_delayslot(regs, instruction); |
426 | if (ret==0) { | 428 | if (ret==0) { |
427 | regs->pr = regs->pc + 4; | 429 | regs->pr = regs->pc + 4; |
428 | regs->pc = rm; | 430 | regs->pc = rm; |
@@ -449,7 +451,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
449 | case 0x0B00: /* bf lab - no delayslot*/ | 451 | case 0x0B00: /* bf lab - no delayslot*/ |
450 | break; | 452 | break; |
451 | case 0x0F00: /* bf/s lab */ | 453 | case 0x0F00: /* bf/s lab */ |
452 | ret = handle_unaligned_delayslot(regs); | 454 | ret = handle_unaligned_delayslot(regs, instruction); |
453 | if (ret==0) { | 455 | if (ret==0) { |
454 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) | 456 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) |
455 | if ((regs->sr & 0x00000001) != 0) | 457 | if ((regs->sr & 0x00000001) != 0) |
@@ -462,7 +464,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
462 | case 0x0900: /* bt lab - no delayslot */ | 464 | case 0x0900: /* bt lab - no delayslot */ |
463 | break; | 465 | break; |
464 | case 0x0D00: /* bt/s lab */ | 466 | case 0x0D00: /* bt/s lab */ |
465 | ret = handle_unaligned_delayslot(regs); | 467 | ret = handle_unaligned_delayslot(regs, instruction); |
466 | if (ret==0) { | 468 | if (ret==0) { |
467 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) | 469 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) |
468 | if ((regs->sr & 0x00000001) == 0) | 470 | if ((regs->sr & 0x00000001) == 0) |
@@ -476,13 +478,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
476 | break; | 478 | break; |
477 | 479 | ||
478 | case 0xA000: /* bra label */ | 480 | case 0xA000: /* bra label */ |
479 | ret = handle_unaligned_delayslot(regs); | 481 | ret = handle_unaligned_delayslot(regs, instruction); |
480 | if (ret==0) | 482 | if (ret==0) |
481 | regs->pc += SH_PC_12BIT_OFFSET(instruction); | 483 | regs->pc += SH_PC_12BIT_OFFSET(instruction); |
482 | break; | 484 | break; |
483 | 485 | ||
484 | case 0xB000: /* bsr label */ | 486 | case 0xB000: /* bsr label */ |
485 | ret = handle_unaligned_delayslot(regs); | 487 | ret = handle_unaligned_delayslot(regs, instruction); |
486 | if (ret==0) { | 488 | if (ret==0) { |
487 | regs->pr = regs->pc + 4; | 489 | regs->pr = regs->pc + 4; |
488 | regs->pc += SH_PC_12BIT_OFFSET(instruction); | 490 | regs->pc += SH_PC_12BIT_OFFSET(instruction); |
@@ -493,12 +495,11 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
493 | 495 | ||
494 | /* handle non-delay-slot instruction */ | 496 | /* handle non-delay-slot instruction */ |
495 | simple: | 497 | simple: |
496 | ret = handle_unaligned_ins(instruction,regs); | 498 | ret = handle_unaligned_ins(instruction, regs); |
497 | if (ret==0) | 499 | if (ret==0) |
498 | regs->pc += instruction_size(instruction); | 500 | regs->pc += instruction_size(instruction); |
499 | return ret; | 501 | return ret; |
500 | } | 502 | } |
501 | #endif /* CONFIG_CPU_SH2A */ | ||
502 | 503 | ||
503 | #ifdef CONFIG_CPU_HAS_SR_RB | 504 | #ifdef CONFIG_CPU_HAS_SR_RB |
504 | #define lookup_exception_vector(x) \ | 505 | #define lookup_exception_vector(x) \ |
@@ -526,10 +527,8 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
526 | unsigned long error_code = 0; | 527 | unsigned long error_code = 0; |
527 | mm_segment_t oldfs; | 528 | mm_segment_t oldfs; |
528 | siginfo_t info; | 529 | siginfo_t info; |
529 | #ifndef CONFIG_CPU_SH2A | 530 | opcode_t instruction; |
530 | u16 instruction; | ||
531 | int tmp; | 531 | int tmp; |
532 | #endif | ||
533 | 532 | ||
534 | /* Intentional ifdef */ | 533 | /* Intentional ifdef */ |
535 | #ifdef CONFIG_CPU_HAS_SR_RB | 534 | #ifdef CONFIG_CPU_HAS_SR_RB |
@@ -549,9 +548,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
549 | goto uspace_segv; | 548 | goto uspace_segv; |
550 | } | 549 | } |
551 | 550 | ||
552 | #ifndef CONFIG_CPU_SH2A | ||
553 | set_fs(USER_DS); | 551 | set_fs(USER_DS); |
554 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 552 | if (copy_from_user(&instruction, (void *)(regs->pc), |
553 | sizeof(instruction))) { | ||
555 | /* Argh. Fault on the instruction itself. | 554 | /* Argh. Fault on the instruction itself. |
556 | This should never happen non-SMP | 555 | This should never happen non-SMP |
557 | */ | 556 | */ |
@@ -564,8 +563,6 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
564 | 563 | ||
565 | if (tmp==0) | 564 | if (tmp==0) |
566 | return; /* sorted */ | 565 | return; /* sorted */ |
567 | #endif | ||
568 | |||
569 | uspace_segv: | 566 | uspace_segv: |
570 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " | 567 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
571 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, | 568 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, |
@@ -580,9 +577,9 @@ uspace_segv: | |||
580 | if (regs->pc & 1) | 577 | if (regs->pc & 1) |
581 | die("unaligned program counter", regs, error_code); | 578 | die("unaligned program counter", regs, error_code); |
582 | 579 | ||
583 | #ifndef CONFIG_CPU_SH2A | ||
584 | set_fs(KERNEL_DS); | 580 | set_fs(KERNEL_DS); |
585 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 581 | if (copy_from_user(&instruction, (void *)(regs->pc), |
582 | sizeof(instruction))) { | ||
586 | /* Argh. Fault on the instruction itself. | 583 | /* Argh. Fault on the instruction itself. |
587 | This should never happen non-SMP | 584 | This should never happen non-SMP |
588 | */ | 585 | */ |
@@ -592,12 +589,6 @@ uspace_segv: | |||
592 | 589 | ||
593 | handle_unaligned_access(instruction, regs); | 590 | handle_unaligned_access(instruction, regs); |
594 | set_fs(oldfs); | 591 | set_fs(oldfs); |
595 | #else | ||
596 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " | ||
597 | "access\n", current->comm); | ||
598 | |||
599 | force_sig(SIGSEGV, current); | ||
600 | #endif | ||
601 | } | 592 | } |
602 | } | 593 | } |
603 | 594 | ||