[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 (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)
|
||||||
(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 ||
|
||||||
|
|
Loading…
Reference in New Issue