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 | 67 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal32.c | 30 |
9 files changed, 101 insertions, 97 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index c2eed8f71516..1ea92e7391cb 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1398,6 +1398,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..ab818cdc4cc0 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_SYSCALL), %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 c80a232db6dd..e85023bb8e50 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -178,6 +178,9 @@ static inline void do_new_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) @@ -299,6 +302,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) @@ -1008,13 +1014,13 @@ 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; /* * XXX Disable svr4 signal handling until solaris emulation works. @@ -1027,18 +1033,28 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest int svr4_signal = current->personality == PER_SVR4; #endif - 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, svr4_signal); /* a signal was successfully delivered; the saved @@ -1050,16 +1066,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; @@ -1111,27 +1127,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 4b2bf9eb447a..b087e977bc5a 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 079d18a11d24..5bfa79dcdd3f 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -270,6 +270,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 01b6f1821e34..ec016cb71971 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -336,6 +336,9 @@ void do_rt_sigreturn(struct pt_regs *regs) regs->tpc = tpc; regs->tnpc = tnpc; + /* Prevent syscall restart. */ + pt_regs_clear_syscall(regs); + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; @@ -500,7 +503,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: @@ -524,16 +527,19 @@ 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. */ -static void do_signal(struct pt_regs *regs, unsigned long orig_i0, int restart_syscall) +static void do_signal(struct pt_regs *regs, unsigned long orig_i0, int __ignored) { - siginfo_t info; - struct signal_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->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { + restart_syscall = 1; + } else + restart_syscall = 0; if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; @@ -543,16 +549,24 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0, int restart_s #ifdef CONFIG_SPARC32_COMPAT if (test_thread_flag(TIF_32BIT)) { extern void do_signal32(sigset_t *, struct pt_regs *, - unsigned long, int); - do_signal32(oldset, regs, orig_i0, - cookie.restart_syscall); + 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) + if (restart_syscall) syscall_restart(orig_i0, regs, &ka.sa); handle_signal(signr, &ka, &info, oldset, regs); @@ -565,16 +579,16 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0, int restart_s 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; @@ -596,26 +610,3 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, int restart_s if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs, orig_i0, restart_syscall); } - -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 c55b67c614b9..c1b06e2e5806 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -295,6 +295,9 @@ void do_new_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); + /* Prevent syscall restart. */ + pt_regs_clear_syscall(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) err |= restore_fpu_state32(regs, &sf->fpu_state); @@ -448,6 +451,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); + /* Prevent syscall restart. */ + pt_regs_clear_syscall(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) err |= restore_fpu_state32(regs, &sf->fpu_state); @@ -1280,20 +1286,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, - unsigned long orig_i0, int restart_syscall) + int restart_syscall, unsigned long orig_i0) { - siginfo_t info; - struct signal_deliver_cookie cookie; struct k_sigaction ka; + siginfo_t info; int signr; int svr4_signal = current->personality == PER_SVR4; - cookie.restart_syscall = restart_syscall; - cookie.orig_i0 = orig_i0; + 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; - signr = get_signal_to_deliver(&info, &ka, regs, &cookie); if (signr > 0) { - if (cookie.restart_syscall) + if (restart_syscall) syscall_restart32(orig_i0, regs, &ka.sa); handle_signal32(signr, &ka, &info, oldset, regs, svr4_signal); @@ -1307,16 +1317,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; |