diff options
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r-- | arch/sparc64/kernel/etrap.S | 7 | ||||
-rw-r--r-- | arch/sparc64/kernel/init_task.c | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 16 | ||||
-rw-r--r-- | arch/sparc64/kernel/rtrap.S | 7 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal.c | 81 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal32.c | 39 | ||||
-rw-r--r-- | arch/sparc64/kernel/sys_sparc.c | 36 | ||||
-rw-r--r-- | arch/sparc64/kernel/sys_sparc32.c | 33 |
8 files changed, 81 insertions, 139 deletions
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index b49d3b60bc0..f25e1da3fd0 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/init_task.c b/arch/sparc64/kernel/init_task.c index 90007cf88ba..d2b312381c1 100644 --- a/arch/sparc64/kernel/init_task.c +++ b/arch/sparc64/kernel/init_task.c @@ -10,7 +10,6 @@ #include <asm/processor.h> static struct fs_struct init_fs = INIT_FS; -static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index e9fc0aa2da3..f6c9fc92921 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 */ @@ -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; } @@ -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; } diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index ecf6753b204..16689b2930d 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -46,7 +46,7 @@ __handle_user_windows: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 +1: andcc %l0, _TIF_SIGPENDING, %g0 be,pt %xcc, __handle_user_windows_continue nop mov %l5, %o1 @@ -86,7 +86,7 @@ __handle_perfctrs: wrpr %g0, RTRAP_PSTATE, %pstate wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 +1: andcc %l0, _TIF_SIGPENDING, %g0 be,pt %xcc, __handle_perfctrs_continue sethi %hi(TSTATE_PEF), %o0 @@ -195,7 +195,7 @@ __handle_preemption_continue: andcc %l1, %o0, %g0 andcc %l0, _TIF_NEED_RESCHED, %g0 bne,pn %xcc, __handle_preemption - andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 + andcc %l0, _TIF_SIGPENDING, %g0 bne,pn %xcc, __handle_signal __handle_signal_continue: ldub [%g6 + TI_WSAVED], %o2 @@ -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 07c0443ea3f..6e4dc67d16a 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -247,7 +247,9 @@ static long _sigpause_common(old_sigset_t set) current->state = TASK_INTERRUPTIBLE; schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); + + set_restore_sigmask(); + return -ERESTARTNOHAND; } @@ -333,7 +335,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 +501,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,21 +527,19 @@ 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)) + if (current_thread_info()->status & TS_RESTORE_SIGMASK) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; @@ -547,77 +547,62 @@ 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 + /* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag. + * clear the TS_RESTORE_SIGMASK flag. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); + current_thread_info()->status &= ~TS_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; regs->tnpc -= 4; } - /* if there's no signal to deliver, we just put the saved sigmask + /* If there's no signal to deliver, we just put the saved sigmask * back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) { - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + if (thread_info_flags & _TIF_SIGPENDING) 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 0f6b7b156ef..97cdd1bf4a1 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,48 +768,55 @@ 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 + /* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag. + * clear the TS_RESTORE_SIGMASK flag. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); + current_thread_info()->status &= ~TS_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; regs->tnpc -= 4; } - /* if there's no signal to deliver, we just put the saved sigmask + /* If there's no signal to deliver, we just put the saved sigmask * back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 0dbc941f130..ac1bff58c1a 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -542,8 +542,7 @@ asmlinkage long sparc64_personality(unsigned long personality) return ret; } -int sparc64_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags) +int sparc64_mmap_check(unsigned long addr, unsigned long len) { if (test_thread_flag(TIF_32BIT)) { if (len >= STACK_TOP32) @@ -609,46 +608,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; if (test_thread_flag(TIF_32BIT)) goto out; if (unlikely(new_len >= VA_EXCLUDE_START)) goto out; - if (unlikely(invalid_64bit_range(addr, old_len))) + if (unlikely(sparc64_mmap_check(addr, old_len))) + goto out; + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (invalid_64bit_range(new_addr, new_len)) - goto out_sem; - } else if (invalid_64bit_range(addr, new_len)) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: return ret; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 1aa4288125f..ba5bd626b39 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -867,44 +867,15 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, u32 __new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long new_addr = __new_addr; - if (old_len > STACK_TOP32 || new_len > STACK_TOP32) + if (unlikely(sparc64_mmap_check(addr, old_len))) goto out; - if (addr > STACK_TOP32 - old_len) + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (new_addr > STACK_TOP32 - new_len) - goto out_sem; - } else if (addr > STACK_TOP32 - new_len) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: return ret; |