X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fsignal32.c;h=490af3b634a4689ad3aef787939e0f63d0cb577f;hb=refs%2Fheads%2Fvserver;hp=63d9cec39754b4ddb2c9e59af788610faf29863d;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 63d9cec39..490af3b63 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -20,21 +20,20 @@ #include #include #include +#include +#include #include -#include #include #include #include #include #include #include +#include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -int do_signal32(sigset_t *oldset, struct pt_regs *regs, - unsigned long orig_o0, int ret_from_syscall); - /* Signal frames: the original one (compatible with SunOS): * * Set up a signal frame... Make the stack look the way SunOS @@ -86,7 +85,7 @@ struct new_signal_frame32 { __siginfo_fpu_t fpu_state; }; -struct siginfo32 { +typedef struct compat_siginfo{ int si_signo; int si_errno; int si_code; @@ -102,9 +101,9 @@ struct siginfo32 { /* POSIX.1b timers */ struct { - timer_t _tid; /* timer id */ + compat_timer_t _tid; /* timer id */ int _overrun; /* overrun count */ - sigval_t32 _sigval; /* same as below */ + compat_sigval_t _sigval; /* same as below */ int _sys_private; /* not to be passed to user */ } _timer; @@ -112,7 +111,7 @@ struct siginfo32 { struct { compat_pid_t _pid; /* sender's pid */ unsigned int _uid; /* sender's uid */ - sigval_t32 _sigval; + compat_sigval_t _sigval; } _rt; /* SIGCHLD */ @@ -136,11 +135,11 @@ struct siginfo32 { int _fd; } _sigpoll; } _sifields; -}; +}compat_siginfo_t; struct rt_signal_frame32 { struct sparc_stackf32 ss; - struct siginfo32 info; + compat_siginfo_t info; struct pt_regs32 regs; compat_sigset_t mask; /* __siginfo_fpu32_t * */ u32 fpu_save; @@ -157,11 +156,11 @@ struct rt_signal_frame32 { #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) -int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; - if (!access_ok(VERIFY_WRITE, to, sizeof(struct siginfo32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -192,9 +191,12 @@ int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - case __SI_POLL >> 16: err |= __put_user(from->si_trapno, &to->si_trapno); - err |= __put_user((long)from->si_addr, &to->si_addr); + err |= __put_user((unsigned long)from->si_addr, &to->si_addr); + break; + case __SI_POLL >> 16: + err |= __put_user(from->si_band, &to->si_band); + err |= __put_user(from->si_fd, &to->si_fd); break; case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: @@ -210,9 +212,9 @@ int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) /* CAUTION: This is just a very minimalist implementation for the * sake of compat_sys_rt_sigqueueinfo() */ -int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from) +int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - if (!access_ok(VERIFY_WRITE, from, sizeof(struct siginfo32))) + if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t))) return -EFAULT; if (copy_from_user(to, from, 3*sizeof(int)) || @@ -223,102 +225,6 @@ int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from) return 0; } -/* - * atomically swap in the new signal mask, and wait for a signal. - * This is really tricky on the Sparc, watch out... - */ -asmlinkage void _sigpause32_common(compat_old_sigset_t set, struct pt_regs *regs) -{ - sigset_t saveset; - - set &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, set); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->tpc = regs->tnpc; - regs->tnpc += 4; - if (test_thread_flag(TIF_32BIT)) { - regs->tpc &= 0xffffffff; - regs->tnpc &= 0xffffffff; - } - - /* Condition codes and return value where set here for sigpause, - * and so got used by setup_frame, which again causes sigreturn() - * to return -EINTR. - */ - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - /* - * Return -EINTR and set condition code here, - * so the interrupted system call actually returns - * these. - */ - regs->tstate |= TSTATE_ICARRY; - regs->u_regs[UREG_I0] = EINTR; - if (do_signal32(&saveset, regs, 0, 0)) - return; - } -} - -asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *regs) -{ - sigset_t oldset, set; - compat_sigset_t set32; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (((compat_size_t)sigsetsize) != sizeof(sigset_t)) { - regs->tstate |= TSTATE_ICARRY; - regs->u_regs[UREG_I0] = EINVAL; - return; - } - if (copy_from_user(&set32, (void __user *)(long)uset, sizeof(set32))) { - regs->tstate |= TSTATE_ICARRY; - regs->u_regs[UREG_I0] = EFAULT; - return; - } - switch (_NSIG_WORDS) { - case 4: set.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32); - case 3: set.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32); - case 2: set.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32); - case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32); - } - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - oldset = current->blocked; - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->tpc = regs->tnpc; - regs->tnpc += 4; - if (test_thread_flag(TIF_32BIT)) { - regs->tpc &= 0xffffffff; - regs->tnpc &= 0xffffffff; - } - - /* Condition codes and return value where set here for sigpause, - * and so got used by setup_frame, which again causes sigreturn() - * to return -EINTR. - */ - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - /* - * Return -EINTR and set condition code here, - * so the interrupted system call actually returns - * these. - */ - regs->tstate |= TSTATE_ICARRY; - regs->u_regs[UREG_I0] = EINTR; - if (do_signal32(&oldset, regs, 0, 0)) - return; - } -} - static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) { unsigned long *fpregs = current_thread_info()->fpregs; @@ -351,7 +257,7 @@ void do_new_sigreturn32(struct pt_regs *regs) sf = (struct new_signal_frame32 __user *) regs->u_regs[UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ - if (verify_area(VERIFY_READ, sf, sizeof(*sf)) || + if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || (((unsigned long) sf) & 3)) goto segv; @@ -436,7 +342,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) scptr = (struct sigcontext32 __user *) (regs->u_regs[UREG_I0] & 0x00000000ffffffffUL); /* Check sanity of the user arg. */ - if (verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || + if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || (((unsigned long) scptr) & 3)) goto segv; @@ -504,7 +410,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ - if (verify_area(VERIFY_READ, sf, sizeof(*sf)) || + if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || (((unsigned long) sf) & 3)) goto segv; @@ -720,9 +626,9 @@ setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *o sig_address = NULL; } } - err |= __put_user((long)sig_address, &sframep->sig_address); + err |= __put_user(ptr_to_compat(sig_address), &sframep->sig_address); err |= __put_user(sig_code, &sframep->sig_code); - err |= __put_user((u64)sc, &sframep->sig_scptr); + err |= __put_user(ptr_to_compat(sc), &sframep->sig_scptr); if (err) goto sigsegv; @@ -857,8 +763,10 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); - pmd_t *pmdp = pmd_offset(pgdp, address); + pud_t *pudp = pud_offset(pgdp, address); + pmd_t *pmdp = pmd_offset(pudp, address); pte_t *ptep; + pte_t pte; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -869,15 +777,17 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, preempt_disable(); ptep = pte_offset_map(pmdp, address); - if (pte_present(*ptep)) { + pte = *ptep; + if (pte_present(pte)) { unsigned long page = (unsigned long) - page_address(pte_page(*ptep)); - - __asm__ __volatile__( - " membar #StoreStore\n" - " flush %0 + %1" - : : "r" (page), "r" (address & (PAGE_SIZE - 1)) - : "memory"); + page_address(pte_page(pte)); + + wmb(); + __asm__ __volatile__("flush %0 + %1" + : /* no outputs */ + : "r" (page), + "r" (address & (PAGE_SIZE - 1)) + : "memory"); } pte_unmap(ptep); preempt_enable(); @@ -967,7 +877,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, /* Save the currently window file: */ /* 1. Link sfp->uc->gwins to our windows */ - err |= __put_user((u32)(long)gw, &mc->gwin); + err |= __put_user(ptr_to_compat(gw), &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ err |= __put_user(get_thread_wsaved(), &gw->count); @@ -1101,7 +1011,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs) goto sigsegv; } - if (!__access_ok((unsigned long)c, sizeof(*c))) { + if (!__access_ok(c, sizeof(*c))) { /* Miguel, add nice debugging msg _here_. ;-) */ goto sigsegv; } @@ -1268,7 +1178,8 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); - pmd_t *pmdp = pmd_offset(pgdp, address); + pud_t *pudp = pud_offset(pgdp, address); + pmd_t *pmdp = pmd_offset(pudp, address); pte_t *ptep; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -1287,11 +1198,12 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, unsigned long page = (unsigned long) page_address(pte_page(*ptep)); - __asm__ __volatile__( - " membar #StoreStore\n" - " flush %0 + %1" - : : "r" (page), "r" (address & (PAGE_SIZE - 1)) - : "memory"); + wmb(); + __asm__ __volatile__("flush %0 + %1" + : /* no outputs */ + : "r" (page), + "r" (address & (PAGE_SIZE - 1)) + : "memory"); } pte_unmap(ptep); preempt_enable(); @@ -1320,13 +1232,13 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, else setup_frame32(&ka->sa, regs, signr, oldset, info); } - if (!(ka->sa.sa_flags & SA_NOMASK)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NOMASK)) sigaddset(¤t->blocked,signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + tracehook_report_handle_signal(signr, ka, oldset, regs); } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -1354,8 +1266,8 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal32(sigset_t *oldset, struct pt_regs * regs, - unsigned long orig_i0, int restart_syscall) +void do_signal32(sigset_t *oldset, struct pt_regs * regs, + unsigned long orig_i0, int restart_syscall) { siginfo_t info; struct signal_deliver_cookie cookie; @@ -1372,7 +1284,15 @@ int do_signal32(sigset_t *oldset, struct pt_regs * regs, syscall_restart32(orig_i0, regs, &ka.sa); handle_signal32(signr, &ka, &info, oldset, regs, svr4_signal); - return 1; + + /* 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. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + return; } if (cookie.restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || @@ -1389,7 +1309,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs * regs, regs->tpc -= 4; regs->tnpc -= 4; } - return 0; + + /* 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); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } struct sigstack32 { @@ -1446,10 +1373,12 @@ asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp) u32 u_ss_sp = 0; int ret; mm_segment_t old_fs; + stack_t32 __user *uss32 = compat_ptr(ussa); + stack_t32 __user *uoss32 = compat_ptr(uossa); - if (ussa && (get_user(u_ss_sp, &((stack_t32 __user *)(long)ussa)->ss_sp) || - __get_user(uss.ss_flags, &((stack_t32 __user *)(long)ussa)->ss_flags) || - __get_user(uss.ss_size, &((stack_t32 __user *)(long)ussa)->ss_size))) + if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) || + __get_user(uss.ss_flags, &uss32->ss_flags) || + __get_user(uss.ss_size, &uss32->ss_size))) return -EFAULT; uss.ss_sp = compat_ptr(u_ss_sp); old_fs = get_fs(); @@ -1457,9 +1386,9 @@ asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp) ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL, uossa ? (stack_t __user *) &uoss : NULL, sp); set_fs(old_fs); - if (!ret && uossa && (put_user((long)uoss.ss_sp, &((stack_t32 __user *)(long)uossa)->ss_sp) || - __put_user(uoss.ss_flags, &((stack_t32 __user *)(long)uossa)->ss_flags) || - __put_user(uoss.ss_size, &((stack_t32 __user *)(long)uossa)->ss_size))) + if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) || + __put_user(uoss.ss_flags, &uoss32->ss_flags) || + __put_user(uoss.ss_size, &uoss32->ss_size))) return -EFAULT; return ret; }