Commit f606a6ff authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Russell King

[ARM] 3626/1: ARM EABI: fix syscall restarting

Patch from Nicolas Pitre

The RESTARTBLOCK case currently store some code on the stack to invoke
sys_restart_syscall.  However this is ABI dependent and there is a
mismatch with the way __NR_restart_syscall gets defined when the kernel
is compiled for EABI.

There is also a long standing bug in the thumb case since with OABI the
__NR_restart_syscall value includes __NR_SYSCALL_BASE which should not
be the case for Thumb syscalls.

Credits to Yauheni Kaliuta <yauheni.kaliuta@gmail.com> for finding the
EABI bug.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 92b7eb8f
...@@ -665,17 +665,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) ...@@ -665,17 +665,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (syscall) { if (syscall) {
if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
if (thumb_mode(regs)) { if (thumb_mode(regs)) {
regs->ARM_r7 = __NR_restart_syscall; regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
regs->ARM_pc -= 2; regs->ARM_pc -= 2;
} else { } else {
#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
regs->ARM_r7 = __NR_restart_syscall;
regs->ARM_pc -= 4;
#else
u32 __user *usp; u32 __user *usp;
u32 swival = __NR_restart_syscall;
regs->ARM_sp -= 12; regs->ARM_sp -= 12;
usp = (u32 __user *)regs->ARM_sp; usp = (u32 __user *)regs->ARM_sp;
/*
* Either we supports OABI only, or we have
* EABI with the OABI compat layer enabled.
* In the later case we don't know if user
* space is EABI or not, and if not we must
* not clobber r7. Always using the OABI
* syscall solves that issue and works for
* all those cases.
*/
swival = swival - __NR_SYSCAll_BASE + __NR_OABI_SYSCALL_BASE;
put_user(regs->ARM_pc, &usp[0]); put_user(regs->ARM_pc, &usp[0]);
/* swi __NR_restart_syscall */ /* swi __NR_restart_syscall */
put_user(0xef000000 | __NR_restart_syscall, &usp[1]); put_user(0xef000000 | swival, &usp[1]);
/* ldr pc, [sp], #12 */ /* ldr pc, [sp], #12 */
put_user(0xe49df00c, &usp[2]); put_user(0xe49df00c, &usp[2]);
...@@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) ...@@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
(unsigned long)(usp + 3)); (unsigned long)(usp + 3));
regs->ARM_pc = regs->ARM_sp + 4; regs->ARM_pc = regs->ARM_sp + 4;
#endif
} }
} }
if (regs->ARM_r0 == -ERESTARTNOHAND || if (regs->ARM_r0 == -ERESTARTNOHAND ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment