X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fkernel%2Fsignal32.c;h=c86a5ddff050a78661eced6ca74a68b5358b5187;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=407beff81d52fe39b4ca0ed22f82969c138b75f3;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 407beff81..c86a5ddff 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -4,9 +4,10 @@ * for more details. * * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1994 - 2000 Ralf Baechle + * Copyright (C) 1994 - 2000, 2006 Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#include #include #include #include @@ -19,15 +20,80 @@ #include #include #include +#include +#include #include -#include +#include #include #include #include #include #include #include +#include + +#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct compat_siginfo { + int si_signo; + int si_code; + int si_errno; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + compat_uid_t _uid; /* sender's uid */ + } _kill; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + compat_uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* IRIX SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + compat_clock_t _utime; + int _status; /* exit code */ + compat_clock_t _stime; + } _irix_sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + s32 _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL, SIGXFSZ (To do ...) */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval;/* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + compat_uid_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + } _sifields; +} compat_siginfo_t; /* * Including would give use the 64-bit syscall numbers ... @@ -40,8 +106,6 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs); - /* 32-bit compatibility types */ #define _NSIG_BPW32 32 @@ -78,7 +142,7 @@ struct ucontext32 { extern void __put_sigset_unknown_nsig(void); extern void __get_sigset_unknown_nsig(void); -static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t *ubuf) +static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) { int err = 0; @@ -99,7 +163,7 @@ static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t *ubuf) return err; } -static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf) +static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) { int err = 0; unsigned long sig[4]; @@ -126,68 +190,63 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf) /* * Atomically swap in the new signal mask, and wait for a signal. */ + save_static_function(sys32_sigsuspend); -static_unused int _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) +__attribute_used__ noinline static int +_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) { - compat_sigset_t *uset; - sigset_t newset, saveset; + compat_sigset_t __user *uset; + sigset_t newset; - uset = (compat_sigset_t *) regs.regs[4]; + uset = (compat_sigset_t __user *) regs.regs[4]; if (get_sigset(&newset, uset)) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; + current->saved_sigmask = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs.regs[2] = EINTR; - regs.regs[7] = 1; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, ®s)) - return -EINTR; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } save_static_function(sys32_rt_sigsuspend); -static_unused int _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +__attribute_used__ noinline static int +_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { - compat_sigset_t *uset; - sigset_t newset, saveset; - size_t sigsetsize; + compat_sigset_t __user *uset; + sigset_t newset; + size_t sigsetsize; /* XXX Don't preclude handling different sized sigset_t's. */ sigsetsize = regs.regs[5]; if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - uset = (compat_sigset_t *) regs.regs[4]; + uset = (compat_sigset_t __user *) regs.regs[4]; if (get_sigset(&newset, uset)) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; + current->saved_sigmask = current->blocked; current->blocked = newset; - recalc_sigpending(); + recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs.regs[2] = EINTR; - regs.regs[7] = 1; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, ®s)) - return -EINTR; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } -asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, - struct sigaction32 *oact) +asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act, + struct sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -195,11 +254,12 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, if (act) { old_sigset_t mask; + s32 handler; if (!access_ok(VERIFY_READ, act, sizeof(*act))) return -EFAULT; - err |= __get_user((u32)(u64)new_ka.sa.sa_handler, - &act->sa_handler); + err |= __get_user(handler, &act->sa_handler); + new_ka.sa.sa_handler = (void __user *)(s64)handler; err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); err |= __get_user(mask, &act->sa_mask.sig[0]); if (err) @@ -212,15 +272,15 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) - return -EFAULT; + return -EFAULT; err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); err |= __put_user((u32)(u64)old_ka.sa.sa_handler, &oact->sa_handler); err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); - err |= __put_user(0, &oact->sa_mask.sig[1]); - err |= __put_user(0, &oact->sa_mask.sig[2]); - err |= __put_user(0, &oact->sa_mask.sig[3]); - if (err) + err |= __put_user(0, &oact->sa_mask.sig[1]); + err |= __put_user(0, &oact->sa_mask.sig[2]); + err |= __put_user(0, &oact->sa_mask.sig[3]); + if (err) return -EFAULT; } @@ -229,8 +289,8 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) { - const stack32_t *uss = (const stack32_t *) regs.regs[4]; - stack32_t *uoss = (stack32_t *) regs.regs[5]; + const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4]; + stack32_t __user *uoss = (stack32_t __user *) regs.regs[5]; unsigned long usp = regs.regs[29]; stack_t kss, koss; int ret, err = 0; @@ -241,7 +301,7 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) return -EFAULT; err |= __get_user(sp, &uss->ss_sp); - kss.ss_sp = (void *) (long) sp; + kss.ss_sp = (void __user *) (long) sp; err |= __get_user(kss.ss_size, &uss->ss_size); err |= __get_user(kss.ss_flags, &uss->ss_flags); if (err) @@ -249,13 +309,14 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) } set_fs (KERNEL_DS); - ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, usp); + ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL, + uoss ? (stack_t __user *)&koss : NULL, usp); set_fs (old_fs); if (!ret && uoss) { if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) return -EFAULT; - sp = (int) (long) koss.ss_sp; + sp = (int) (unsigned long) koss.ss_sp; err |= __put_user(sp, &uoss->ss_sp); err |= __put_user(koss.ss_size, &uoss->ss_size); err |= __put_user(koss.ss_flags, &uoss->ss_flags); @@ -265,10 +326,11 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) return ret; } -static asmlinkage int restore_sigcontext32(struct pt_regs *regs, - struct sigcontext32 *sc) +static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { + u32 used_math; int err = 0; + s32 treg; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -276,6 +338,15 @@ static asmlinkage int restore_sigcontext32(struct pt_regs *regs, err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(regs->hi, &sc->sc_mdhi); err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } #define restore_gp_reg(i) do { \ err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ @@ -293,9 +364,12 @@ static asmlinkage int restore_sigcontext32(struct pt_regs *regs, restore_gp_reg(31); #undef restore_gp_reg - err |= __get_user(current->used_math, &sc->sc_used_math); + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); - if (current->used_math) { + preempt_disable(); + + if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); err |= restore_fp_context32(sc); @@ -304,28 +378,44 @@ static asmlinkage int restore_sigcontext32(struct pt_regs *regs, lose_fpu(); } + preempt_enable(); + return err; } struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_pad[2]; +#else u32 sf_code[2]; /* signal trampoline */ +#endif struct sigcontext32 sf_sc; sigset_t sf_mask; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +#endif }; struct rt_sigframe32 { u32 rs_ass[4]; /* argument save space for o32 */ +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_pad[2]; +#else u32 rs_code[2]; /* signal trampoline */ - struct siginfo32 rs_info; +#endif + compat_siginfo_t rs_info; struct ucontext32 rs_uc; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ +#endif }; -static int copy_siginfo_to_user32(siginfo_t32 *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(siginfo_t32))) + if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -342,6 +432,11 @@ static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user(from->si_int, &to->si_int); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); @@ -351,7 +446,7 @@ static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - 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); @@ -368,12 +463,14 @@ static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) return err; } -asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sys32_sigreturn); +__attribute_used__ noinline static void +_sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { - struct sigframe *frame; + struct sigframe __user *frame; sigset_t blocked; - frame = (struct sigframe *) regs.regs[29]; + frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) @@ -391,8 +488,6 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) /* * Don't let your children do this ... */ - if (current_thread_info()->flags & TIF_SYSCALL_TRACE) - do_syscall_trace(®s, 1); __asm__ __volatile__( "move\t$29, %0\n\t" "j\tsyscall_exit" @@ -404,14 +499,17 @@ badframe: force_sig(SIGSEGV, current); } -asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sys32_rt_sigreturn); +__attribute_used__ noinline static void +_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { - struct rt_sigframe32 *frame; + struct rt_sigframe32 __user *frame; + mm_segment_t old_fs; sigset_t set; stack_t st; s32 sp; - frame = (struct rt_sigframe32 *) regs.regs[29]; + frame = (struct rt_sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) @@ -429,7 +527,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* The ucontext contains a stack32_t, so we must convert! */ if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) goto badframe; - st.ss_size = (long) sp; + st.ss_sp = (void __user *)(long) sp; if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) goto badframe; if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) @@ -437,7 +535,10 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs.regs[29]); + old_fs = get_fs(); + set_fs (KERNEL_DS); + do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); + set_fs (old_fs); /* * Don't let your children do this ... @@ -454,7 +555,7 @@ badframe: } static inline int setup_sigcontext32(struct pt_regs *regs, - struct sigcontext32 *sc) + struct sigcontext32 __user *sc) { int err = 0; @@ -477,24 +578,35 @@ static inline int setup_sigcontext32(struct pt_regs *regs, err |= __put_user(regs->hi, &sc->sc_mdhi); err |= __put_user(regs->lo, &sc->sc_mdlo); - err |= __put_user(regs->cp0_cause, &sc->sc_cause); - err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + if (cpu_has_dsp) { + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + } - err |= __put_user(current->used_math, &sc->sc_used_math); + err |= __put_user(!!used_math(), &sc->sc_used_math); - if (!current->used_math) + if (!used_math()) goto out; - /* + /* * Save FPU state to signal context. Signal handler will "inherit" * current FPU state. */ + preempt_disable(); + if (!is_fpu_owner()) { own_fpu(); restore_fp(current); } err |= save_fp_context32(sc); + preempt_enable(); + out: return err; } @@ -502,8 +614,9 @@ out: /* * Determine which stack to use.. */ -static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, - size_t frame_size) +static inline void __user *get_sigframe(struct k_sigaction *ka, + struct pt_regs *regs, + size_t frame_size) { unsigned long sp; @@ -511,23 +624,23 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, sp = regs->regs[29]; /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; /* This is the X/Open sanctioned signal stack switching. */ if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) sp = current->sas_ss_sp + current->sas_ss_size; - return (void *)((sp - frame_size) & ALMASK); + return (void __user *)((sp - frame_size) & ALMASK); } -static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, - int signr, sigset_t *set) +int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set) { - struct sigframe *frame; + struct sigframe __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -571,19 +684,17 @@ static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, current->comm, current->pid, frame, regs->cp0_epc, frame->sf_code); #endif - return; + return 0; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); + return -EFAULT; } -static inline void setup_rt_frame(struct k_sigaction * ka, - struct pt_regs *regs, int signr, - sigset_t *set, siginfo_t *info) +int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info) { - struct rt_sigframe32 *frame; + struct rt_sigframe32 __user *frame; int err = 0; s32 sp; @@ -603,7 +714,7 @@ static inline void setup_rt_frame(struct k_sigaction * ka, err |= __put_user(0x0000000c , frame->rs_code + 1); flush_cache_sigtramp((unsigned long) frame->rs_code); - /* Convert (siginfo_t -> siginfo_t32) and copy to user. */ + /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ err |= copy_siginfo_to_user32(&frame->rs_info, info); /* Create the ucontext. */ @@ -644,18 +755,17 @@ static inline void setup_rt_frame(struct k_sigaction * ka, current->comm, current->pid, frame, regs->cp0_epc, frame->rs_code); #endif - return; + return 0; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); + return -EFAULT; } -static inline void handle_signal(unsigned long sig, siginfo_t *info, - sigset_t *oldset, struct pt_regs * regs) +static inline int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; + int ret; switch (regs->regs[0]) { case ERESTART_RESTARTBLOCK: @@ -663,7 +773,7 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[2] = EINTR; break; case ERESTARTSYS: - if(!(ka->sa.sa_flags & SA_RESTART)) { + if (!(ka->sa.sa_flags & SA_RESTART)) { regs->regs[2] = EINTR; break; } @@ -676,23 +786,24 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(ka, regs, sig, oldset, info); + ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); else - setup_frame(ka, regs, sig, oldset); + ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - 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_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + return ret; } -asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs) +void do_signal32(struct pt_regs *regs) { + struct k_sigaction ka; + sigset_t *oldset; siginfo_t info; int signr; @@ -702,23 +813,30 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs) * if so. */ if (!user_mode(regs)) - return 1; + return; - if (current->flags & PF_FREEZE) { - refrigerator(0); - goto no_signal; - } - - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &info, oldset, regs); - return 1; + /* Whee! Actually deliver the signal. */ + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * 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; } -no_signal: /* * Who's code doesn't conform to the restartable syscall convention * dies here!!! The li instruction, a single machine instruction, @@ -736,12 +854,21 @@ no_signal: regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; } + regs->regs[0] = 0; /* Don't deal with this again. */ + } + + /* + * 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); } - return 0; } -asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, - struct sigaction32 *oact, +asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, + struct sigaction32 __user *oact, unsigned int sigsetsize) { struct k_sigaction new_sa, old_sa; @@ -752,12 +879,13 @@ asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, goto out; if (act) { + s32 handler; int err = 0; if (!access_ok(VERIFY_READ, act, sizeof(*act))) return -EFAULT; - err |= __get_user((u32)(u64)new_sa.sa.sa_handler, - &act->sa_handler); + err |= __get_user(handler, &act->sa_handler); + new_sa.sa.sa_handler = (void __user *)(s64)handler; err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); if (err) @@ -783,8 +911,8 @@ out: return ret; } -asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, - compat_sigset_t *oset, unsigned int sigsetsize) +asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, + compat_sigset_t __user *oset, unsigned int sigsetsize) { sigset_t old_set, new_set; int ret; @@ -794,8 +922,9 @@ asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, return -EFAULT; set_fs (KERNEL_DS); - ret = sys_rt_sigprocmask(how, set ? &new_set : NULL, - oset ? &old_set : NULL, sigsetsize); + ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL, + oset ? (sigset_t __user *)&old_set : NULL, + sigsetsize); set_fs (old_fs); if (!ret && oset && put_sigset(&old_set, oset)) @@ -804,7 +933,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, return ret; } -asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset, +asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize) { int ret; @@ -812,7 +941,7 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset, mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_rt_sigpending(&set, sigsetsize); + ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize); set_fs (old_fs); if (!ret && put_sigset(&set, uset)) @@ -821,108 +950,44 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset, return ret; } -asmlinkage int sys32_rt_sigtimedwait(compat_sigset_t *uthese, - siginfo_t32 *uinfo, struct compat_timespec *uts, - compat_time_t sigsetsize) +asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) { - int ret, sig; - sigset_t these; - compat_sigset_t these32; - struct timespec ts; siginfo_t info; - long timeout = 0; + int ret; + mm_segment_t old_fs = get_fs(); - /* - * As the result of a brainfarting competition a few years ago the - * size of sigset_t for the 32-bit kernel was choosen to be 128 bits - * but nothing so far is actually using that many, 64 are enough. So - * for now we just drop the high bits. - */ - if (copy_from_user (&these32, uthese, sizeof(compat_old_sigset_t))) + if (copy_from_user (&info, uinfo, 3*sizeof(int)) || + copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) return -EFAULT; - - switch (_NSIG_WORDS) { -#ifdef __MIPSEB__ - case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); - case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); - case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); - case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); -#endif -#ifdef __MIPSEL__ - case 4: these.sig[3] = these32.sig[7] | (((long)these32.sig[6]) << 32); - case 3: these.sig[2] = these32.sig[5] | (((long)these32.sig[4]) << 32); - case 2: these.sig[1] = these32.sig[3] | (((long)these32.sig[2]) << 32); - case 1: these.sig[0] = these32.sig[1] | (((long)these32.sig[0]) << 32); -#endif - } - - /* - * Invert the set of allowed signals to get those we - * want to block. - */ - sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&these); - - if (uts) { - if (get_user (ts.tv_sec, &uts->tv_sec) || - get_user (ts.tv_nsec, &uts->tv_nsec)) - return -EINVAL; - if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 - || ts.tv_sec < 0) - return -EINVAL; - } - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - if (!sig) { - /* None ready -- temporarily unblock those we're interested - in so that we'll be awakened when they arrive. */ - sigset_t oldblocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); - - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = oldblocked; - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); - - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = -EAGAIN; - if (timeout) - ret = -EINTR; - } - + set_fs (KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info); + set_fs (old_fs); return ret; } -asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) +asmlinkage long +sys32_waitid(int which, compat_pid_t pid, + compat_siginfo_t __user *uinfo, int options, + struct compat_rusage __user *uru) { siginfo_t info; - int ret; + struct rusage ru; + long ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info, uinfo, 3*sizeof(int)) || - copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) - return -EFAULT; + info.si_signo = 0; set_fs (KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, &info); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? (struct rusage __user *) &ru : NULL); set_fs (old_fs); - return ret; + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); }