diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/entry.S | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/rtrap.S | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/signal.c | 64 | ||||
-rw-r--r-- | arch/sparc64/kernel/etrap.S | 7 | ||||
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 12 | ||||
-rw-r--r-- | arch/sparc64/kernel/rtrap.S | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal.c | 60 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal32.c | 26 |
9 files changed, 91 insertions, 96 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 57d1bbdd0bd2..4bcfe54f878d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1306,6 +1306,8 @@ ret_from_fork: .align 4 .globl linux_sparc_syscall linux_sparc_syscall: + sethi %hi(PSR_SYSCALL), %l4 + or %l0, %l4, %l0 /* Direct access to user regs, must faster. */ cmp %g1, NR_SYSCALLS bgeu linux_sparc_ni_syscall diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 60dfc65549db..81f3b929743f 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -170,8 +170,8 @@ static int genregs32_set(struct task_struct *target, switch (pos) { case 32: /* PSR */ psr = regs->psr; - psr &= ~PSR_ICC; - psr |= (reg & PSR_ICC); + psr &= ~(PSR_ICC | PSR_SYSCALL); + psr |= (reg & (PSR_ICC | PSR_SYSCALL)); regs->psr = psr; break; case 33: /* PC */ diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index 77ca6fd81253..b27b5b56f77a 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S @@ -50,8 +50,9 @@ rtrap_7win_patch5: and %g1, 0x7f, %g1 ret_trap_entry: ret_trap_lockless_ipi: andcc %t_psr, PSR_PS, %g0 + sethi %hi(PSR_SYSCALL), %g1 be 1f - nop + andn %t_psr, %g1, %t_psr wr %t_psr, 0x0, %psr b ret_trap_kernel @@ -73,7 +74,6 @@ signal_p: ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr mov %l5, %o1 - mov %l6, %o2 call do_signal add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr @@ -81,6 +81,8 @@ signal_p: ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr clr %l6 ret_trap_continue: + sethi %hi(PSR_SYSCALL), %g1 + andn %t_psr, %g1, %t_psr wr %t_psr, 0x0, %psr WRITE_PAUSE @@ -137,8 +139,9 @@ ret_trap_userwins_ok: LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) or %t_pc, %t_npc, %g2 andcc %g2, 0x3, %g0 + sethi %hi(PSR_SYCALL), %g2 be 1f - nop + andn %t_psr, %g2, %t_psr b ret_trap_unaligned_pc add %sp, STACKFRAME_SZ, %o0 @@ -201,6 +204,8 @@ rtrap_patch5: and %g1, 0xff, %g1 1: LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) 2: + sethi %hi(PSR_SYSCALL), %twin_tmp1 + andn %t_psr, %twin_tmp1, %t_psr wr %t_psr, 0x0, %psr WRITE_PAUSE diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 368157926d24..3fd1df9f9ba7 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -145,6 +145,9 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | (regs->psr & (PSR_ICC | PSR_EF)); + /* Prevent syscall restart. */ + pt_regs_clear_syscall(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -199,6 +202,9 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); + /* Prevent syscall restart. */ + pt_regs_clear_syscall(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -507,26 +513,36 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) +asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0) { - siginfo_t info; - struct sparc_deliver_cookie cookie; struct k_sigaction ka; - int signr; + int restart_syscall; sigset_t *oldset; + siginfo_t info; + int signr; - cookie.restart_syscall = restart_syscall; - cookie.orig_i0 = orig_i0; + if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) + restart_syscall = 1; + else + restart_syscall = 0; if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, &ka, regs, &cookie); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + + /* If the debugger messes with the program counter, it clears + * the software "in syscall" bit, directing us to not perform + * a syscall restart. + */ + if (restart_syscall && !pt_regs_is_syscall(regs)) + restart_syscall = 0; + if (signr > 0) { - if (cookie.restart_syscall) - syscall_restart(cookie.orig_i0, regs, &ka.sa); + if (restart_syscall) + syscall_restart(orig_i0, regs, &ka.sa); handle_signal(signr, &ka, &info, oldset, regs); /* a signal was successfully delivered; the saved @@ -538,16 +554,16 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest clear_thread_flag(TIF_RESTORE_SIGMASK); return; } - if (cookie.restart_syscall && + if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ - regs->u_regs[UREG_I0] = cookie.orig_i0; + regs->u_regs[UREG_I0] = orig_i0; regs->pc -= 4; regs->npc -= 4; } - if (cookie.restart_syscall && + if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->pc -= 4; @@ -599,27 +615,3 @@ do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, out: return ret; } - -void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) -{ - struct sparc_deliver_cookie *cp = cookie; - - if (cp->restart_syscall && - (regs->u_regs[UREG_I0] == ERESTARTNOHAND || - regs->u_regs[UREG_I0] == ERESTARTSYS || - regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { - /* replay the system call when we are done */ - regs->u_regs[UREG_I0] = cp->orig_i0; - regs->pc -= 4; - regs->npc -= 4; - cp->restart_syscall = 0; - } - - if (cp->restart_syscall && - regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { - regs->u_regs[UREG_G1] = __NR_restart_syscall; - regs->pc -= 4; - regs->npc -= 4; - cp->restart_syscall = 0; - } -} diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index b49d3b60bc0c..f25e1da3fd03 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -27,11 +27,12 @@ .text .align 64 - .globl etrap, etrap_irq, etraptl1 + .globl etrap_syscall, etrap, etrap_irq, etraptl1 etrap: rdpr %pil, %g2 -etrap_irq: - TRAP_LOAD_THREAD_REG(%g6, %g1) +etrap_irq: clr %g3 +etrap_syscall: TRAP_LOAD_THREAD_REG(%g6, %g1) rdpr %tstate, %g1 + or %g1, %g3, %g1 sllx %g2, 20, %g3 andcc %g1, TSTATE_PRIV, %g0 or %g1, %g3, %g1 diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index b803fe9b2c8d..f6c9fc92921d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -287,11 +287,11 @@ static int genregs64_set(struct task_struct *target, 32 * sizeof(u64), 33 * sizeof(u64)); if (!ret) { - /* Only the condition codes can be modified - * in the %tstate register. + /* Only the condition codes and the "in syscall" + * state can be modified in the %tstate register. */ - tstate &= (TSTATE_ICC | TSTATE_XCC); - regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); + regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); regs->tstate |= tstate; } } @@ -657,8 +657,10 @@ static int genregs32_set(struct task_struct *target, switch (pos) { case 32: /* PSR */ tstate = regs->tstate; - tstate &= ~(TSTATE_ICC | TSTATE_XCC); + tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); tstate |= psr_to_tstate_icc(reg); + if (reg & PSR_SYSCALL) + tstate |= TSTATE_SYSCALL; regs->tstate = tstate; break; case 33: /* PC */ diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index ecf6753b204a..b9b785fd8b46 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -257,6 +257,7 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 wr %o3, %g0, %y wrpr %l4, 0x0, %pil wrpr %g0, 0x1, %tl + andn %l1, TSTATE_SYSCALL, %l1 wrpr %l1, %g0, %tstate wrpr %l2, %g0, %tpc wrpr %o2, %g0, %tnpc diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 07c0443ea3f5..2378482c2aab 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -333,7 +333,7 @@ void do_rt_sigreturn(struct pt_regs *regs) regs->tnpc = tnpc; /* Prevent syscall restart. */ - pt_regs_clear_trap_type(regs); + pt_regs_clear_syscall(regs); sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); @@ -499,7 +499,7 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, - struct sigaction *sa) + struct sigaction *sa) { switch (regs->u_regs[UREG_I0]) { case ERESTART_RESTARTBLOCK: @@ -525,19 +525,17 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, */ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) { - struct signal_deliver_cookie cookie; struct k_sigaction ka; + int restart_syscall; sigset_t *oldset; siginfo_t info; int signr; if (pt_regs_is_syscall(regs) && (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { - pt_regs_clear_trap_type(regs); - cookie.restart_syscall = 1; + restart_syscall = 1; } else - cookie.restart_syscall = 0; - cookie.orig_i0 = orig_i0; + restart_syscall = 0; if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; @@ -547,16 +545,25 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { extern void do_signal32(sigset_t *, struct pt_regs *, - struct signal_deliver_cookie *); - do_signal32(oldset, regs, &cookie); + int restart_syscall, + unsigned long orig_i0); + do_signal32(oldset, regs, restart_syscall, orig_i0); return; } #endif - signr = get_signal_to_deliver(&info, &ka, regs, &cookie); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + + /* If the debugger messes with the program counter, it clears + * the software "in syscall" bit, directing us to not perform + * a syscall restart. + */ + if (restart_syscall && !pt_regs_is_syscall(regs)) + restart_syscall = 0; + if (signr > 0) { - if (cookie.restart_syscall) - syscall_restart(cookie.orig_i0, regs, &ka.sa); + if (restart_syscall) + syscall_restart(orig_i0, regs, &ka.sa); handle_signal(signr, &ka, &info, oldset, regs); /* a signal was successfully delivered; the saved @@ -568,16 +575,16 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) clear_thread_flag(TIF_RESTORE_SIGMASK); return; } - if (cookie.restart_syscall && + if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ - regs->u_regs[UREG_I0] = cookie.orig_i0; + regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; } - if (cookie.restart_syscall && + if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->tpc -= 4; @@ -598,26 +605,3 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs, orig_i0); } - -void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) -{ - struct signal_deliver_cookie *cp = cookie; - - if (cp->restart_syscall && - (regs->u_regs[UREG_I0] == ERESTARTNOHAND || - regs->u_regs[UREG_I0] == ERESTARTSYS || - regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { - /* replay the system call when we are done */ - regs->u_regs[UREG_I0] = cp->orig_i0; - regs->tpc -= 4; - regs->tnpc -= 4; - cp->restart_syscall = 0; - } - if (cp->restart_syscall && - regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { - regs->u_regs[UREG_G1] = __NR_restart_syscall; - regs->tpc -= 4; - regs->tnpc -= 4; - cp->restart_syscall = 0; - } -} diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 0f6b7b156efd..3f19e9af3d1b 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -269,7 +269,7 @@ void do_sigreturn32(struct pt_regs *regs) regs->tstate |= psr_to_tstate_icc(psr); /* Prevent syscall restart. */ - pt_regs_clear_trap_type(regs); + pt_regs_clear_syscall(regs); err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -355,7 +355,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) regs->tstate |= psr_to_tstate_icc(psr); /* Prevent syscall restart. */ - pt_regs_clear_trap_type(regs); + pt_regs_clear_syscall(regs); err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -768,16 +768,24 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs * mistake. */ void do_signal32(sigset_t *oldset, struct pt_regs * regs, - struct signal_deliver_cookie *cookie) + int restart_syscall, unsigned long orig_i0) { struct k_sigaction ka; siginfo_t info; int signr; - signr = get_signal_to_deliver(&info, &ka, regs, cookie); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + + /* If the debugger messes with the program counter, it clears + * the "in syscall" bit, directing us to not perform a syscall + * restart. + */ + if (restart_syscall && !pt_regs_is_syscall(regs)) + restart_syscall = 0; + if (signr > 0) { - if (cookie->restart_syscall) - syscall_restart32(cookie->orig_i0, regs, &ka.sa); + if (restart_syscall) + syscall_restart32(orig_i0, regs, &ka.sa); handle_signal32(signr, &ka, &info, oldset, regs); /* a signal was successfully delivered; the saved @@ -789,16 +797,16 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, clear_thread_flag(TIF_RESTORE_SIGMASK); return; } - if (cookie->restart_syscall && + if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ - regs->u_regs[UREG_I0] = cookie->orig_i0; + regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; } - if (cookie->restart_syscall && + if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->tpc -= 4; |