diff options
| -rw-r--r-- | arch/arm/kernel/signal.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a0cd0a90a10d..e9fe78033361 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -665,17 +665,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
| 665 | if (syscall) { | 665 | if (syscall) { |
| 666 | if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { | 666 | if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { |
| 667 | if (thumb_mode(regs)) { | 667 | if (thumb_mode(regs)) { |
| 668 | regs->ARM_r7 = __NR_restart_syscall; | 668 | regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; |
| 669 | regs->ARM_pc -= 2; | 669 | regs->ARM_pc -= 2; |
| 670 | } else { | 670 | } else { |
| 671 | #if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) | ||
| 672 | regs->ARM_r7 = __NR_restart_syscall; | ||
| 673 | regs->ARM_pc -= 4; | ||
| 674 | #else | ||
| 671 | u32 __user *usp; | 675 | u32 __user *usp; |
| 676 | u32 swival = __NR_restart_syscall; | ||
| 672 | 677 | ||
| 673 | regs->ARM_sp -= 12; | 678 | regs->ARM_sp -= 12; |
| 674 | usp = (u32 __user *)regs->ARM_sp; | 679 | usp = (u32 __user *)regs->ARM_sp; |
| 675 | 680 | ||
| 681 | /* | ||
| 682 | * Either we supports OABI only, or we have | ||
| 683 | * EABI with the OABI compat layer enabled. | ||
| 684 | * In the later case we don't know if user | ||
| 685 | * space is EABI or not, and if not we must | ||
| 686 | * not clobber r7. Always using the OABI | ||
| 687 | * syscall solves that issue and works for | ||
| 688 | * all those cases. | ||
| 689 | */ | ||
| 690 | swival = swival - __NR_SYSCAll_BASE + __NR_OABI_SYSCALL_BASE; | ||
| 691 | |||
| 676 | put_user(regs->ARM_pc, &usp[0]); | 692 | put_user(regs->ARM_pc, &usp[0]); |
| 677 | /* swi __NR_restart_syscall */ | 693 | /* swi __NR_restart_syscall */ |
| 678 | put_user(0xef000000 | __NR_restart_syscall, &usp[1]); | 694 | put_user(0xef000000 | swival, &usp[1]); |
| 679 | /* ldr pc, [sp], #12 */ | 695 | /* ldr pc, [sp], #12 */ |
| 680 | put_user(0xe49df00c, &usp[2]); | 696 | put_user(0xe49df00c, &usp[2]); |
| 681 | 697 | ||
| @@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
| 683 | (unsigned long)(usp + 3)); | 699 | (unsigned long)(usp + 3)); |
| 684 | 700 | ||
| 685 | regs->ARM_pc = regs->ARM_sp + 4; | 701 | regs->ARM_pc = regs->ARM_sp + 4; |
| 702 | #endif | ||
| 686 | } | 703 | } |
| 687 | } | 704 | } |
| 688 | if (regs->ARM_r0 == -ERESTARTNOHAND || | 705 | if (regs->ARM_r0 == -ERESTARTNOHAND || |
