From ad82cc08f70486b5741560b1b2121dadf82897de Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 19 Jul 2012 17:46:44 +0100 Subject: ARM: 7470/1: Revert "7443/1: Revert "new way of handling ERESTART_RESTARTBLOCK"" This reverts commit 433e2f307beff8adba241646ce9108544e0c5a03. Conflicts: arch/arm/kernel/ptrace.c Reintroduce the new syscall restart handling in preparation for further patches from Al Viro. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/ptrace.c | 8 +++++++- arch/arm/kernel/signal.c | 33 ++++++--------------------------- 2 files changed, 13 insertions(+), 28 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index dab711e..efd25d6 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -940,7 +941,12 @@ static int ptrace_syscall_trace(struct pt_regs *regs, int scno, asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) { - int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER); + int ret; + + if (test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS)) + scno = __NR_restart_syscall - __NR_SYSCALL_BASE; + + ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER); audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); return ret; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 536c5d6..6d3bce5 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -605,12 +605,10 @@ static void do_signal(struct pt_regs *regs, int syscall) case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: + case -ERESTART_RESTARTBLOCK: regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc = restart_addr; break; - case -ERESTART_RESTARTBLOCK: - regs->ARM_r0 = -EINTR; - break; } } @@ -626,12 +624,14 @@ static void do_signal(struct pt_regs *regs, int syscall) * debugger has chosen to restart at a different PC. */ if (regs->ARM_pc == restart_addr) { - if (retval == -ERESTARTNOHAND + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK || (retval == -ERESTARTSYS && !(ka.sa.sa_flags & SA_RESTART))) { regs->ARM_r0 = -EINTR; regs->ARM_pc = continue_addr; } + clear_thread_flag(TIF_SYSCALL_RESTARTSYS); } handle_signal(signr, &ka, &info, regs); @@ -645,29 +645,8 @@ static void do_signal(struct pt_regs *regs, int syscall) * ignore the restart. */ if (retval == -ERESTART_RESTARTBLOCK - && regs->ARM_pc == continue_addr) { - if (thumb_mode(regs)) { - 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; - - regs->ARM_sp -= 4; - usp = (u32 __user *)regs->ARM_sp; - - if (put_user(regs->ARM_pc, usp) == 0) { - regs->ARM_pc = KERN_RESTART_CODE; - } else { - regs->ARM_sp += 4; - force_sigsegv(0, current); - } -#endif - } - } + && regs->ARM_pc == restart_addr) + set_thread_flag(TIF_SYSCALL_RESTARTSYS); } restore_saved_sigmask(); -- cgit v1.1 From 8d4150ccbb63419649a69fe04b46120a46d60da2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 19 Jul 2012 17:47:22 +0100 Subject: ARM: 7471/1: Revert "7442/1: Revert "remove unused restart trampoline"" This reverts commit 3b0c06226783ffc836217eb34f7eca311b1e63f7. We no longer require the restart trampoline for syscall restarting. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 13 ------------- arch/arm/kernel/signal.h | 2 -- arch/arm/kernel/traps.c | 2 -- 3 files changed, 17 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 6d3bce5..fd2392a 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -27,7 +27,6 @@ */ #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) -#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE) /* * With EABI, the syscall number has to be loaded into r7. @@ -48,18 +47,6 @@ const unsigned long sigreturn_codes[7] = { }; /* - * Either we support 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. - */ -const unsigned long syscall_restart_code[2] = { - SWI_SYS_RESTART, /* swi __NR_restart_syscall */ - 0xe49df004, /* ldr pc, [sp], #4 */ -}; - -/* * atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h index 6fcfe83..5ff067b7 100644 --- a/arch/arm/kernel/signal.h +++ b/arch/arm/kernel/signal.h @@ -8,7 +8,5 @@ * published by the Free Software Foundation. */ #define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) -#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) extern const unsigned long sigreturn_codes[7]; -extern const unsigned long syscall_restart_code[2]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3647170..4928d89 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -820,8 +820,6 @@ void __init early_trap_init(void *vectors_base) */ memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), sigreturn_codes, sizeof(sigreturn_codes)); - memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), - syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); -- cgit v1.1 From 0a267fa6a15d41c4061358bf2e67c633fdbffc90 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Jul 2012 17:47:55 +0100 Subject: ARM: 7472/1: pull all work_pending logics into C function Signed-off-by: Al Viro Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 17 ++--------------- arch/arm/kernel/signal.c | 27 +++++++++++++++++++-------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 49d9f93..1873f65 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -51,23 +51,10 @@ ret_fast_syscall: fast_work_pending: str r0, [sp, #S_R0+S_OFF]! @ returned r0 work_pending: - tst r1, #_TIF_NEED_RESCHED - bne work_resched - /* - * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here - */ - ldr r2, [sp, #S_PSR] mov r0, sp @ 'regs' - tst r2, #15 @ are we returning to user mode? - bne no_work_pending @ no? just leave, then... mov r2, why @ 'syscall' - tst r1, #_TIF_SIGPENDING @ delivering a signal? - movne why, #0 @ prevent further restarts - bl do_notify_resume - b ret_slow_syscall @ Check work again - -work_resched: - bl schedule + bl do_work_pending + b no_work_pending /* * "slow" syscall return path. "why" tells us if this was a real syscall. */ diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index fd2392a..8756e5d 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -640,13 +640,24 @@ static void do_signal(struct pt_regs *regs, int syscall) } asmlinkage void -do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) +do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (thread_flags & _TIF_SIGPENDING) - do_signal(regs, syscall); - - if (thread_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + do_signal(regs, syscall); + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); } -- cgit v1.1 From 81783786d5cf4aa0d3e15bb0fac856aa8ebf1a76 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Jul 2012 17:48:21 +0100 Subject: ARM: 7473/1: deal with handlerless restarts without leaving the kernel Signed-off-by: Al Viro Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 7 +++++- arch/arm/kernel/signal.c | 50 ++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 22 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 1873f65..8ae58c47 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -54,7 +54,11 @@ work_pending: mov r0, sp @ 'regs' mov r2, why @ 'syscall' bl do_work_pending - b no_work_pending + tst r0, #1 + beq no_work_pending + ldmia sp, {r0 - r6} @ have to reload r0 - r6 + b local_restart @ ... and off we go + /* * "slow" syscall return path. "why" tells us if this was a real syscall. */ @@ -396,6 +400,7 @@ ENTRY(vector_swi) eor scno, scno, #__NR_SYSCALL_BASE @ check OS number #endif +local_restart: ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing stmdb sp!, {r4, r5} @ push fifth and sixth args diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 8756e5d..99851cb 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -569,12 +569,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -static void do_signal(struct pt_regs *regs, int syscall) +static int do_signal(struct pt_regs *regs, int syscall) { unsigned int retval = 0, continue_addr = 0, restart_addr = 0; struct k_sigaction ka; siginfo_t info; int signr; + int restart = 0; /* * If we were from a system call, check for system call restarting... @@ -589,10 +590,12 @@ static void do_signal(struct pt_regs *regs, int syscall) * debugger will see the already changed PSW. */ switch (retval) { + case -ERESTART_RESTARTBLOCK: + restart++; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - case -ERESTART_RESTARTBLOCK: + restart++; regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc = restart_addr; break; @@ -604,13 +607,15 @@ static void do_signal(struct pt_regs *regs, int syscall) * point the debugger may change all our registers ... */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); + /* + * Depending on the signal settings we may need to revert the + * decision to restart the system call. But skip this if a + * debugger has chosen to restart at a different PC. + */ + if (regs->ARM_pc != restart_addr) + restart = 0; if (signr > 0) { - /* - * Depending on the signal settings we may need to revert the - * decision to restart the system call. But skip this if a - * debugger has chosen to restart at a different PC. - */ - if (regs->ARM_pc == restart_addr) { + if (unlikely(restart)) { if (retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK || (retval == -ERESTARTSYS @@ -618,28 +623,23 @@ static void do_signal(struct pt_regs *regs, int syscall) regs->ARM_r0 = -EINTR; regs->ARM_pc = continue_addr; } - clear_thread_flag(TIF_SYSCALL_RESTARTSYS); } handle_signal(signr, &ka, &info, regs); - return; + return 0; } - if (syscall) { - /* - * Handle restarting a different system call. As above, - * if a debugger has chosen to restart at a different PC, - * ignore the restart. - */ - if (retval == -ERESTART_RESTARTBLOCK - && regs->ARM_pc == restart_addr) + if (unlikely(restart)) { + if (restart > 1) set_thread_flag(TIF_SYSCALL_RESTARTSYS); + regs->ARM_pc = continue_addr; } restore_saved_sigmask(); + return restart; } -asmlinkage void +asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { do { @@ -647,10 +647,17 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) schedule(); } else { if (unlikely(!user_mode(regs))) - return; + return 0; local_irq_enable(); if (thread_flags & _TIF_SIGPENDING) { - do_signal(regs, syscall); + if (unlikely(do_signal(regs, syscall))) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return 1; + } syscall = 0; } else { clear_thread_flag(TIF_NOTIFY_RESUME); @@ -660,4 +667,5 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) local_irq_disable(); thread_flags = current_thread_info()->flags; } while (thread_flags & _TIF_WORK_MASK); + return 0; } -- cgit v1.1 From 6628521784d1da3b7354c6b6e8499e19ab46a3d1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Jul 2012 17:48:50 +0100 Subject: ARM: 7474/1: get rid of TIF_SYSCALL_RESTARTSYS just let do_work_pending() return 1 on normal local restarts and -1 on those that had been caused by ERESTART_RESTARTBLOCK (and 0 is still "all done, sod off to userland now"). And let the asm glue flip scno to restart_syscall(2) one if it got negative from us... [will: resolved conflicts with audit fixes] Signed-off-by: Al Viro Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 3 ++- arch/arm/kernel/ptrace.c | 7 +------ arch/arm/kernel/signal.c | 15 ++++++--------- 3 files changed, 9 insertions(+), 16 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 8ae58c47..2909bbca 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -54,8 +54,9 @@ work_pending: mov r0, sp @ 'regs' mov r2, why @ 'syscall' bl do_work_pending - tst r0, #1 + cmp r0, #0 beq no_work_pending + movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE) ldmia sp, {r0 - r6} @ have to reload r0 - r6 b local_restart @ ... and off we go diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index efd25d6..3e0fc5f 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -941,12 +941,7 @@ static int ptrace_syscall_trace(struct pt_regs *regs, int scno, asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) { - int ret; - - if (test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS)) - scno = __NR_restart_syscall - __NR_SYSCALL_BASE; - - ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER); + int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER); audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); return ret; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 99851cb..f27789e 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -591,7 +591,7 @@ static int do_signal(struct pt_regs *regs, int syscall) */ switch (retval) { case -ERESTART_RESTARTBLOCK: - restart++; + restart -= 2; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: @@ -629,13 +629,9 @@ static int do_signal(struct pt_regs *regs, int syscall) return 0; } - if (unlikely(restart)) { - if (restart > 1) - set_thread_flag(TIF_SYSCALL_RESTARTSYS); - regs->ARM_pc = continue_addr; - } - restore_saved_sigmask(); + if (unlikely(restart)) + regs->ARM_pc = continue_addr; return restart; } @@ -650,13 +646,14 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) return 0; local_irq_enable(); if (thread_flags & _TIF_SIGPENDING) { - if (unlikely(do_signal(regs, syscall))) { + int restart = do_signal(regs, syscall); + if (unlikely(restart)) { /* * Restart without handlers. * Deal with it without leaving * the kernel space. */ - return 1; + return restart; } syscall = 0; } else { -- cgit v1.1 From c7aa00db074e4961b49277d7d0fc2f5367d914ca Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 19 Jul 2012 17:49:22 +0100 Subject: ARM: 7475/1: sys_trace: allow all syscall arguments to be updated via ptrace Prior to syscall invocation, __sys_trace only reloads r0-r3 from the kernel stack, preventing the debugger from updating arguments 5-7 when signalled via ptrace. This patch updates the code to reload r0-r6, updating arguments 5 and 6 on the stack (argument 7 is only used by OABI indirect syscalls and can remain in a register). Reported-by: Al Viro Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 2909bbca..978eac5 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -443,7 +443,8 @@ __sys_trace: mov scno, r0 @ syscall number (possibly new) add r1, sp, #S_R0 + S_OFF @ pointer to regs cmp scno, #NR_syscalls @ check upper syscall limit - ldmccia r1, {r0 - r3} @ have to reload r0 - r3 + ldmccia r1, {r0 - r6} @ have to reload r0 - r6 + stmccia sp, {r4, r5} @ and update the stack args ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine b 2b -- cgit v1.1