[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: Nicolas Pitre <nico@cam.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
92b7eb8ffc
commit
f606a6ff22
|
@ -665,17 +665,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|||
if (syscall) {
|
||||
if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
|
||||
if (thumb_mode(regs)) {
|
||||
regs->ARM_r7 = __NR_restart_syscall;
|
||||
regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
|
||||
regs->ARM_pc -= 2;
|
||||
} else {
|
||||
#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
|
||||
regs->ARM_r7 = __NR_restart_syscall;
|
||||
regs->ARM_pc -= 4;
|
||||
#else
|
||||
u32 __user *usp;
|
||||
u32 swival = __NR_restart_syscall;
|
||||
|
||||
regs->ARM_sp -= 12;
|
||||
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]);
|
||||
/* swi __NR_restart_syscall */
|
||||
put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
|
||||
put_user(0xef000000 | swival, &usp[1]);
|
||||
/* ldr pc, [sp], #12 */
|
||||
put_user(0xe49df00c, &usp[2]);
|
||||
|
||||
|
@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|||
(unsigned long)(usp + 3));
|
||||
|
||||
regs->ARM_pc = regs->ARM_sp + 4;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (regs->ARM_r0 == -ERESTARTNOHAND ||
|
||||
|
|
Loading…
Reference in New Issue