Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
Browse files Browse the repository at this point in the history
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  sparc: Fix debugger syscall restart interactions.
  sparc: Fix ptrace() detach.
  sparc32: Don't twiddle PT_DTRACE in exec.
  sparc video: remove open boot prom code
  • Loading branch information
Linus Torvalds committed May 11, 2008
2 parents 633331f + 28e6103 commit 854a989
Show file tree
Hide file tree
Showing 30 changed files with 149 additions and 159 deletions.
2 changes: 2 additions & 0 deletions arch/sparc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions arch/sparc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,11 +638,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
(char __user * __user *)regs->u_regs[base + UREG_I2],
regs);
putname(filename);
if (error == 0) {
task_lock(current);
current->ptrace &= ~PT_DTRACE;
task_unlock(current);
}
out:
return error;
}
Expand Down
6 changes: 4 additions & 2 deletions arch/sparc/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -441,6 +441,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;

default:
if (request == PTRACE_SPARC_DETACH)
request = PTRACE_DETACH;
ret = ptrace_request(child, request, addr, data);
break;
}
Expand Down
11 changes: 8 additions & 3 deletions arch/sparc/kernel/rtrap.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -73,14 +74,15 @@ 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

/* Fall through. */
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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
64 changes: 28 additions & 36 deletions arch/sparc/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}
7 changes: 4 additions & 3 deletions arch/sparc64/kernel/etrap.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 11 additions & 5 deletions arch/sparc64/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -944,6 +946,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;

default:
if (request == PTRACE_SPARC_DETACH)
request = PTRACE_DETACH;
ret = compat_ptrace_request(child, request, addr, data);
break;
}
Expand Down Expand Up @@ -1036,6 +1040,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;

default:
if (request == PTRACE_SPARC_DETACH)
request = PTRACE_DETACH;
ret = ptrace_request(child, request, addr, data);
break;
}
Expand Down
1 change: 1 addition & 0 deletions arch/sparc64/kernel/rtrap.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 22 additions & 38 deletions arch/sparc64/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&current->sighand->siglock);
Expand Down Expand Up @@ -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:
Expand All @@ -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 = &current->saved_sigmask;
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
}
}
Loading

0 comments on commit 854a989

Please sign in to comment.