aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/entry.S2
-rw-r--r--arch/sparc/kernel/ptrace.c4
-rw-r--r--arch/sparc/kernel/rtrap.S11
-rw-r--r--arch/sparc/kernel/signal.c64
4 files changed, 40 insertions, 41 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 57d1bbdd0bd..4bcfe54f878 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 60dfc65549d..81f3b929743 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 77ca6fd8125..b27b5b56f77 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 368157926d2..3fd1df9f9ba 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 = &current->saved_sigmask;
else
oldset = &current->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;
- }
-}